Skip to content

Commit d45dc8d

Browse files
committed
core::rt: More work on Reader extensions and error handling
1 parent 28a13ec commit d45dc8d

File tree

2 files changed

+127
-65
lines changed

2 files changed

+127
-65
lines changed

src/libcore/rt/io/extensions.rs

Lines changed: 121 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
// XXX: Iteration should probably be considered separately
1515

1616
use vec;
17-
use rt::io::{Reader, read_error, standard_error, EndOfFile};
17+
use rt::io::{Reader, read_error, standard_error, EndOfFile, DEFAULT_BUF_SIZE};
1818
use option::{Option, Some, None};
1919
use unstable::finally::Finally;
2020
use util;
@@ -37,18 +37,17 @@ pub trait ReaderUtil {
3737
/// # Failure
3838
///
3939
/// Raises the same conditions as `read`. Additionally raises `read_error`
40-
/// on EOF. If `read_error` is handled then `push_bytes` returns without
41-
/// pushing any bytes onto `buf` - that is, `buf` has the same length
42-
/// upon exit as it did on entry.
40+
/// on EOF. If `read_error` is handled then `push_bytes` may push less
41+
/// than the requested number of bytes.
4342
fn push_bytes(&mut self, buf: &mut ~[u8], len: uint);
4443

4544
/// Reads `len` bytes and gives you back a new vector of length `len`
4645
///
4746
/// # Failure
4847
///
4948
/// Raises the same conditions as `read`. Additionally raises `read_error`
50-
/// on EOF. If `read_error` is handled then the returned vector has
51-
/// length 0.
49+
/// on EOF. If `read_error` is handled then the returned vector may
50+
/// contain less than the requested number of bytes.
5251
fn read_bytes(&mut self, len: uint) -> ~[u8];
5352

5453
/// Reads all remaining bytes from the stream.
@@ -60,60 +59,6 @@ pub trait ReaderUtil {
6059

6160
}
6261

63-
impl<T: Reader> ReaderUtil for T {
64-
fn read_byte(&mut self) -> Option<u8> {
65-
let mut buf = [0];
66-
match self.read(buf) {
67-
Some(0) => {
68-
debug!("read 0 bytes. trying again");
69-
self.read_byte()
70-
}
71-
Some(1) => Some(buf[0]),
72-
Some(_) => util::unreachable(),
73-
None => None
74-
}
75-
}
76-
77-
fn push_bytes(&mut self, buf: &mut ~[u8], len: uint) {
78-
unsafe {
79-
let start_len = buf.len();
80-
let mut total_read = 0;
81-
82-
vec::reserve_at_least(buf, start_len + len);
83-
vec::raw::set_len(buf, start_len + len);
84-
85-
do (|| {
86-
while total_read < len {
87-
let slice = vec::mut_slice(*buf, start_len + total_read, buf.len());
88-
match self.read(slice) {
89-
Some(nread) => {
90-
total_read += nread;
91-
}
92-
None => {
93-
read_error::cond.raise(standard_error(EndOfFile));
94-
// Reset the vector length as though we didn't read anything
95-
total_read = 0;
96-
break;
97-
}
98-
}
99-
}
100-
}).finally {
101-
vec::raw::set_len(buf, start_len + total_read);
102-
}
103-
}
104-
}
105-
106-
fn read_bytes(&mut self, len: uint) -> ~[u8] {
107-
let mut buf = vec::with_capacity(len);
108-
self.push_bytes(&mut buf, len);
109-
return buf;
110-
}
111-
112-
fn read_to_end(&mut self) -> ~[u8] {
113-
fail!()
114-
}
115-
}
116-
11762
pub trait ReaderByteConversions {
11863
/// Reads `n` little-endian unsigned integer bytes.
11964
///
@@ -323,6 +268,71 @@ pub trait WriterByteConversions {
323268
fn write_i8(&mut self, n: i8);
324269
}
325270

271+
impl<T: Reader> ReaderUtil for T {
272+
fn read_byte(&mut self) -> Option<u8> {
273+
let mut buf = [0];
274+
match self.read(buf) {
275+
Some(0) => {
276+
debug!("read 0 bytes. trying again");
277+
self.read_byte()
278+
}
279+
Some(1) => Some(buf[0]),
280+
Some(_) => util::unreachable(),
281+
None => None
282+
}
283+
}
284+
285+
fn push_bytes(&mut self, buf: &mut ~[u8], len: uint) {
286+
unsafe {
287+
let start_len = buf.len();
288+
let mut total_read = 0;
289+
290+
vec::reserve_at_least(buf, start_len + len);
291+
vec::raw::set_len(buf, start_len + len);
292+
293+
do (|| {
294+
while total_read < len {
295+
let slice = vec::mut_slice(*buf, start_len + total_read, buf.len());
296+
match self.read(slice) {
297+
Some(nread) => {
298+
total_read += nread;
299+
}
300+
None => {
301+
read_error::cond.raise(standard_error(EndOfFile));
302+
break;
303+
}
304+
}
305+
}
306+
}).finally {
307+
vec::raw::set_len(buf, start_len + total_read);
308+
}
309+
}
310+
}
311+
312+
fn read_bytes(&mut self, len: uint) -> ~[u8] {
313+
let mut buf = vec::with_capacity(len);
314+
self.push_bytes(&mut buf, len);
315+
return buf;
316+
}
317+
318+
fn read_to_end(&mut self) -> ~[u8] {
319+
let mut buf = vec::with_capacity(DEFAULT_BUF_SIZE);
320+
let mut keep_reading = true;
321+
do read_error::cond.trap(|e| {
322+
if e.kind == EndOfFile {
323+
keep_reading = false;
324+
} else {
325+
read_error::cond.raise(e)
326+
}
327+
}).in {
328+
while keep_reading {
329+
self.push_bytes(&mut buf, DEFAULT_BUF_SIZE)
330+
}
331+
}
332+
return buf;
333+
}
334+
}
335+
326336
#[cfg(test)]
327337
mod test {
328338
use super::*;
@@ -414,7 +424,7 @@ mod test {
414424
let mut reader = MemReader::new(~[10, 11]);
415425
do read_error::cond.trap(|_| {
416426
}).in {
417-
assert!(reader.read_bytes(4) == ~[]);
427+
assert!(reader.read_bytes(4) == ~[10, 11]);
418428
}
419429
}
420430

@@ -456,7 +466,7 @@ mod test {
456466
do read_error::cond.trap(|_| {
457467
}).in {
458468
reader.push_bytes(&mut buf, 4);
459-
assert!(buf == ~[8, 9]);
469+
assert!(buf == ~[8, 9, 10, 11]);
460470
}
461471
}
462472

@@ -480,7 +490,7 @@ mod test {
480490
do read_error::cond.trap(|_| { } ).in {
481491
reader.push_bytes(&mut buf, 4);
482492
}
483-
assert!(buf == ~[8, 9]);
493+
assert!(buf == ~[8, 9, 10]);
484494
}
485495

486496
#[test]
@@ -514,4 +524,52 @@ mod test {
514524
}
515525
}
516526

527+
#[test]
528+
fn read_to_end() {
529+
let mut reader = MockReader::new();
530+
let count = Cell(0);
531+
reader.read = |buf| {
532+
do count.with_mut_ref |count| {
533+
if *count == 0 {
534+
*count = 1;
535+
buf[0] = 10;
536+
buf[1] = 11;
537+
Some(2)
538+
} else if *count == 1 {
539+
*count = 2;
540+
buf[0] = 12;
541+
buf[1] = 13;
542+
Some(2)
543+
} else {
544+
None
545+
}
546+
}
547+
};
548+
let buf = reader.read_to_end();
549+
assert!(buf == ~[10, 11, 12, 13]);
550+
}
551+
552+
#[test]
553+
#[should_fail]
554+
#[ignore(cfg(windows))]
555+
fn read_to_end_error() {
556+
let mut reader = MockReader::new();
557+
let count = Cell(0);
558+
reader.read = |buf| {
559+
do count.with_mut_ref |count| {
560+
if *count == 0 {
561+
*count = 1;
562+
buf[0] = 10;
563+
buf[1] = 11;
564+
Some(2)
565+
} else {
566+
read_error::cond.raise(placeholder_error());
567+
None
568+
}
569+
}
570+
};
571+
let buf = reader.read_to_end();
572+
assert!(buf == ~[10, 11]);
573+
}
574+
517575
}

src/libcore/rt/io/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ In particular code written to ignore errors and expect conditions to be unhandle
187187
will start passing around null or zero objects when wrapped in a condition handler.
188188
189189
* XXX: How should we use condition handlers that return values?
190-
190+
* XXX: Should EOF raise default conditions when EOF is not an error?
191191
192192
# Issues withi/o scheduler affinity, work stealing, task pinning
193193
@@ -323,6 +323,10 @@ pub mod native {
323323
/// Mock implementations for testing
324324
mod mock;
325325

326+
/// The default buffer size for various I/O operations
327+
/// XXX: Not pub
328+
pub static DEFAULT_BUF_SIZE: uint = 1024 * 64;
329+
326330
/// The type passed to I/O condition handlers to indicate error
327331
///
328332
/// # XXX
@@ -375,7 +379,7 @@ pub trait Reader {
375379
///
376380
/// # XXX
377381
///
378-
/// * Should raise error on eof
382+
/// * Should raise_default error on eof?
379383
/// * If the condition is handled it should still return the bytes read,
380384
/// in which case there's no need to return Option - but then you *have*
381385
/// to install a handler to detect eof.

0 commit comments

Comments
 (0)