summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-11-13 11:36:21 -0800
committerAlex Crichton <alex@alexcrichton.com>2013-11-16 02:11:47 -0800
commit01343d3d2987dfea6a3982aba3735a95c9a0c51c (patch)
treef178b7261ab93af8612dd9258267c7f094e24bee /src/libstd
parent7bc092f109d79b7214fb11108bbe38ac322c775c (diff)
downloadrust-01343d3d2987dfea6a3982aba3735a95c9a0c51c.tar.gz
rust-01343d3d2987dfea6a3982aba3735a95c9a0c51c.zip
Implement read_char on the Buffer trait
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/io/mem.rs16
-rw-r--r--src/libstd/io/mod.rs27
2 files changed, 43 insertions, 0 deletions
diff --git a/src/libstd/io/mem.rs b/src/libstd/io/mem.rs
index 541648a534f..2f4324f9db6 100644
--- a/src/libstd/io/mem.rs
+++ b/src/libstd/io/mem.rs
@@ -299,4 +299,20 @@ mod test {
         let buf = with_mem_writer(|wr| wr.write([1,2,3,4,5,6,7]));
         assert_eq!(buf, ~[1,2,3,4,5,6,7]);
     }
+
+    #[test]
+    fn test_read_char() {
+        let mut r = BufReader::new(bytes!("Việt"));
+        assert_eq!(r.read_char(), Some('V'));
+        assert_eq!(r.read_char(), Some('i'));
+        assert_eq!(r.read_char(), Some('ệ'));
+        assert_eq!(r.read_char(), Some('t'));
+        assert_eq!(r.read_char(), None);
+    }
+
+    #[test]
+    fn test_read_bad_char() {
+        let mut r = BufReader::new(bytes!(0x80));
+        assert_eq!(r.read_char(), None);
+    }
 }
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index 251e60bdbe0..6924b33aecd 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -1048,6 +1048,33 @@ pub trait Buffer: Reader {
         self.consume(used);
         return if res.len() == 0 {None} else {Some(res)};
     }
+
+    /// Reads the next utf8-encoded character from the underlying stream.
+    ///
+    /// This will return `None` if the following sequence of bytes in the
+    /// stream are not a valid utf8-sequence, or if an I/O error is encountered.
+    ///
+    /// # Failure
+    ///
+    /// This function will raise on the `io_error` condition if a read error is
+    /// encountered.
+    fn read_char(&mut self) -> Option<char> {
+        let width = {
+            let available = self.fill();
+            if available.len() == 0 { return None } // read error
+            str::utf8_char_width(available[0])
+        };
+        if width == 0 { return None } // not uf8
+        let mut buf = [0, ..4];
+        match self.read(buf.mut_slice_to(width)) {
+            Some(n) if n == width => {}
+            Some(*) | None => return None // read error
+        }
+        match str::from_utf8_slice_opt(buf.slice_to(width)) {
+            Some(s) => Some(s.char_at(0)),
+            None => None
+        }
+    }
 }
 
 pub enum SeekStyle {