about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-10-06 15:39:42 -0700
committerAlex Crichton <alex@alexcrichton.com>2013-10-10 03:38:51 -0700
commitee1e6529bddc4ea262e6453589a8042e0128594e (patch)
treeef21691dab3dade61813b2cc579534f73cc519d6 /src/libstd
parentfacefa7c8d1adf6c851dca88fcf4f5d26f72caa9 (diff)
downloadrust-ee1e6529bddc4ea262e6453589a8042e0128594e.tar.gz
rust-ee1e6529bddc4ea262e6453589a8042e0128594e.zip
Implement BufferedReader.{read_until, read_line}
These two functions will be useful when replacing various other counterparts
used by std::io consumers.
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/rt/io/buffered.rs72
1 files changed, 65 insertions, 7 deletions
diff --git a/src/libstd/rt/io/buffered.rs b/src/libstd/rt/io/buffered.rs
index 2269469ee23..725477bec41 100644
--- a/src/libstd/rt/io/buffered.rs
+++ b/src/libstd/rt/io/buffered.rs
@@ -55,6 +55,7 @@ use prelude::*;
 
 use num;
 use vec;
+use str;
 use super::{Reader, Writer, Stream, Decorator};
 
 // libuv recommends 64k buffers to maximize throughput
@@ -84,23 +85,69 @@ impl<R: Reader> BufferedReader<R> {
     pub fn new(inner: R) -> BufferedReader<R> {
         BufferedReader::with_capacity(DEFAULT_CAPACITY, inner)
     }
-}
 
-impl<R: Reader> Reader for BufferedReader<R> {
-    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+    /// Reads the next line of input, interpreted as a sequence of utf-8
+    /// encoded unicode codepoints. If a newline is encountered, then the
+    /// newline is contained in the returned string.
+    pub fn read_line(&mut self) -> ~str {
+        str::from_utf8_owned(self.read_until('\n' as u8))
+    }
+
+    /// Reads a sequence of bytes leading up to a specified delimeter. Once the
+    /// specified byte is encountered, reading ceases and the bytes up to and
+    /// including the delimiter are returned.
+    pub fn read_until(&mut self, byte: u8) -> ~[u8] {
+        let mut res = ~[];
+        let mut used;
+        loop {
+            {
+                let available = self.fill_buffer();
+                match available.iter().position(|&b| b == byte) {
+                    Some(i) => {
+                        res.push_all(available.slice_to(i + 1));
+                        used = i + 1;
+                        break
+                    }
+                    None => {
+                        res.push_all(available);
+                        used = available.len();
+                    }
+                }
+            }
+            if used == 0 {
+                break
+            }
+            self.pos += used;
+        }
+        self.pos += used;
+        return res;
+    }
+
+    fn fill_buffer<'a>(&'a mut self) -> &'a [u8] {
         if self.pos == self.cap {
             match self.inner.read(self.buf) {
                 Some(cap) => {
                     self.pos = 0;
                     self.cap = cap;
                 }
-                None => return None
+                None => {}
             }
         }
+        return self.buf.slice(self.pos, self.cap);
+    }
+}
 
-        let src = self.buf.slice(self.pos, self.cap);
-        let nread = num::min(src.len(), buf.len());
-        vec::bytes::copy_memory(buf, src, nread);
+impl<R: Reader> Reader for BufferedReader<R> {
+    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+        let nread = {
+            let available = self.fill_buffer();
+            if available.len() == 0 {
+                return None;
+            }
+            let nread = num::min(available.len(), buf.len());
+            vec::bytes::copy_memory(buf, available, nread);
+            nread
+        };
         self.pos += nread;
         Some(nread)
     }
@@ -355,4 +402,15 @@ mod test {
         stream.write(buf);
         stream.flush();
     }
+
+    #[test]
+    fn test_read_until() {
+        let inner = MemReader::new(~[0, 1, 2, 1, 0]);
+        let mut reader = BufferedReader::with_capacity(2, inner);
+        assert_eq!(reader.read_until(0), Some(~[0]));
+        assert_eq!(reader.read_until(2), Some(~[1, 2]));
+        assert_eq!(reader.read_until(1), Some(~[1]));
+        assert_eq!(reader.read_until(8), Some(~[0]));
+        assert_eq!(reader.read_until(9), None);
+    }
 }