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}