custom_print/
fmt_try_writer.rs

1use core::fmt::{self, Arguments, Debug};
2
3use crate::{IntoTryWriteFn, WriteBytes, WriteStr};
4
5/// A writer that calls `write_str` for each formatted chunk, but do not require allocations.
6///
7/// Write function can return either `()` or [`fmt::Result`].
8///
9/// Writer propagates error to the caller if the write function returns `Result::Err`.
10/// Note that the error context will be lost, because [`fmt::Error`]
11/// does not support transmission of an error other than that an error occurred.
12///
13/// [`fmt::Error`]: https://doc.rust-lang.org/std/fmt/struct.Error.html
14/// [`fmt::Result`]: https://doc.rust-lang.org/std/fmt/type.Result.html
15#[derive(Clone, Copy, Debug, Eq, PartialEq)]
16pub struct FmtTryWriter<F1>(F1);
17
18/// A helper trait used by [`FmtTryWriter`]
19/// to convert wrapped function result to [`fmt::Result`] with error propagation.
20///
21/// [`fmt::Result`]: https://doc.rust-lang.org/std/fmt/type.Result.html
22pub trait IntoFmtWriteResult {
23    /// Performs the conversion with error propagation.
24    fn into_fmt_write_result(self) -> fmt::Result;
25}
26
27impl<F1> FmtTryWriter<F1>
28where
29    F1: WriteStr,
30{
31    /// Creates a new `FmtTryWriter` from an object that implements [`WriteStr`].
32    pub fn new(write: F1) -> Self {
33        Self(write)
34    }
35
36    /// Creates a new `FmtTryWriter` with a [`WriteStr`] wrapper
37    /// deduced with [`IntoTryWriteFn`] by the closure signature and constructed from it.
38    pub fn from_closure<F, Ts>(closure: F) -> Self
39    where
40        F: IntoTryWriteFn<Ts, TryWriteFn = F1>,
41    {
42        Self(closure.into_try_write_fn())
43    }
44}
45
46impl<F1> FmtTryWriter<F1>
47where
48    Self: fmt::Write,
49{
50    /// Writes a formatted string into this writer, returning any error encountered.
51    ///
52    /// This method is primarily used to interface with the [`format_args!`] macro,
53    /// but it is rare that this should explicitly be called.
54    /// The [`write!`] macro should be favored to invoke this method instead.
55    ///
56    /// [`write!`]: https://doc.rust-lang.org/std/macro.write.html
57    /// [`format_args!`]: https://doc.rust-lang.org/std/macro.format_args.html
58    pub fn write_fmt(&mut self, args: Arguments<'_>) -> fmt::Result {
59        fmt::Write::write_fmt(self, args)
60    }
61}
62
63impl<F1> fmt::Write for FmtTryWriter<F1>
64where
65    Self: WriteStr<Output = fmt::Result>,
66{
67    fn write_str(&mut self, buf: &str) -> fmt::Result {
68        WriteStr::write_str(self, buf)
69    }
70}
71
72impl<F1> WriteStr for FmtTryWriter<F1>
73where
74    F1: WriteStr,
75    F1::Output: IntoFmtWriteResult,
76{
77    type Output = fmt::Result;
78
79    fn write_str(&mut self, buf: &str) -> Self::Output {
80        self.0.write_str(buf).into_fmt_write_result()
81    }
82}
83
84impl<F1> WriteBytes for FmtTryWriter<F1>
85where
86    F1: WriteBytes,
87    F1::Output: IntoFmtWriteResult,
88{
89    type Output = fmt::Result;
90
91    fn write_bytes(&mut self, buf: &[u8]) -> Self::Output {
92        self.0.write_bytes(buf).into_fmt_write_result()
93    }
94}
95
96impl IntoFmtWriteResult for () {
97    fn into_fmt_write_result(self) -> fmt::Result {
98        Ok(())
99    }
100}
101
102impl<E: Debug> IntoFmtWriteResult for Result<(), E> {
103    fn into_fmt_write_result(self) -> fmt::Result {
104        self.map_err(|_| fmt::Error)
105    }
106}