Skip to content

Commit 5fbb094

Browse files
committed
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
1 parent fe13b86 commit 5fbb094

File tree

2 files changed

+174
-3
lines changed

2 files changed

+174
-3
lines changed

src/libcore/rt/io/mod.rs

+21-3
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ pub mod mem;
152152
/// Non-blocking access to stdin, stdout, stderr
153153
pub mod stdio;
154154

155+
/// Implementations for Option
156+
mod option;
157+
155158
/// Basic stream compression. XXX: Belongs with other flate code
156159
#[cfg(not(stage0))] // XXX Using unsnapshotted features
157160
pub mod flate;
@@ -194,12 +197,14 @@ pub struct IoError {
194197
detail: Option<~str>
195198
}
196199

200+
#[deriving(Eq)]
197201
pub enum IoErrorKind {
198202
FileNotFound,
199203
FilePermission,
200204
ConnectionFailed,
201205
Closed,
202-
OtherIoError
206+
OtherIoError,
207+
PreviousIoError
203208
}
204209

205210
// XXX: Can't put doc comments on macros
@@ -232,9 +237,9 @@ pub trait Reader {
232237
/// println(reader.read_line());
233238
/// }
234239
///
235-
/// # XXX
240+
/// # Failue
236241
///
237-
/// What does this return if the Reader is in an error state?
242+
/// Returns `true` on failure.
238243
fn eof(&mut self) -> bool;
239244
}
240245

@@ -323,3 +328,16 @@ pub trait Decorator<T> {
323328
/// Take a mutable reference to the decorated value
324329
fn inner_mut_ref<'a>(&'a mut self) -> &'a mut T;
325330
}
331+
332+
pub fn standard_error(kind: IoErrorKind) -> IoError {
333+
match kind {
334+
PreviousIoError => {
335+
IoError {
336+
kind: PreviousIoError,
337+
desc: "Failing due to a previous I/O error",
338+
detail: None
339+
}
340+
}
341+
_ => fail!()
342+
}
343+
}

src/libcore/rt/io/option.rs

+153
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! Implementations of I/O traits for the Option type
12+
//!
13+
//! I/O constructors return option types to allow errors to be handled.
14+
//! These implementations allow e.g. `Option<FileStream>` to be used
15+
//! as a `Reader` without unwrapping the option first.
16+
//!
17+
//! # XXX Seek and Close
18+
19+
use option::*;
20+
use super::{Reader, Writer, Listener};
21+
use super::{standard_error, PreviousIoError, io_error, IoError};
22+
23+
fn prev_io_error() -> IoError {
24+
standard_error(PreviousIoError)
25+
}
26+
27+
impl<W: Writer> Writer for Option<W> {
28+
fn write(&mut self, buf: &[u8]) {
29+
match *self {
30+
Some(ref mut writer) => writer.write(buf),
31+
None => io_error::cond.raise(prev_io_error())
32+
}
33+
}
34+
35+
fn flush(&mut self) {
36+
match *self {
37+
Some(ref mut writer) => writer.flush(),
38+
None => io_error::cond.raise(prev_io_error())
39+
}
40+
}
41+
}
42+
43+
impl<R: Reader> Reader for Option<R> {
44+
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
45+
match *self {
46+
Some(ref mut reader) => reader.read(buf),
47+
None => {
48+
io_error::cond.raise(prev_io_error());
49+
None
50+
}
51+
}
52+
}
53+
54+
fn eof(&mut self) -> bool {
55+
match *self {
56+
Some(ref mut reader) => reader.eof(),
57+
None => {
58+
io_error::cond.raise(prev_io_error());
59+
true
60+
}
61+
}
62+
}
63+
}
64+
65+
impl<L: Listener<S>, S> Listener<S> for Option<L> {
66+
fn accept(&mut self) -> Option<S> {
67+
match *self {
68+
Some(ref mut listener) => listener.accept(),
69+
None => {
70+
io_error::cond.raise(prev_io_error());
71+
None
72+
}
73+
}
74+
}
75+
}
76+
77+
#[cfg(test)]
78+
mod test {
79+
use option::*;
80+
use super::super::mem::*;
81+
use rt::test::*;
82+
use super::super::{PreviousIoError, io_error};
83+
84+
#[test]
85+
fn test_option_writer() {
86+
do run_in_newsched_task {
87+
let mut writer: Option<MemWriter> = Some(MemWriter::new());
88+
writer.write([0, 1, 2]);
89+
writer.flush();
90+
assert!(writer.unwrap().inner() == ~[0, 1, 2]);
91+
}
92+
}
93+
94+
#[test]
95+
fn test_option_writer_error() {
96+
do run_in_newsched_task {
97+
let mut writer: Option<MemWriter> = None;
98+
99+
let mut called = false;
100+
do io_error::cond.trap(|err| {
101+
assert!(err.kind == PreviousIoError);
102+
called = true;
103+
}).in {
104+
writer.write([0, 0, 0]);
105+
}
106+
assert!(called);
107+
108+
let mut called = false;
109+
do io_error::cond.trap(|err| {
110+
assert!(err.kind == PreviousIoError);
111+
called = true;
112+
}).in {
113+
writer.flush();
114+
}
115+
assert!(called);
116+
}
117+
}
118+
119+
#[test]
120+
fn test_option_reader() {
121+
do run_in_newsched_task {
122+
let mut reader: Option<MemReader> = Some(MemReader::new(~[0, 1, 2, 3]));
123+
let mut buf = [0, 0];
124+
reader.read(buf);
125+
assert!(buf == [0, 1]);
126+
assert!(!reader.eof());
127+
}
128+
}
129+
130+
#[test]
131+
fn test_option_reader_error() {
132+
let mut reader: Option<MemReader> = None;
133+
let mut buf = [];
134+
135+
let mut called = false;
136+
do io_error::cond.trap(|err| {
137+
assert!(err.kind == PreviousIoError);
138+
called = true;
139+
}).in {
140+
reader.read(buf);
141+
}
142+
assert!(called);
143+
144+
let mut called = false;
145+
do io_error::cond.trap(|err| {
146+
assert!(err.kind == PreviousIoError);
147+
called = true;
148+
}).in {
149+
assert!(reader.eof());
150+
}
151+
assert!(called);
152+
}
153+
}

0 commit comments

Comments
 (0)