custom_print/
concat_try_writer.rs

1use core::fmt::{Arguments, Debug};
2
3use crate::{IntoTryWriteFn, NeverError, WriteBytes, WriteStr};
4
5/// A writer that calls `write_str` once with a combined string.
6///
7/// Write function can return either `()` or `for<T, E> `[`Result`]`<T, E>`.
8///
9/// Writer propagates error to the caller if the write function returns `Result::Err`.
10///
11/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
12#[derive(Clone, Copy, Debug, Eq, PartialEq)]
13pub struct ConcatTryWriter<F1>(F1);
14
15/// A helper trait used by [`ConcatTryWriter`]
16/// to convert wrapped function result to [`Result`]`<T, E>`.
17///
18/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
19pub trait IntoConcatWriteResult {
20    /// The resulting type after convertion.
21    type Output;
22
23    /// Performs the conversion with error propagation.
24    fn into_concat_write_result(self) -> Self::Output;
25}
26
27impl<F1> ConcatTryWriter<F1>
28where
29    F1: WriteStr,
30{
31    /// Creates a new `ConcatTryWriter` from an object that implements [`WriteStr`].
32    pub fn new(write: F1) -> Self {
33        Self(write)
34    }
35
36    /// Creates a new `ConcatTryWriter` 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> ConcatTryWriter<F1>
47where
48    Self: WriteStr,
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<'_>) -> <Self as WriteStr>::Output {
59        if let Some(buf) = args.as_str() {
60            self.write_str(buf)
61        } else {
62            let buf = alloc::fmt::format(args);
63            self.write_str(&buf)
64        }
65    }
66}
67
68impl<F1, Output> WriteStr for ConcatTryWriter<F1>
69where
70    F1: WriteStr,
71    F1::Output: IntoConcatWriteResult<Output = Output>,
72{
73    type Output = Output;
74
75    fn write_str(&mut self, buf: &str) -> Output {
76        self.0.write_str(buf).into_concat_write_result()
77    }
78}
79
80impl<F1, Output> WriteBytes for ConcatTryWriter<F1>
81where
82    F1: WriteBytes,
83    F1::Output: IntoConcatWriteResult<Output = Output>,
84{
85    type Output = Output;
86
87    fn write_bytes(&mut self, buf: &[u8]) -> Output {
88        self.0.write_bytes(buf).into_concat_write_result()
89    }
90}
91
92impl IntoConcatWriteResult for () {
93    type Output = Result<(), NeverError>;
94    fn into_concat_write_result(self) -> Self::Output {
95        Ok(())
96    }
97}
98
99impl<T, E: Debug> IntoConcatWriteResult for Result<T, E> {
100    type Output = Result<T, E>;
101    fn into_concat_write_result(self) -> Self::Output {
102        self
103    }
104}