custom_print/
io_writer.rs

1use core::fmt::{Arguments, Debug};
2use std::io;
3
4use crate::{Flush, IntoWriteFn, WriteBytes, WriteStr};
5
6/// A writer that uses `write_bytes` and has both `write` and `flush` methods.
7///
8/// It calls `write_bytes` for each formatted chunk like the [`FmtWriter`],
9/// but provides write and flush methods that allows you to use [`BufWriter`], [`LineWriter`] etc.
10///
11/// Write function can return either
12/// `()`, `usize`, `for<E> `[`Result`]`<(), E>` or `for<E> `[`Result`]`<usize, E>`.
13///
14/// The `usize` itself or in `Result` indicates how many bytes were written.
15/// `write_fmt` method that is used by [`write!`] and [`writeln!`]
16/// will continuously call write until there is no more data to be written
17/// or a non-[`ErrorKind::Interrupted`] kind is returned.
18///
19/// Flush function can return either `()` or [`for<E> Result<(), E>`].
20///
21/// # Panics
22///
23/// Writer panics if the write function returns `Result::Err`.
24///
25/// [`FmtWriter`]: struct.FmtWriter.html
26/// [`write!`]: https://doc.rust-lang.org/std/macro.write.html
27/// [`writeln!`]: https://doc.rust-lang.org/std/macro.writeln.html
28/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
29/// [`BufWriter`]: https://doc.rust-lang.org/std/io/struct.BufWriter.html
30/// [`LineWriter`]: https://doc.rust-lang.org/std/io/struct.LineWriter.html
31/// [`ErrorKind::Interrupted`]: https://doc.rust-lang.org/std/io/enum.ErrorKind.html#variant.Interrupted
32#[derive(Clone, Copy, Debug, Eq, PartialEq)]
33pub struct IoWriter<F1, F2>(F1, F2);
34
35/// A helper trait used by [`IoWriter`] write method
36/// to convert wrapped function result to [`io::Result`] with error unwrapping.
37///
38/// [`io::Result`]: https://doc.rust-lang.org/std/io/type.Result.html
39pub trait ExpectIoWriteResult {
40    /// Performs the conversion with error unwrapping.
41    fn expect_io_write_result(self, buf: &[u8]) -> io::Result<usize>;
42}
43
44/// A helper trait used by [`IoWriter`] flush method
45/// to convert wrapped function result to [`io::Result`] with error unwrapping.
46///
47/// [`io::Result`]: https://doc.rust-lang.org/std/io/type.Result.html
48pub trait ExpectIoFlushResult {
49    /// Performs the conversion with error unwrapping.
50    fn expect_io_flush_result(self) -> io::Result<()>;
51}
52
53impl<F1, F2> IoWriter<F1, F2>
54where
55    F1: WriteStr,
56    F2: Flush,
57{
58    /// Creates a new `IoWriter` from an object that implements [`WriteBytes`]
59    /// and object that implements [`Flush`].
60    pub fn new(write: F1, flush: F2) -> Self {
61        Self(write, flush)
62    }
63}
64
65impl<F1> IoWriter<F1, ()>
66where
67    F1: WriteStr,
68{
69    /// Creates a new `IoWriter` with a [`WriteBytes`] wrapper
70    /// deduced with [`IntoWriteFn`] by the closure signature and constructed from it.
71    pub fn from_closure<F, Ts>(closure: F) -> Self
72    where
73        F: IntoWriteFn<Ts, WriteFn = F1>,
74    {
75        Self(closure.into_write_fn(), ())
76    }
77}
78
79impl<F1> IoWriter<F1, ()>
80where
81    Self: io::Write,
82{
83    /// Writes a formatted string into this writer.
84    ///
85    /// This method is primarily used to interface with the [`format_args!`] macro,
86    /// but it is rare that this should explicitly be called.
87    /// The [`write!`] macro should be favored to invoke this method instead.
88    ///
89    /// [`write!`]: https://doc.rust-lang.org/std/macro.write.html
90    /// [`format_args!`]: https://doc.rust-lang.org/std/macro.format_args.html
91    pub fn write_fmt(&mut self, args: Arguments<'_>) -> io::Result<()> {
92        io::Write::write_fmt(self, args)
93    }
94}
95
96impl<F1, F2> io::Write for IoWriter<F1, F2>
97where
98    Self: WriteBytes<Output = io::Result<usize>> + Flush<Output = io::Result<()>>,
99{
100    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
101        WriteBytes::write_bytes(self, buf)
102    }
103
104    fn flush(&mut self) -> io::Result<()> {
105        Flush::flush(self)
106    }
107}
108
109impl<F1, F2> WriteBytes for IoWriter<F1, F2>
110where
111    F1: WriteBytes,
112    F1::Output: ExpectIoWriteResult,
113{
114    type Output = io::Result<usize>;
115
116    fn write_bytes(&mut self, buf: &[u8]) -> Self::Output {
117        self.0.write_bytes(buf).expect_io_write_result(buf)
118    }
119}
120
121impl<F1, F2> Flush for IoWriter<F1, F2>
122where
123    F2: Flush,
124    F2::Output: ExpectIoFlushResult,
125{
126    type Output = io::Result<()>;
127
128    fn flush(&mut self) -> Self::Output {
129        self.1.flush().expect_io_flush_result()
130    }
131}
132
133impl ExpectIoWriteResult for () {
134    fn expect_io_write_result(self, buf: &[u8]) -> io::Result<usize> {
135        Ok(buf.len())
136    }
137}
138
139impl ExpectIoWriteResult for usize {
140    fn expect_io_write_result(self, buf: &[u8]) -> io::Result<usize> {
141        let _ = buf;
142        Ok(self)
143    }
144}
145
146impl<E: Debug> ExpectIoWriteResult for Result<(), E> {
147    fn expect_io_write_result(self, buf: &[u8]) -> io::Result<usize> {
148        self.expect("failed writing");
149        Ok(buf.len())
150    }
151}
152
153impl<E: Debug> ExpectIoWriteResult for Result<usize, E> {
154    fn expect_io_write_result(self, buf: &[u8]) -> io::Result<usize> {
155        let _ = buf;
156        Ok(self.expect("failed writing"))
157    }
158}
159
160impl ExpectIoFlushResult for () {
161    fn expect_io_flush_result(self) -> io::Result<()> {
162        Ok(())
163    }
164}
165
166impl<E: Debug> ExpectIoFlushResult for Result<(), E> {
167    fn expect_io_flush_result(self) -> io::Result<()> {
168        self.expect("failed flushing");
169        Ok(())
170    }
171}