Skip to content

Commit f0c9ce2

Browse files
author
Oliver Schneider
committed
read_until reworked so returned delimiter is explicit
read_line never returns '\n' character read_until returns enum signifying whether delimiter is returned or not
1 parent b7930d9 commit f0c9ce2

File tree

4 files changed

+50
-14
lines changed

4 files changed

+50
-14
lines changed

src/libstd/io/buffered.rs

+16-4
Original file line numberDiff line numberDiff line change
@@ -574,12 +574,24 @@ mod test {
574574

575575
#[test]
576576
fn test_read_until() {
577+
use io::ReadUntilHelper;
577578
let inner = MemReader::new(vec!(0, 1, 2, 1, 0));
578579
let mut reader = BufferedReader::with_capacity(2, inner);
579-
assert_eq!(reader.read_until(0), Ok(vec!(0)));
580-
assert_eq!(reader.read_until(2), Ok(vec!(1, 2)));
581-
assert_eq!(reader.read_until(1), Ok(vec!(1)));
582-
assert_eq!(reader.read_until(8), Ok(vec!(0)));
580+
assert_eq!(reader.read_until(0), Ok(ReadUntilHelper::WithDelimiter(vec!(0))));
581+
assert_eq!(reader.read_until(2), Ok(ReadUntilHelper::WithDelimiter(vec!(1, 2))));
582+
assert_eq!(reader.read_until(1), Ok(ReadUntilHelper::WithDelimiter(vec!(1))));
583+
assert_eq!(reader.read_until(8), Ok(ReadUntilHelper::WithoutDelimiter(vec!(0))));
584+
assert!(reader.read_until(9).is_err());
585+
}
586+
587+
#[test]
588+
fn test_read_until_without_delimiter() {
589+
let inner = MemReader::new(vec!(0, 1, 2, 1, 0));
590+
let mut reader = BufferedReader::with_capacity(2, inner);
591+
assert_eq!(reader.read_until(0).unwrap().without_delimiter(), vec![]);
592+
assert_eq!(reader.read_until(2).unwrap().without_delimiter(), vec![1]);
593+
assert_eq!(reader.read_until(1).unwrap().without_delimiter(), vec![]);
594+
assert_eq!(reader.read_until(8).unwrap().without_delimiter(), vec![0]);
583595
assert!(reader.read_until(9).is_err());
584596
}
585597

src/libstd/io/mod.rs

+32-8
Original file line numberDiff line numberDiff line change
@@ -1348,6 +1348,32 @@ impl<'r, T: Buffer> Iterator for Chars<'r, T> {
13481348
}
13491349
}
13501350

