custom_print/
concat_writer.rs

1use core::fmt::{Arguments, Debug};
2
3use crate::{IntoWriteFn, 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/// # Panics
10///
11/// Writer panics if the write function returns `Result::Err`.
12///
13/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
14#[derive(Clone, Copy, Debug, Eq, PartialEq)]
15pub struct ConcatWriter<F1>(F1);
16
17/// A helper trait used by [`ConcatWriter`]
18/// to convert wrapped function result to [`Result`]`<T, NeverError>` with error unwrapping.
19///
20/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
21
22pub trait ExpectConcatWriteResult {
23    /// The resulting type after convertion.
24    type Output;
25
26    /// Performs the conversion with error unwrapping.
27    fn expect_concat_write_result(self) -> Self::Output;
28}
29
30impl<F1> ConcatWriter<F1>
31where
32    F1: WriteStr,
33{
34    /// Creates a new `ConcatWriter` from an object that implements [`WriteStr`].
35    pub fn new(write: F1) -> Self {
36        Self(write)
37    }
38
39    /// Creates a new `ConcatWriter` with a [`WriteStr`] wrapper
40    /// deduced with [`IntoWriteFn`] by the closure signature and constructed from it.
41    pub fn from_closure<F, Ts>(closure: F) -> Self
42    where
43        F: IntoWriteFn<Ts, WriteFn = F1>,
44    {
45        Self(closure.into_write_fn())
46    }
47}
48
49impl<F1> ConcatWriter<F1>
50where
51    Self: WriteStr,
52{
53    /// Writes a formatted string into this writer.
54    ///
55    /// This method is primarily used to interface with the [`format_args!`] macro,
56    /// but it is rare that this should explicitly be called.
57    /// The [`write!`] macro should be favored to invoke this method instead.
58    ///
59    /// [`write!`]: https://doc.rust-lang.org/std/macro.write.html
60    /// [`format_args!`]: https://doc.rust-lang.org/std/macro.format_args.html
61    pub fn write_fmt(&mut self, args: Arguments<'_>) -> <Self as WriteStr>::Output {
62        if let Some(buf) = args.as_str() {
63            self.write_str(buf)
64        } else {
65            let buf = alloc::fmt::format(args);
66            self.write_str(&buf)
67        }
68    }
69}
70
71impl<F1, Output> WriteStr for ConcatWriter<F1>
72where
73    F1: WriteStr,
74    F1::Output: ExpectConcatWriteResult<Output = Output>,
75{
76    type Output = Output;
77
78    fn write_str(&mut self, buf: &str) -> Output {
79        self.0.write_str(buf).expect_concat_write_result()
80    }
81}
82
83impl<F1, Output> WriteBytes for ConcatWriter<F1>
84where
85    F1: WriteBytes,
86    F1::Output: ExpectConcatWriteResult<Output = Output>,
87{
88    type Output = Output;
89
90    fn write_bytes(&mut self, buf: &[u8]) -> Output {
91        self.0.write_bytes(buf).expect_concat_write_result()
92    }
93}
94
95impl ExpectConcatWriteResult for () {
96    type Output = Result<(), NeverError>;
97    fn expect_concat_write_result(self) -> Self::Output {
98        Ok(())
99    }
100}
101
102impl<T, E: Debug> ExpectConcatWriteResult for Result<T, E> {
103    type Output = Result<T, NeverError>;
104    fn expect_concat_write_result(self) -> Self::Output {
105        Ok(self.expect("failed writing"))
106    }
107}