1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
use {Write, BufRead, Result, Error, ErrorKind}; use memchr; /// Copies the entire content of a buffered reader into a writer. /// /// Similar to [`std::io::copy`], this function will continuously read data from reader and /// then write it into writer in a streaming fashion until reader returns EOF. /// /// Errors /// ====== /// This function will return an error immediately if any call to [`fill_buf`] or /// [`write`] returns any kind of error. /// Instances of [`ErrorKind`]`::Interrupted` are *not* handled by this function. /// /// All bytes consumed from the buffered reader will be written to the specified writer and vice /// versa. /// It is guaranteed that no data is lost in case of error. /// /// Differences to `std::io::copy` /// ============================== /// - Does not retry on [`ErrorKind`]`::Interrupted`. /// - Uses [`BufRead`] instead of [`Read`]. /// - Does not return the number of bytes that are copied. /// /// Advantages /// ---------- /// - Allows for reliable retry on errors. /// - Function is interruptable, e.g. to allow graceful shutdown for server applications. /// - Avoids double buffering if the source already implements [`BufRead`]. /// - Allows different buffer sizes by using [`BufReader::with_capacity`]. /// /// Disadvantages /// ------------- /// The fact that it does not return the number of bytes copied stems from the fact that it cannot /// return this information in case of error. /// This would go against the goal of allowing reliable retry. /// /// [`fill_buf`]: ./trait.BufRead.html#tymethod.fill_buf /// [`write`]: ./trait.Write.html#tymethod.write /// [`Read`]: ./trait.Read.html /// [`BufRead`]: ./trait.BufRead.html /// [`BufReader::with_capacity`]: ./buf_redux_reexport/struct.BufReader.html#method.with_capacity /// [`std::io::copy`]: https://doc.rust-lang.org/nightly/std/io/fn.copy.html /// [`ErrorKind`]: https://doc.rust-lang.org/nightly/std/io/enum.ErrorKind.html pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> Result<()> where R: BufRead, W: Write { loop { let written = { let buf = try!(reader.fill_buf()); if buf.len() == 0 { return Ok(()); } try!(writer.write(buf)) }; if written == 0 { return Err(Error::new(ErrorKind::WriteZero, "no bytes could be written")); } reader.consume(written); } } /// Copies the content of a buffered reader into a writer until a delimiter is reached. /// /// This function will continuously read data from reader and then write it into writer in a /// streaming fashion until until the delimiter or EOF is found. /// /// Errors /// ====== /// This function will return an error immediately if any call to [`fill_buf`] or /// [`write`] returns any kind of error. /// Instances of [`ErrorKind`]`::Interrupted` are *not* handled by this function. /// /// All bytes consumed from the buffered reader will be written to the specified writer and vice /// versa. /// It is guaranteed that no data is lost in case of error. /// /// [`fill_buf`]: ./trait.BufRead.html#tymethod.fill_buf /// [`write`]: ./trait.Write.html#tymethod.write /// [`ErrorKind`]: https://doc.rust-lang.org/nightly/std/io/enum.ErrorKind.html pub fn copy_until<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W, delim: u8) -> Result<()> where R: BufRead, W: Write { loop { let (found, used) = { let buf = try!(reader.fill_buf()); if buf.len() == 0 { return Err(Error::new(ErrorKind::UnexpectedEof, "Stream did not contain the delimiter")); } match memchr::memchr(delim, buf) { Some(i) => { let written = try!(writer.write(&buf[..i + 1])); (written == i + 1, written) } None => (false, try!(writer.write(buf))), } }; if used == 0 { return Err(Error::new(ErrorKind::WriteZero, "no bytes could be written")); } reader.consume(used); if found { return Ok(()); } } }