1351+
/// Makes the possibility of `read_until` returning a sequence with a delimiter explicit
1352+
/// Use `without_delimiter` if you always want the same type of result
1353+
pub enum ReadUntilHelper {
1354+
/// If you run `read_until` again after receiving `WithoutDelimiter`, you will get an EOF
1355+
/// Does not contain the delimiter.
1356+
WithoutDelimiter(Vec<u8>),
1357+
/// Always contains the delimiter. If the delimiter was just before the end of the Buffer,
1358+
/// the next call to `read_until` will also give you an EOF.
1359+
WithDelimiter(Vec<u8>),
1360+
}
1361+
1362+
impl ReadUntilHelper {
1363+
/// Destructures the ReadUntilHelper by either removing the delimiter (if present) or
1364+
/// directly returning the read block (if no delimiter was present)
1365+
pub fn without_delimiter(self) -> Vec<u8> {
1366+
match self {
1367+
ReadUntilHelper::WithoutDelimiter(x) => x,
1368+
ReadUntilHelper::WithDelimiter(mut x) => {
1369+
let len = x.len() - 1;
1370+
x.truncate(len);
1371+
x
1372+
},
1373+
}
1374+
}
1375+
}
1376+
13511377
/// A Buffer is a type of reader which has some form of internal buffering to
13521378
/// allow certain kinds of reading operations to be more optimized than others.
13531379
/// This type extends the `Reader` trait with a few methods that are not
@@ -1374,15 +1400,15 @@ pub trait Buffer: Reader {
13741400

13751401
/// Reads the next line of input, interpreted as a sequence of UTF-8
13761402
/// encoded Unicode codepoints. If a newline is encountered, then the
1377-
/// newline is contained in the returned string.
1403+
/// newline is NOT contained in the returned string.
13781404
///
13791405
/// # Example
13801406
///
13811407
/// ```rust
13821408
/// use std::io::BufReader;
13831409
///
13841410
/// let mut reader = BufReader::new(b"hello\nworld");
1385-
/// assert_eq!("hello\n", &*reader.read_line().unwrap());
1411+
/// assert_eq!("hello", &*reader.read_line().unwrap());
13861412
/// ```
13871413
///
13881414
/// # Error
@@ -1392,13 +1418,11 @@ pub trait Buffer: Reader {
13921418
/// * All non-EOF errors will be returned immediately
13931419
/// * If an error is returned previously consumed bytes are lost
13941420
/// * EOF is only returned if no bytes have been read
1395-
/// * Reach EOF may mean that the delimiter is not present in the return
1396-
/// value
13971421
///
13981422
/// Additionally, this function can fail if the line of input read is not a
13991423
/// valid UTF-8 sequence of bytes.
14001424
fn read_line(&mut self) -> IoResult<String> {
1401-
self.read_until(b'\n').and_then(|line|
1425+
self.read_until(b'\n').and_then(|ruh| Ok(ruh.without_delimiter())).and_then(|line|
14021426
match String::from_utf8(line) {
14031427
Ok(s) => Ok(s),
14041428
Err(_) => Err(standard_error(InvalidInput)),
@@ -1421,15 +1445,15 @@ pub trait Buffer: Reader {
14211445
/// have been read, otherwise the pending byte buffer is returned. This
14221446
/// is the reason that the byte buffer returned may not always contain the
14231447
/// delimiter.
1424-
fn read_until(&mut self, byte: u8) -> IoResult<Vec<u8>> {
1448+
fn read_until(&mut self, byte: u8) -> IoResult<ReadUntilHelper> {
14251449
let mut res = Vec::new();
14261450

14271451
loop {
14281452
let (done, used) = {
14291453
let available = match self.fill_buf() {
14301454
Ok(n) => n,
14311455
Err(ref e) if res.len() > 0 && e.kind == EndOfFile => {
1432-
return Ok(res);
1456+
return Ok(ReadUntilHelper::WithoutDelimiter(res));
14331457
}
14341458
Err(e) => return Err(e)
14351459
};
@@ -1446,7 +1470,7 @@ pub trait Buffer: Reader {
14461470
};
14471471
self.consume(used);
14481472
if done {
1449-
return Ok(res);
1473+
return Ok(ReadUntilHelper::WithDelimiter(res));
14501474
}
14511475
}
14521476
}

src/libstd/io/stdio.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ impl StdinReader {
166166
/// The read is performed atomically - concurrent read calls in other
167167
/// threads will not interleave with this one.
168168
pub fn read_until(&mut self, byte: u8) -> IoResult<Vec<u8>> {
169-
self.inner.lock().unwrap().0.read_until(byte)
169+
self.inner.lock().unwrap().0.read_until(byte).and_then(|x| Ok(x.without_delimiter()))
170170
}
171171

172172
/// Like `Buffer::read_char`.

src/test/run-pass/issue-13304.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ fn parent() {
3333
let out = p.wait_with_output().unwrap();
3434
assert!(out.status.success());
3535
let s = str::from_utf8(out.output.as_slice()).unwrap();
36-
assert_eq!(s, "test1\n\ntest2\n\ntest3\n");
36+
assert_eq!(s, "test1\ntest2\ntest3\n");
3737
}
3838

3939
fn child() {

0 commit comments

Comments
 (0)