const_format/macros/
call_debug_fmt.rs

1/// For debug formatting of some specific generic std types, and other types.
2///
3/// # Errors
4///
5/// This macro propagates errors from the debug formatting methods that
6/// it calls, by `return`ing them.
7///
8/// # Macro variants
9///
10/// The macro has these variants:
11///
12/// - `slice` (also `array`): to format a slice or an array of *any debug type.
13///
14/// - `Option`: to format an `Option` of *any debug type.
15///
16/// - `newtype`: to format a single field tuple struct (eg: `struct Foo(Bar);`)
17/// which wraps *any debug type.
18///
19/// - `std`: to format the standard library types, where `PWrapper<ThatType>`
20/// has a `const_debug_fmt` method.<br>
21///
22/// - `other`: to format non-standard-library types that have a `const_debug_fmt` method.
23///
24/// *"any debug type" meaning types that have a `const_debug_fmt` method
25///
26/// # Example
27///
28/// ### Printing all of them
29///
30/// Printing all of the kinds of types this supports.
31///
32/// ```rust
33///
34/// use const_format::{
35///     for_examples::{Point3, Unit},
36///     Error, Formatter, FormattingFlags, StrWriter,
37///     call_debug_fmt, try_, unwrap,
38/// };
39///
40/// use std::num::Wrapping;
41///
42/// const CAP: usize = 512;
43///
44/// // `call_debug_fmt` implicitly returns on error,
45/// // so the function has to return a `Result<_, const_format::Error>`
46/// const fn make() -> Result<StrWriter<[u8; CAP]>, Error> {
47///     let mut writer = StrWriter::new([0; CAP]);
48///     let mut fmt = Formatter::from_sw(&mut writer, FormattingFlags::NEW);
49///     let mut fmt = fmt.debug_struct("Foo");
50///
51///     let point = Point3{ x: 5, y: 8, z: 13 };
52///
53///     call_debug_fmt!(array, [Unit, Unit], fmt.field("array") );
54///     call_debug_fmt!(slice, [0u8, 1], fmt.field("slice") );
55///     call_debug_fmt!(Option, Some(point), fmt.field("option") );
56///     call_debug_fmt!(newtype NumWrapping, Wrapping(255u16), fmt.field("newtype") );
57///     call_debug_fmt!(std, false, fmt.field("std_") );
58///     call_debug_fmt!(other, point, fmt.field("other") );
59///
60///     try_!(fmt.finish());
61///     Ok(writer)
62/// }
63///
64/// const TEXT: &str = {
65///     const PROM: &StrWriter<[u8]> = &unwrap!(make());
66///     PROM.as_str_alt()
67/// };
68///
69/// const EXPECTED: &str = "\
70///     Foo { \
71///         array: [Unit, Unit], \
72///         slice: [0, 1], \
73///         option: Some(Point3 { x: 5, y: 8, z: 13 }), \
74///         newtype: NumWrapping(255), \
75///         std_: false, \
76///         other: Point3 { x: 5, y: 8, z: 13 } \
77///     }\
78/// ";
79///
80/// assert_eq!(TEXT, EXPECTED);
81///
82/// ```
83///
84/// ### Used as `formatc` argument
85///
86/// This macro can be used in the formatting macros by using the Formatter in the argument,<br>
87/// with the `|formatter_ident| expression_that_uses_formatter ` syntax.
88///
89///
90/// ```rust
91///
92/// use const_format::{
93///     for_examples::{Point3, Unit},
94///     Error, Formatter, FormattingFlags, StrWriter,
95///     call_debug_fmt, formatc, try_, unwrap,
96/// };
97///
98/// use std::num::Wrapping;
99///
100/// const POINT: Point3 = Point3{ x: 5, y: 8, z: 13 };
101///
102/// const TEXT: &str = formatc!(
103///     "a: {},b: {},c: {},d: {},e: {},f: {},",
104///     |fmt| call_debug_fmt!(array, [Unit, Unit], fmt ),
105///     |fmt| call_debug_fmt!(slice, [0u8, 1], fmt ),
106///     |fmt| call_debug_fmt!(Option, Some(POINT), fmt ),
107///     |fmt| call_debug_fmt!(newtype NumWrapping, Wrapping(255u16), fmt ),
108///     |fmt| call_debug_fmt!(std, false, fmt ),
109///     |fmt| call_debug_fmt!(other, POINT, fmt ),
110/// );
111///
112/// const EXPECTED: &str = "\
113///     a: [Unit, Unit],\
114///     b: [0, 1],\
115///     c: Some(Point3 { x: 5, y: 8, z: 13 }),\
116///     d: NumWrapping(255),\
117///     e: false,\
118///     f: Point3 { x: 5, y: 8, z: 13 },\
119/// ";
120///
121/// assert_eq!(TEXT, EXPECTED);
122///
123/// # Ok::<(), const_format::Error>(())
124/// ```
125///
126#[cfg_attr(feature = "__docsrs", doc(cfg(feature = "fmt")))]
127#[macro_export]
128macro_rules! call_debug_fmt {
129    (array, $expr:expr, $formatter:expr $(,)* ) => {{
130        match (&$expr, $formatter.borrow_mutably()) {
131            (expr, formatter) => {
132                let mut n = 0;
133                let len = expr.len();
134                let mut f = formatter.debug_list();
135                while n != len {
136                    $crate::__call_debug_fmt_dispatch!(&expr[n], f.entry());
137                    n += 1;
138                }
139                $crate::try_!(f.finish());
140            }
141        }
142    }};
143    (slice, $expr:expr, $formatter:expr $(,)*) => {
144        $crate::call_debug_fmt!(array, $expr, $formatter)
145    };
146    (Option, $expr:expr, $formatter:expr $(,)*) => {{
147        match $formatter.borrow_mutably() {
148            formatter => $crate::try_!(match &$expr {
149                $crate::pmr::Some(x) => {
150                    let mut f = formatter.debug_tuple("Some");
151                    $crate::__call_debug_fmt_dispatch!(x, f.field());
152                    f.finish()
153                }
154                $crate::pmr::None => formatter.write_str("None"),
155            }),
156        }
157    }};
158    (newtype $name:ident, $expr:expr, $formatter:expr $(,)*) => {
159        match (&$expr, $formatter.borrow_mutably()) {
160            (newtype_, formatter) => {
161                let mut f = formatter.debug_tuple(stringify!($name));
162                $crate::__call_debug_fmt_dispatch!(&newtype_.0, f.field());
163                $crate::try_!(f.finish());
164            }
165        }
166    };
167    (std, $expr:expr, $formatter:expr $(,)*) => {
168        if let Err(e) = $crate::coerce_to_fmt!(&$expr).const_debug_fmt($formatter) {
169            return Err(e);
170        }
171    };
172    (other, $expr:expr, $formatter:expr $(,)*) => {
173        if let Err(e) = $expr.const_debug_fmt($formatter) {
174            return Err(e);
175        }
176    };
177}
178
179#[doc(hidden)]
180#[macro_export]
181macro_rules! __call_debug_fmt_dispatch {
182    ($e:expr, $f:expr) => {
183        if let Err(e) = $crate::coerce_to_fmt!(&$e).const_debug_fmt($f) {
184            return Err(e);
185        }
186    };
187}