about summary refs log tree commit diff
path: root/src/libstd/old_io/util.rs
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2015-01-22 16:27:48 -0800
committerAlex Crichton <alex@alexcrichton.com>2015-01-26 16:01:16 -0800
commitf72b1645103e12b581f7022b893c37b5fe41aef7 (patch)
tree91f98ee9b6a33110445bcf73d172e16c99042863 /src/libstd/old_io/util.rs
parent8ec3a833d5082a77e74a30c2d3d353ba7f5df644 (diff)
downloadrust-f72b1645103e12b581f7022b893c37b5fe41aef7.tar.gz
rust-f72b1645103e12b581f7022b893c37b5fe41aef7.zip
std: Rename io to old_io
In preparation for the I/O rejuvination of the standard library, this commit
renames the current `io` module to `old_io` in order to make room for the new
I/O modules. It is expected that the I/O RFCs will land incrementally over time
instead of all at once, and this provides a fresh clean path for new modules to
enter into as well as guaranteeing that all old infrastructure will remain in
place for some time.

As each `old_io` module is replaced it will be deprecated in-place for new
structures in `std::{io, fs, net}` (as appropriate).

This commit does *not* leave a reexport of `old_io as io` as the deprecation
lint does not currently warn on this form of use. This is quite a large breaking
change for all imports in existing code, but all functionality is retained
precisely as-is and path statements simply need to be renamed from `io` to
`old_io`.

