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}