ckb_rust_std/io/buffered/
linewriter.rs

1use crate::io::{self, buffered::LineWriterShim, BufWriter, IntoInnerError, Write};
2use alloc::fmt;
3/// Wraps a writer and buffers output to it, flushing whenever a newline
4/// (`0x0a`, `'\n'`) is detected.
5///
6/// The [`BufWriter`] struct wraps a writer and buffers its output.
7/// But it only does this batched write when it goes out of scope, or when the
8/// internal buffer is full. Sometimes, you'd prefer to write each line as it's
9/// completed, rather than the entire buffer at once. Enter `LineWriter`. It
10/// does exactly that.
11///
12/// Like [`BufWriter`], a `LineWriter`’s buffer will also be flushed when the
13/// `LineWriter` goes out of scope or when its internal buffer is full.
14///
15/// If there's still a partial line in the buffer when the `LineWriter` is
16/// dropped, it will flush those contents.
17///
18/// # Examples
19///
20/// We can use `LineWriter` to write one line at a time, significantly
21/// reducing the number of actual writes to the file.
22///
23/// ```no_run
24/// use std::fs::{self, File};
25/// use std::io::prelude::*;
26/// use std::io::LineWriter;
27///
28/// fn main() -> std::io::Result<()> {
29///     let road_not_taken = b"I shall be telling this with a sigh
30/// Somewhere ages and ages hence:
31/// Two roads diverged in a wood, and I -
32/// I took the one less traveled by,
33/// And that has made all the difference.";
34///
35///     let file = File::create("poem.txt")?;
36///     let mut file = LineWriter::new(file);
37///
38///     file.write_all(b"I shall be telling this with a sigh")?;
39///
40///     // No bytes are written until a newline is encountered (or
41///     // the internal buffer is filled).
42///     assert_eq!(fs::read_to_string("poem.txt")?, "");
43///     file.write_all(b"\n")?;
44///     assert_eq!(
45///         fs::read_to_string("poem.txt")?,
46///         "I shall be telling this with a sigh\n",
47///     );
48///
49///     // Write the rest of the poem.
50///     file.write_all(b"Somewhere ages and ages hence:
51/// Two roads diverged in a wood, and I -
52/// I took the one less traveled by,
53/// And that has made all the difference.")?;
54///
55///     // The last line of the poem doesn't end in a newline, so
56///     // we have to flush or drop the `LineWriter` to finish
57///     // writing.
58///     file.flush()?;
59///
60///     // Confirm the whole poem was written.
61///     assert_eq!(fs::read("poem.txt")?, &road_not_taken[..]);
62///     Ok(())
63/// }
64/// ```
65pub struct LineWriter<W: ?Sized + Write> {
66    inner: BufWriter<W>,
67}
68
69impl<W: Write> LineWriter<W> {
70    /// Creates a new `LineWriter`.
71    ///
72    /// # Examples
73    ///
74    /// ```no_run
75    /// use std::fs::File;
76    /// use std::io::LineWriter;
77    ///
78    /// fn main() -> std::io::Result<()> {
79    ///     let file = File::create("poem.txt")?;
80    ///     let file = LineWriter::new(file);
81    ///     Ok(())
82    /// }
83    /// ```
84    pub fn new(inner: W) -> LineWriter<W> {
85        // Lines typically aren't that long, don't use a giant buffer
86        LineWriter::with_capacity(1024, inner)
87    }
88
89    /// Creates a new `LineWriter` with at least the specified capacity for the
90    /// internal buffer.
91    ///
92    /// # Examples
93    ///
94    /// ```no_run
95    /// use std::fs::File;
96    /// use std::io::LineWriter;
97    ///
98    /// fn main() -> std::io::Result<()> {
99    ///     let file = File::create("poem.txt")?;
100    ///     let file = LineWriter::with_capacity(100, file);
101    ///     Ok(())
102    /// }
103    /// ```
104    pub fn with_capacity(capacity: usize, inner: W) -> LineWriter<W> {
105        LineWriter {
106            inner: BufWriter::with_capacity(capacity, inner),
107        }
108    }
109
110    /// Gets a mutable reference to the underlying writer.
111    ///
112    /// Caution must be taken when calling methods on the mutable reference
113    /// returned as extra writes could corrupt the output stream.
114    ///
115    /// # Examples
116    ///
117    /// ```no_run
118    /// use std::fs::File;
119    /// use std::io::LineWriter;
120    ///
121    /// fn main() -> std::io::Result<()> {
122    ///     let file = File::create("poem.txt")?;
123    ///     let mut file = LineWriter::new(file);
124    ///
125    ///     // we can use reference just like file
126    ///     let reference = file.get_mut();
127    ///     Ok(())
128    /// }
129    /// ```
130    pub fn get_mut(&mut self) -> &mut W {
131        self.inner.get_mut()
132    }
133
134    /// Unwraps this `LineWriter`, returning the underlying writer.
135    ///
136    /// The internal buffer is written out before returning the writer.
137    ///
138    /// # Errors
139    ///
140    /// An [`Err`] will be returned if an error occurs while flushing the buffer.
141    ///
142    /// # Examples
143    ///
144    /// ```no_run
145    /// use std::fs::File;
146    /// use std::io::LineWriter;
147    ///
148    /// fn main() -> std::io::Result<()> {
149    ///     let file = File::create("poem.txt")?;
150    ///
151    ///     let writer: LineWriter<File> = LineWriter::new(file);
152    ///
153    ///     let file: File = writer.into_inner()?;
154    ///     Ok(())
155    /// }
156    /// ```
157    pub fn into_inner(self) -> Result<W, IntoInnerError<LineWriter<W>>> {
158        self.inner
159            .into_inner()
160            .map_err(|err| err.new_wrapped(|inner| LineWriter { inner }))
161    }
162}
163
164impl<W: ?Sized + Write> LineWriter<W> {
165    /// Gets a reference to the underlying writer.
166    ///
167    /// # Examples
168    ///
169    /// ```no_run
170    /// use std::fs::File;
171    /// use std::io::LineWriter;
172    ///
173    /// fn main() -> std::io::Result<()> {
174    ///     let file = File::create("poem.txt")?;
175    ///     let file = LineWriter::new(file);
176    ///
177    ///     let reference = file.get_ref();
178    ///     Ok(())
179    /// }
180    /// ```
181    pub fn get_ref(&self) -> &W {
182        self.inner.get_ref()
183    }
184}
185impl<W: ?Sized + Write> Write for LineWriter<W> {
186    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
187        LineWriterShim::new(&mut self.inner).write(buf)
188    }
189    fn flush(&mut self) -> io::Result<()> {
190        self.inner.flush()
191    }
192    fn is_write_vectored(&self) -> bool {
193        self.inner.is_write_vectored()
194    }
195
196    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
197        LineWriterShim::new(&mut self.inner).write_all(buf)
198    }
199    fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
200        LineWriterShim::new(&mut self.inner).write_fmt(fmt)
201    }
202}
203impl<W: ?Sized + Write> fmt::Debug for LineWriter<W>
204where
205    W: fmt::Debug,
206{
207    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
208        fmt.debug_struct("LineWriter")
209            .field("writer", &self.get_ref())
210            .field(
211                "buffer",
212                &format_args!("{}/{}", self.inner.buffer().len(), self.inner.capacity()),
213            )
214            .finish_non_exhaustive()
215    }
216}