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