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}