read_write_pipe/
lib.rs

1use std::io::{ErrorKind, Read, Result, Write};
2
3/// A trait for objects implementing [`Write`], to write all content from a [`Read`] object.
4///
5/// This trait adds one method to the writers implementing it.
6/// * `write_reader`
7/// This method allows to read a whole reader object into the writer.
8/// There is no garantee about the state of both reader and writer in case of an error.
9/// ```
10/// use std::io;
11/// use read_write_pipe::*;
12/// let _ = io::stdout().write_reader(io::stdin()).unwrap();
13/// ```
14///
15/// [`Read`]:         https://doc.rust-lang.org/std/io/trait.Read.html
16/// [`Write`]:         https://doc.rust-lang.org/std/io/trait.Read.html
17pub trait ReadWritePipe: Write {
18    fn write_reader<R: Read>(&mut self, mut r: R) -> Result<usize> {
19        let ret;
20        let mut bytes_written = 0;
21        let mut buffer = [0; 1024];
22
23        loop {
24            match r.read(&mut buffer[..]) {
25                Ok(0) => {
26                    ret = Ok(bytes_written);
27                    break;
28                }
29                Ok(n) => {
30                    self.write_all(&buffer[0..n])?;
31                    bytes_written += n;
32                }
33                Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
34                Err(e) => {
35                    ret = Err(e);
36                    break;
37                }
38            }
39        }
40        ret
41    }
42}
43
44impl<W: Write> ReadWritePipe for W {}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49
50    #[test]
51    fn writes_all_bytes_from_reader_into_writer() {
52        let reader = b"a small little text";
53        let mut writer: Vec<u8> = Vec::new();
54        let size = writer.write_reader(reader as &[u8]).unwrap();
55        assert_eq!(size, 19);
56        let mut expected_result: Vec<u8> = Vec::new();
57        expected_result.write_all(b"a small little text").unwrap();
58        assert_eq!(writer, expected_result);
59    }
60}