display_buffered/
lib.rs

1//! Provides convinience functions to write all the elements into a writer with buffering
2
3use std::{
4    fmt::Display,
5    io::{self, BufWriter, Write},
6};
7
8/// Writes all the items into the writer with buffering sepparating them with the new line
9///
10/// # Arguments
11///
12/// * values - iterator of values to print
13/// * writer - buffer to write into
14///
15/// # Errors
16///
17/// Errors if the writing or flushing the buffer errors
18///
19/// # Example
20///
21/// ```
22/// use display_buffered::display_buffered;
23///
24/// use std::io::stdout;
25///
26/// display_buffered([10, 20, 30], stdout()).unwrap()
27/// ```
28#[inline]
29pub fn display_buffered<I, T, W>(values: I, writer: W) -> Result<(), io::Error>
30where
31    T: Display,
32    I: IntoIterator<Item = T>,
33    W: Write,
34{
35    let mut writer = BufWriter::new(writer);
36
37    for value in values {
38        writeln!(writer, "{value}")?
39    }
40
41    writer.flush()
42}
43
44/// Writes all the bytes from values into the writer with buffering without any separators.
45/// Worth noting that values may also consist of String and &str and any other objects that can
46/// be turned into &[u8] using as_ref method
47///
48/// # Arguments
49///
50/// * values - iterator of elements to write
51/// * writer - buffer to write into
52///
53/// # Errors
54///
55/// Errors if the writing or flushing the buffer errors
56///
57/// # Example
58///
59/// ```
60/// use display_buffered::write_buffered;
61///
62/// use std::io::stdout;
63///
64/// write_buffered(["10", "20", "30"], stdout()).unwrap() // Prints 102030
65/// ```
66#[inline]
67pub fn write_buffered<T, I, W>(values: I, writer: W) -> Result<(), io::Error>
68where
69    T: AsRef<[u8]>,
70    I: IntoIterator<Item = T>,
71    W: Write,
72{
73    let mut writer = BufWriter::new(writer);
74
75    for bytes in values {
76        writer.write_all(bytes.as_ref())?
77    }
78
79    writer.flush()
80}
81
82/// Writes all the elements from values into the writer with the provided separator.
83/// The separator isn't written after the last element
84///
85/// # Arguments
86///
87/// * values - iterator of elements to write
88/// * writer - buffer to write into
89/// * sep - separator to use
90///
91/// # Errors
92///
93/// Errors if the writing or flushing the buffer errors
94///
95/// # Example
96///
97/// ```
98/// use display_buffered::write_buffered_separated;
99///
100/// use std::io::stdout;
101///
102/// // Prints "It_Just_Works"
103/// write_buffered_separated(["It", "Just", "Works"], stdout(), b"_").unwrap()
104/// ```
105#[inline]
106pub fn write_buffered_separated<T, I, W>(
107    values: I,
108    mut writer: W,
109    sep: &[u8],
110) -> Result<(), io::Error>
111where
112    T: AsRef<[u8]>,
113    I: IntoIterator<Item = T>,
114    W: Write,
115{
116    let mut values = values.into_iter();
117    // We are not initializing buf_writer here to avoid unnessesary heap allocation if there're no values
118    let mut buf_writer;
119    match values.next() {
120        Some(val) => {
121            buf_writer = BufWriter::new(writer);
122            buf_writer.write_all(val.as_ref())?
123        }
124        None => return writer.flush(),
125    }
126
127    for bytes in values {
128        buf_writer.write_all(sep)?;
129        buf_writer.write_all(bytes.as_ref())?
130    }
131
132    buf_writer.flush()
133}
134
135/// Writes all the elements from values into the writer with the computed separator.
136/// The separator isn't written after the last element
137///
138/// # Arguments
139///
140/// * values - iterator of elements to write
141/// * writer - buffer to write into
142/// * f - Function that computes the sepparator from the index and the value of next printed value
143///
144/// # Errors
145///
146/// Errors if the writing or flushing the buffer errors
147///
148/// # Example
149///
150/// ```
151/// use display_buffered::write_buffered_separated_with;
152///
153/// use std::io::stdout;
154///
155/// write_buffered_separated_with(["It", "Just", "Works"], stdout(), |i, _| {
156/// if i % 2 == 0 {
157///     "_"
158/// } else {
159///     "-"
160/// }
161/// })
162/// .unwrap(); // Prints "It-Just_Works"
163/// ```
164#[inline]
165pub fn write_buffered_separated_with<T, I, W, U, F>(
166    values: I,
167    mut writer: W,
168    mut f: F,
169) -> Result<(), io::Error>
170where
171    T: AsRef<[u8]>,
172    I: IntoIterator<Item = T>,
173    W: Write,
174    U: AsRef<[u8]>,
175    F: FnMut(usize, &[u8]) -> U,
176{
177    let mut values = values.into_iter().enumerate();
178    // We are not initializing buf_writer here to avoid unnessesary heap allocation if there're no values
179    let mut buf_writer;
180    match values.next() {
181        Some((_, val)) => {
182            buf_writer = BufWriter::new(writer);
183            buf_writer.write_all(val.as_ref())?
184        }
185        None => return writer.flush(),
186    }
187
188    for (pos, bytes) in values {
189        let bytes = bytes.as_ref();
190        buf_writer.write_all(f(pos, bytes).as_ref())?;
191        buf_writer.write_all(bytes)?
192    }
193
194    buf_writer.flush()
195}
196
197#[cfg(test)]
198mod tests {
199    use super::*;
200
201    /// A Write implementation for testing
202    struct Writer(Vec<u8>);
203
204    impl Writer {
205        fn new() -> Self {
206            Self(Vec::new())
207        }
208
209        fn into_inner(self) -> Vec<u8> {
210            self.0
211        }
212    }
213
214    impl Write for Writer {
215        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
216            self.0.extend(buf);
217            Ok(buf.len())
218        }
219
220        fn flush(&mut self) -> io::Result<()> {
221            Ok(())
222        }
223    }
224
225    #[test]
226    fn test_display_buffered() {
227        let mut writer = Writer::new();
228        display_buffered([10, 20], &mut writer).unwrap();
229        assert_eq!(writer.into_inner(), b"10\n20\n")
230    }
231
232    #[test]
233    fn test_write_buffered_with_slices() {
234        let mut writer = Writer::new();
235        write_buffered(["It ", "Works"], &mut writer).unwrap();
236        assert_eq!(writer.into_inner(), b"It Works")
237    }
238
239    #[test]
240    fn test_write_buffered_with_strings() {
241        let mut writer = Writer::new();
242        write_buffered(["It ".to_owned(), "Works".to_owned()], &mut writer).unwrap();
243        assert_eq!(writer.into_inner(), b"It Works")
244    }
245
246    #[test]
247    fn test_write_buffered_with_bytes() {
248        let mut writer = Writer::new();
249        let values: [&[u8]; 2] = [b"It ", b"Works"];
250        write_buffered(values, &mut writer).unwrap();
251        assert_eq!(writer.into_inner(), b"It Works")
252    }
253
254    #[test]
255    fn test_write_buffered_with_separator() {
256        let mut writer = Writer::new();
257        write_buffered_separated(["It", "Just", "Works"], &mut writer, b" ").unwrap();
258        assert_eq!(writer.into_inner(), b"It Just Works")
259    }
260
261    #[test]
262    fn test_write_buffered_separated_with() {
263        let mut writer = Writer::new();
264        write_buffered_separated_with(["It", "Just", "Works"], &mut writer, |i, _| {
265            if i % 2 == 0 {
266                b"_"
267            } else {
268                b"-"
269            }
270        })
271        .unwrap();
272        assert_eq!(writer.into_inner(), b"It-Just_Works")
273    }
274
275    #[test]
276    fn test_write_buffered_separated_with2() {
277        let mut writer = Writer::new();
278        write_buffered_separated_with(["It", "Just ", "Works_"], &mut writer, |_, val| {
279            if val.len() % 2 == 0 {
280                b"_"
281            } else {
282                b"-"
283            }
284        })
285        .unwrap();
286        assert_eq!(writer.into_inner(), b"It-Just _Works_")
287    }
288}