[breaking-change]
Diffstat (limited to 'src/libstd/old_io/util.rs')
-rw-r--r--src/libstd/old_io/util.rs444
1 files changed, 444 insertions, 0 deletions
diff --git a/src/libstd/old_io/util.rs b/src/libstd/old_io/util.rs
new file mode 100644
index 00000000000..f3f0b8dd663
--- /dev/null
+++ b/src/libstd/old_io/util.rs
@@ -0,0 +1,444 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Utility implementations of Reader and Writer
+
+use prelude::v1::*;
+use cmp;
+use old_io;
+use slice::bytes::MutableByteVector;
+
+/// Wraps a `Reader`, limiting the number of bytes that can be read from it.
+#[derive(Show)]
+pub struct LimitReader<R> {
+    limit: uint,
+    inner: R
+}
+
+impl<R: Reader> LimitReader<R> {
+    /// Creates a new `LimitReader`
+    pub fn new(r: R, limit: uint) -> LimitReader<R> {
+        LimitReader { limit: limit, inner: r }
+    }
+
+    /// Consumes the `LimitReader`, returning the underlying `Reader`.
+    pub fn into_inner(self) -> R { self.inner }
+
+    /// Returns the number of bytes that can be read before the `LimitReader`
+    /// will return EOF.
+    ///
+    /// # Note
+    ///
+    /// The reader may reach EOF after reading fewer bytes than indicated by
+    /// this method if the underlying reader reaches EOF.
+    pub fn limit(&self) -> uint { self.limit }
+}
+
+impl<R: Reader> Reader for LimitReader<R> {
+    fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult<uint> {
+        if self.limit == 0 {
+            return Err(old_io::standard_error(old_io::EndOfFile));
+        }
+
+        let len = cmp::min(self.limit, buf.len());
+        let res = self.inner.read(&mut buf[..len]);
+        match res {
+            Ok(len) => self.limit -= len,
+            _ => {}
+        }
+        res
+    }
+}
+
+impl<R: Buffer> Buffer for LimitReader<R> {
+    fn fill_buf<'a>(&'a mut self) -> old_io::IoResult<&'a [u8]> {
+        let amt = try!(self.inner.fill_buf());
+        let buf = &amt[..cmp::min(amt.len(), self.limit)];
+        if buf.len() == 0 {
+            Err(old_io::standard_error(old_io::EndOfFile))
+        } else {
+            Ok(buf)
+        }
+    }
+
+    fn consume(&mut self, amt: uint) {
+        // Don't let callers reset the limit by passing an overlarge value
+        let amt = cmp::min(amt, self.limit);
+        self.limit -= amt;
+        self.inner.consume(amt);
+    }
+
+}
+
+/// A `Writer` which ignores bytes written to it, like /dev/null.
+#[derive(Copy, Show)]
+pub struct NullWriter;
+
+impl Writer for NullWriter {
+    #[inline]
+    fn write(&mut self, _buf: &[u8]) -> old_io::IoResult<()> { Ok(()) }
+}
+
+/// A `Reader` which returns an infinite stream of 0 bytes, like /dev/zero.
+#[derive(Copy, Show)]
+pub struct ZeroReader;
+
+impl Reader for ZeroReader {
+    #[inline]
+    fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult<uint> {
+        buf.set_memory(0);
+        Ok(buf.len())
+    }
+}
+
+impl Buffer for ZeroReader {
+    fn fill_buf<'a>(&'a mut self) -> old_io::IoResult<&'a [u8]> {
+        static DATA: [u8; 64] = [0; 64];
+        Ok(DATA.as_slice())
+    }
+
+    fn consume(&mut self, _amt: uint) {}
+}
+
+/// A `Reader` which is always at EOF, like /dev/null.
+#[derive(Copy, Show)]
+pub struct NullReader;
+
+impl Reader for NullReader {
+    #[inline]
+    fn read(&mut self, _buf: &mut [u8]) -> old_io::IoResult<uint> {
+        Err(old_io::standard_error(old_io::EndOfFile))
+    }
+}
+
+impl Buffer for NullReader {
+    fn fill_buf<'a>(&'a mut self) -> old_io::IoResult<&'a [u8]> {
+        Err(old_io::standard_error(old_io::EndOfFile))
+    }
+    fn consume(&mut self, _amt: uint) {}
+}
+
+/// A `Writer` which multiplexes writes to a set of `Writer`s.
+///
+/// The `Writer`s are delegated to in order. If any `Writer` returns an error,
+/// that error is returned immediately and remaining `Writer`s are not called.
+#[derive(Show)]
+pub struct MultiWriter<W> {
+    writers: Vec<W>
+}
+
+impl<W> MultiWriter<W> where W: Writer {
+    /// Creates a new `MultiWriter`
+    pub fn new(writers: Vec<W>) -> MultiWriter<W> {
+        MultiWriter { writers: writers }
+    }
+}
+
+impl<W> Writer for MultiWriter<W> where W: Writer {
+    #[inline]
+    fn write(&mut self, buf: &[u8]) -> old_io::IoResult<()> {
+        for writer in self.writers.iter_mut() {
+            try!(writer.write(buf));
+        }
+        Ok(())
+    }
+
+    #[inline]
+    fn flush(&mut self) -> old_io::IoResult<()> {
+        for writer in self.writers.iter_mut() {
+            try!(writer.flush());
+        }
+        Ok(())
+    }
+}
+
+/// A `Reader` which chains input from multiple `Reader`s, reading each to
+/// completion before moving onto the next.
+#[derive(Clone, Show)]
+pub struct ChainedReader<I, R> {
+    readers: I,
+    cur_reader: Option<R>,
+}
+
+impl<R: Reader, I: Iterator<Item=R>> ChainedReader<I, R> {
+    /// Creates a new `ChainedReader`
+    pub fn new(mut readers: I) -> ChainedReader<I, R> {
+        let r = readers.next();
+        ChainedReader { readers: readers, cur_reader: r }
+    }
+}
+
+impl<R: Reader, I: Iterator<Item=R>> Reader for ChainedReader<I, R> {
+    fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult<uint> {
+        loop {
+            let err = match self.cur_reader {
+                Some(ref mut r) => {
+                    match r.read(buf) {
+                        Ok(len) => return Ok(len),
+                        Err(ref e) if e.kind == old_io::EndOfFile => None,
+                        Err(e) => Some(e),
+                    }
+                }
+                None => break
+            };
+            self.cur_reader = self.readers.next();
+            match err {
+                Some(e) => return Err(e),
+                None => {}
+            }
+        }
+        Err(old_io::standard_error(old_io::EndOfFile))
+    }
+}
+
+/// A `Reader` which forwards input from another `Reader`, passing it along to
+/// a `Writer` as well. Similar to the `tee(1)` command.
+#[derive(Show)]
+pub struct TeeReader<R, W> {
+    reader: R,
+    writer: W,
+}
+
+impl<R: Reader, W: Writer> TeeReader<R, W> {
+    /// Creates a new `TeeReader`
+    pub fn new(r: R, w: W) -> TeeReader<R, W> {
+        TeeReader { reader: r, writer: w }
+    }
+
+    /// Consumes the `TeeReader`, returning the underlying `Reader` and
+    /// `Writer`.
+    pub fn into_inner(self) -> (R, W) {
+        let TeeReader { reader, writer } = self;
+        (reader, writer)
+    }
+}
+
+impl<R: Reader, W: Writer> Reader for TeeReader<R, W> {
+    fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult<uint> {
+        self.reader.read(buf).and_then(|len| {
+            self.writer.write(&mut buf[..len]).map(|()| len)
+        })
+    }
+}
+
+/// Copies all data from a `Reader` to a `Writer`.
+pub fn copy<R: Reader, W: Writer>(r: &mut R, w: &mut W) -> old_io::IoResult<()> {
+    let mut buf = [0; super::DEFAULT_BUF_SIZE];
+    loop {
+        let len = match r.read(&mut buf) {
+            Ok(len) => len,
+            Err(ref e) if e.kind == old_io::EndOfFile => return Ok(()),
+            Err(e) => return Err(e),
+        };
+        try!(w.write(&buf[..len]));
+    }
+}
+
+/// An adaptor converting an `Iterator<u8>` to a `Reader`.
+#[derive(Clone, Show)]
+pub struct IterReader<T> {
+    iter: T,
+}
+
+impl<T: Iterator<Item=u8>> IterReader<T> {
+    /// Creates a new `IterReader` which will read from the specified
+    /// `Iterator`.
+    pub fn new(iter: T) -> IterReader<T> {
+        IterReader { iter: iter }
+    }
+}
+
+impl<T: Iterator<Item=u8>> Reader for IterReader<T> {
+    #[inline]
+    fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult<uint> {
+        let mut len = 0;
+        for (slot, elt) in buf.iter_mut().zip(self.iter.by_ref()) {
+            *slot = elt;
+            len += 1;
+        }
+        if len == 0 && buf.len() != 0 {
+            Err(old_io::standard_error(old_io::EndOfFile))
+        } else {
+            Ok(len)
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use prelude::v1::*;
+
+    use old_io::{MemReader, ByRefReader};
+    use io;
+    use super::*;
+
+    #[test]
+    fn test_limit_reader_unlimited() {
+        let mut r = MemReader::new(vec!(0, 1, 2));
+        {
+            let mut r = LimitReader::new(r.by_ref(), 4);
+            assert_eq!(vec!(0, 1, 2), r.read_to_end().unwrap());
+        }
+    }
+
+    #[test]
+    fn test_limit_reader_limited() {
+        let mut r = MemReader::new(vec!(0, 1, 2));
+        {
+            let mut r = LimitReader::new(r.by_ref(), 2);
+            assert_eq!(vec!(0, 1), r.read_to_end().unwrap());
+        }
+        assert_eq!(vec!(2), r.read_to_end().unwrap());
+    }
+
+    #[test]
+    fn test_limit_reader_limit() {
+        let r = MemReader::new(vec!(0, 1, 2));
+        let mut r = LimitReader::new(r, 3);
+        assert_eq!(3, r.limit());
+        assert_eq!(0, r.read_byte().unwrap());
+        assert_eq!(2, r.limit());
+        assert_eq!(vec!(1, 2), r.read_to_end().unwrap());
+        assert_eq!(0, r.limit());
+    }
+
+    #[test]
+    fn test_limit_reader_overlong_consume() {
+        let mut r = MemReader::new(vec![0, 1, 2, 3, 4, 5]);
+        let mut r = LimitReader::new(r.by_ref(), 1);
+        r.consume(2);
+        assert_eq!(vec![], r.read_to_end().unwrap());
+    }
+
+    #[test]
+    fn test_null_writer() {
+        let mut s = NullWriter;
+        let buf = vec![0, 0, 0];
+        s.write(buf.as_slice()).unwrap();
+        s.flush().unwrap();
+    }
+
+    #[test]
+    fn test_zero_reader() {
+        let mut s = ZeroReader;
+        let mut buf = vec![1, 2, 3];
+        assert_eq!(s.read(buf.as_mut_slice()), Ok(3));
+        assert_eq!(vec![0, 0, 0], buf);
+    }
+
+    #[test]
+    fn test_null_reader() {
+        let mut r = NullReader;
+        let mut buf = vec![0];
+        assert!(r.read(buf.as_mut_slice()).is_err());
+    }
+
+    #[test]
+    fn test_multi_writer() {
+        static mut writes: uint = 0;
+        static mut flushes: uint = 0;
+
+        struct TestWriter;
+        impl Writer for TestWriter {
+            fn write(&mut self, _buf: &[u8]) -> old_io::IoResult<()> {
+                unsafe { writes += 1 }
+                Ok(())
+            }
+
+            fn flush(&mut self) -> old_io::IoResult<()> {
+                unsafe { flushes += 1 }
+                Ok(())
+            }
+        }
+
+        let mut multi = MultiWriter::new(vec!(box TestWriter as Box<Writer>,
+                                              box TestWriter as Box<Writer>));
+        multi.write(&[1, 2, 3]).unwrap();
+        assert_eq!(2, unsafe { writes });
+        assert_eq!(0, unsafe { flushes });
+        multi.flush().unwrap();
+        assert_eq!(2, unsafe { writes });
+        assert_eq!(2, unsafe { flushes });
+    }
+
+    #[test]
+    fn test_chained_reader() {
+        let rs = vec!(MemReader::new(vec!(0, 1)), MemReader::new(vec!()),
+                      MemReader::new(vec!(2, 3)));
+        let mut r = ChainedReader::new(rs.into_iter());
+        assert_eq!(vec!(0, 1, 2, 3), r.read_to_end().unwrap());
+    }
+
+    #[test]
+    fn test_tee_reader() {
+        let mut r = TeeReader::new(MemReader::new(vec!(0, 1, 2)),
+                                   Vec::new());
+        assert_eq!(vec!(0, 1, 2), r.read_to_end().unwrap());
+        let (_, w) = r.into_inner();
+        assert_eq!(vec!(0, 1, 2), w);
+    }
+
+    #[test]
+    fn test_copy() {
+        let mut r = MemReader::new(vec!(0, 1, 2, 3, 4));
+        let mut w = Vec::new();
+        copy(&mut r, &mut w).unwrap();
+        assert_eq!(vec!(0, 1, 2, 3, 4), w);
+    }
+
+    #[test]
+    fn limit_reader_buffer() {
+        let r = &mut b"0123456789\n0123456789\n";
+        {
+            let mut r = LimitReader::new(r.by_ref(), 3);
+            assert_eq!(r.read_line(), Ok("012".to_string()));
+            assert_eq!(r.limit(), 0);
+            assert_eq!(r.read_line().err().unwrap().kind, old_io::EndOfFile);
+        }
+        {
+            let mut r = LimitReader::new(r.by_ref(), 9);
+            assert_eq!(r.read_line(), Ok("3456789\n".to_string()));
+            assert_eq!(r.limit(), 1);
+            assert_eq!(r.read_line(), Ok("0".to_string()));
+        }
+        {
+            let mut r = LimitReader::new(r.by_ref(), 100);
+            assert_eq!(r.read_char(), Ok('1'));
+            assert_eq!(r.limit(), 99);
+            assert_eq!(r.read_line(), Ok("23456789\n".to_string()));
+        }
+    }
+
+    #[test]
+    fn test_iter_reader() {
+        let mut r = IterReader::new(range(0u8, 8));
+        let mut buf = [0, 0, 0];
+        let len = r.read(&mut buf).unwrap();
+        assert_eq!(len, 3);
+        assert!(buf == [0, 1, 2]);
+
+        let len = r.read(&mut buf).unwrap();
+        assert_eq!(len, 3);
+        assert!(buf == [3, 4, 5]);
+
+        let len = r.read(&mut buf).unwrap();
+        assert_eq!(len, 2);
+        assert!(buf == [6, 7, 5]);
+
+        assert_eq!(r.read(&mut buf).unwrap_err().kind, old_io::EndOfFile);
+    }
+
+    #[test]
+    fn iter_reader_zero_length() {
+        let mut r = IterReader::new(range(0u8, 8));
+        let mut buf = [];
+        assert_eq!(Ok(0), r.read(&mut buf));
+    }
+}