about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2013-04-22 14:52:40 -0700
committerBrian Anderson <banderson@mozilla.com>2013-04-22 15:08:47 -0700
commit5fbb0949a53a6ac51c6d9b187ef4c464e52ae536 (patch)
tree412f3a63b3278e97bc57105e28bc13e0cf5c53a7
parentfe13b865192028645b50c17d2cb1a6d44481f338 (diff)
downloadrust-5fbb0949a53a6ac51c6d9b187ef4c464e52ae536.tar.gz
rust-5fbb0949a53a6ac51c6d9b187ef4c464e52ae536.zip
core::rt: Add implementations of Reader, Writer, and Listener for Option
These will make it easier to write I/O code without worrying about errors
-rw-r--r--src/libcore/rt/io/mod.rs24
-rw-r--r--src/libcore/rt/io/option.rs153
2 files changed, 174 insertions, 3 deletions
diff --git a/src/libcore/rt/io/mod.rs b/src/libcore/rt/io/mod.rs
index f1b248c6e1d..d9d6622277f 100644
--- a/src/libcore/rt/io/mod.rs
+++ b/src/libcore/rt/io/mod.rs
@@ -152,6 +152,9 @@ pub mod mem;
 /// Non-blocking access to stdin, stdout, stderr
 pub mod stdio;
 
+/// Implementations for Option
+mod option;
+
 /// Basic stream compression. XXX: Belongs with other flate code
 #[cfg(not(stage0))] // XXX Using unsnapshotted features
 pub mod flate;
@@ -194,12 +197,14 @@ pub struct IoError {
     detail: Option<~str>
 }
 
+#[deriving(Eq)]
 pub enum IoErrorKind {
     FileNotFound,
     FilePermission,
     ConnectionFailed,
     Closed,
-    OtherIoError
+    OtherIoError,
+    PreviousIoError
 }
 
 // XXX: Can't put doc comments on macros
@@ -232,9 +237,9 @@ pub trait Reader {
     ///         println(reader.read_line());
     ///     }
     ///
-    /// # XXX
+    /// # Failue
     ///
-    /// What does this return if the Reader is in an error state?
+    /// Returns `true` on failure.
     fn eof(&mut self) -> bool;
 }
 
@@ -323,3 +328,16 @@ pub trait Decorator<T> {
     /// Take a mutable reference to the decorated value
     fn inner_mut_ref<'a>(&'a mut self) -> &'a mut T;
 }
+
+pub fn standard_error(kind: IoErrorKind) -> IoError {
+    match kind {
+        PreviousIoError => {
+            IoError {
+                kind: PreviousIoError,
+                desc: "Failing due to a previous I/O error",
+                detail: None
+            }
+        }
+        _ => fail!()
+    }
+}
diff --git a/src/libcore/rt/io/option.rs b/src/libcore/rt/io/option.rs
new file mode 100644
index 00000000000..95f8711cb5b
--- /dev/null
+++ b/src/libcore/rt/io/option.rs
@@ -0,0 +1,153 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Implementations of I/O traits for the Option type
+//!
+//! I/O constructors return option types to allow errors to be handled.
+//! These implementations allow e.g. `Option<FileStream>` to be used
+//! as a `Reader` without unwrapping the option first.
+//!
+//! # XXX Seek and Close
+
+use option::*;
+use super::{Reader, Writer, Listener};
+use super::{standard_error, PreviousIoError, io_error, IoError};
+
+fn prev_io_error() -> IoError {
+    standard_error(PreviousIoError)
+}
+
+impl<W: Writer> Writer for Option<W> {
+    fn write(&mut self, buf: &[u8]) {
+        match *self {
+            Some(ref mut writer) => writer.write(buf),
+            None => io_error::cond.raise(prev_io_error())
+        }
+    }
+
+    fn flush(&mut self) {
+        match *self {
+            Some(ref mut writer) => writer.flush(),
+            None => io_error::cond.raise(prev_io_error())
+        }
+    }
+}
+
+impl<R: Reader> Reader for Option<R> {
+    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+        match *self {
+            Some(ref mut reader) => reader.read(buf),
+            None => {
+                io_error::cond.raise(prev_io_error());
+                None
+            }
+        }
+    }
+
+    fn eof(&mut self) -> bool {
+        match *self {
+            Some(ref mut reader) => reader.eof(),
+            None => {
+                io_error::cond.raise(prev_io_error());
+                true
+            }
+        }
+    }
+}
+
+impl<L: Listener<S>, S> Listener<S> for Option<L> {
+    fn accept(&mut self) -> Option<S> {
+        match *self {
+            Some(ref mut listener) => listener.accept(),
+            None => {
+                io_error::cond.raise(prev_io_error());
+                None
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use option::*;
+    use super::super::mem::*;
+    use rt::test::*;
+    use super::super::{PreviousIoError, io_error};
+
+    #[test]
+    fn test_option_writer() {
+        do run_in_newsched_task {
+            let mut writer: Option<MemWriter> = Some(MemWriter::new());
+            writer.write([0, 1, 2]);
+            writer.flush();
+            assert!(writer.unwrap().inner() == ~[0, 1, 2]);
+        }
+    }
+
+    #[test]
+    fn test_option_writer_error() {
+        do run_in_newsched_task {
+            let mut writer: Option<MemWriter> = None;
+
+            let mut called = false;
+            do io_error::cond.trap(|err| {
+                assert!(err.kind == PreviousIoError);
+                called = true;
+            }).in {
+                writer.write([0, 0, 0]);
+            }
+            assert!(called);
+
+            let mut called = false;
+            do io_error::cond.trap(|err| {
+                assert!(err.kind == PreviousIoError);
+                called = true;
+            }).in {
+                writer.flush();
+            }
+            assert!(called);
+        }
+    }
+
+    #[test]
+    fn test_option_reader() {
+        do run_in_newsched_task {
+            let mut reader: Option<MemReader> = Some(MemReader::new(~[0, 1, 2, 3]));
+            let mut buf = [0, 0];
+            reader.read(buf);
+            assert!(buf == [0, 1]);
+            assert!(!reader.eof());
+        }
+    }
+
+    #[test]
+    fn test_option_reader_error() {
+        let mut reader: Option<MemReader> = None;
+        let mut buf = [];
+
+        let mut called = false;
+        do io_error::cond.trap(|err| {
+            assert!(err.kind == PreviousIoError);
+            called = true;
+        }).in {
+            reader.read(buf);
+        }
+        assert!(called);
+
+        let mut called = false;
+        do io_error::cond.trap(|err| {
+            assert!(err.kind == PreviousIoError);
+            called = true;
+        }).in {
+            assert!(reader.eof());
+        }
+        assert!(called);
+    }
+}