const_format/macros/
impl_fmt.rs

1/// For implementing debug or display formatting "manually".
2///
3/// # Generated code
4///
5/// This macro generates:
6///
7/// - An implementation of the [`FormatMarker`] trait for all the `impl`d types,
8///
9/// - All the listed impls, by repeating the methods (and other associated items)
10/// passed to this macro in each of the impls.
11///
12/// # Example
13///
14/// ### Generic type
15///
16/// This demonstrates how you can implement debug formatting for a generic struct.
17///
18/// ```rust
19///
20/// use const_format::{Error, Formatter, PWrapper, StrWriter};
21/// use const_format::{formatc, impl_fmt, try_};
22///
23/// use std::marker::PhantomData;
24///
25/// pub struct Tupled<T>(u32, T);
26///
27/// // Implements debug formatting for:
28/// // - Tupled<PhantomData<T>>
29/// // - Tupled<bool>
30/// // - Tupled<Option<bool>>
31/// // Repeating the `const_debug_fmt` function definition in each of those 3 impls.
32/// impl_fmt!{
33///     // The trailing comma is required
34///     impl[T,] Tupled<PhantomData<T>>
35///     where[ T: 'static ];
36///
37///     impl[] Tupled<bool>;
38///     impl Tupled<Option<bool>>;
39///     
40///     pub const fn const_debug_fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> {
41///         let mut fmt = fmt.debug_tuple("Tupled");
42///
43///         // PWrapper implements const_debug_fmt methods for many std types.
44///         //
45///         // You can use `call_debug_fmt` for formatting generic std types
46///         // if this doesn't work
47///         try_!(PWrapper(self.0).const_debug_fmt(fmt.field()));
48///         try_!(PWrapper(self.1).const_debug_fmt(fmt.field()));
49///
50///         fmt.finish()
51///     }
52/// }
53///
54/// const S_PHANTOM: &str = formatc!("{:?}", Tupled(3, PhantomData::<u32>));
55/// const S_BOOL: &str = formatc!("{:?}", Tupled(5, false));
56/// const S_OPTION: &str = formatc!("{:?}", Tupled(8, Some(true)));
57///
58/// assert_eq!(S_PHANTOM, "Tupled(3, PhantomData)");
59/// assert_eq!(S_BOOL, "Tupled(5, false)");
60/// assert_eq!(S_OPTION, "Tupled(8, Some(true))");
61///
62///
63/// ```
64///
65/// ### Enum
66///
67/// This demonstrates how you can implement debug formatting for an enum,
68/// using this macro purely for implementing the [`FormatMarker`] trait.
69///
70/// ```rust
71///
72/// use const_format::{Error, Formatter, PWrapper, StrWriter};
73/// use const_format::{formatc, impl_fmt, try_};
74///
75/// use std::cmp::Ordering;
76///
77/// pub enum Enum {
78///     Braced{ord: Ordering},
79///     Tupled(u32, u32),
80///     Unit,
81/// }
82///
83/// impl_fmt!{
84///     impl Enum;
85///     
86///     pub const fn const_debug_fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> {
87///         match self {
88///             Self::Braced{ord} => {
89///                 let mut fmt = fmt.debug_struct("Braced");
90///
91///                 // PWrapper implements const_debug_fmt methods for many std types.
92///                 //
93///                 // You can use `call_debug_fmt` for formatting generic std types
94///                 // if this doesn't work
95///                 try_!(PWrapper(*ord).const_debug_fmt(fmt.field("ord")));
96///
97///                 fmt.finish()
98///             }
99///             Self::Tupled(f0,f1) => {
100///                 let mut fmt = fmt.debug_tuple("Tupled");
101///
102///                 try_!(PWrapper(*f0).const_debug_fmt(fmt.field()));
103///                 try_!(PWrapper(*f1).const_debug_fmt(fmt.field()));
104///
105///                 fmt.finish()
106///             }
107///             Self::Unit => {
108///                 fmt.debug_tuple("Unit").finish()
109///             }
110///         }
111///     }
112/// }
113///
114/// const S_BRACED: &str = formatc!("{:?}", Enum::Braced{ord: Ordering::Greater});
115/// const S_TUPLED: &str = formatc!("{:?}", Enum::Tupled(5, 8));
116/// const S_UNIT: &str = formatc!("{:?}", Enum::Unit);
117///
118/// assert_eq!(S_BRACED, "Braced { ord: Greater }");
119/// assert_eq!(S_TUPLED, "Tupled(5, 8)");
120/// assert_eq!(S_UNIT, "Unit");
121///
122/// ```
123///
124/// [`FormatMarker`]: ./marker_traits/trait.FormatMarker.html
125///
126#[cfg_attr(feature = "__docsrs", doc(cfg(feature = "fmt")))]
127#[macro_export]
128macro_rules! impl_fmt {
129    (
130        is_std_type;
131        $($rem:tt)*
132    ) => (
133        $crate::__impl_fmt_recursive!{
134            impls[
135                is_std_type = true;
136            ]
137            tokens[$($rem)*]
138        }
139    );
140    (
141        $($rem:tt)*
142    ) => (
143        $crate::__impl_fmt_recursive!{
144            impls[
145                is_std_type = false;
146            ]
147            tokens[$($rem)*]
148        }
149    );
150}
151
152#[doc(hidden)]
153#[macro_export]
154macro_rules! __impl_fmt_recursive{
155    (
156        impls[$($impls:tt)*]
157
158        tokens[
159            $(#[$impl_attr:meta])*
160            impl[$($impl_:tt)*] $type:ty
161            $(where[ $($where:tt)* ])?;
162
163            $($rem:tt)*
164        ]
165    ) => (
166        $crate::__impl_fmt_recursive!{
167
168            impls[
169                $($impls)*
170                (
171                    $(#[$impl_attr])*
172                    #[allow(unused_mut)]
173                    impl[$($impl_)*] $type
174                    where[ $($($where)*)? ];
175                )
176            ]
177            tokens[
178                $($rem)*
179            ]
180        }
181    );
182    // The same as the above macro branch, but it doesn't require the `[]` in `impl[]`
183    (
184        impls[$($impls:tt)*]
185
186        tokens[
187            $(#[$impl_attr:meta])*
188            impl $type:ty
189            $(where[ $($where:tt)* ])?;
190
191            $($rem:tt)*
192        ]
193    ) => (
194        $crate::__impl_fmt_recursive!{
195
196            impls[
197                $($impls)*
198                (
199                    $(#[$impl_attr])*
200                    #[allow(unused_mut)]
201                    impl[] $type
202                    where[ $($($where)*)? ];
203                )
204            ]
205            tokens[
206                $($rem)*
207            ]
208        }
209    );
210    (
211        impls $impls:tt
212        tokens[
213            $($rem:tt)*
214        ]
215    ) => (
216        $crate::__impl_fmt_inner!{
217            @all_impls
218            impls $impls
219            ($($rem)*)
220        }
221    );
222}
223
224#[doc(hidden)]
225#[macro_export]
226macro_rules! __impl_fmt_inner {
227    (@all_impls
228        impls [
229            is_std_type = $is_std_type:ident;
230            $( $an_impl:tt )+
231        ]
232
233        $stuff:tt
234    )=>{
235        $(
236            $crate::__impl_fmt_inner!{
237                @impl_get_type_kind
238                is_std_type = $is_std_type;
239                $an_impl
240            }
241
242            $crate::__impl_fmt_inner!{
243                @an_impl
244                is_std_type = $is_std_type;
245                $an_impl
246                $stuff
247            }
248        )+
249    };
250    (@impl_get_type_kind
251        is_std_type = true;
252        (
253            $(#[$impl_attr:meta])*
254            impl[$($impl_:tt)*] $type:ty
255            where[ $($where:tt)* ];
256        )
257    )=>{
258        $(#[$impl_attr])*
259        impl<$($impl_)*> $crate::pmr::FormatMarker for $type
260        where
261            $($where)*
262        {
263            type Kind = $crate::pmr::IsStdKind;
264            type This = Self;
265        }
266
267        $(#[$impl_attr])*
268        impl<$($impl_)* __T> $crate::pmr::IsAFormatMarker<IsStdKind, $type, __T>
269        where
270            $($where)*
271        {
272            #[inline(always)]
273            pub const fn coerce(self, reference: &$type) -> PWrapper<$type> {
274                PWrapper(*reference)
275            }
276        }
277    };
278    (@impl_get_type_kind
279        is_std_type = false;
280        (
281            $(#[$impl_attr:meta])*
282            impl[$($impl_:tt)*] $type:ty
283            where[ $($where:tt)* ];
284        )
285    )=>{
286        $(#[$impl_attr])*
287        impl<$($impl_)*> $crate::pmr::FormatMarker for $type
288        where
289            $($where)*
290        {
291            type Kind = $crate::pmr::IsNotStdKind;
292            type This = Self;
293        }
294    };
295    (@an_impl
296        is_std_type = $is_std_type:ident;
297        (
298            $(#[$impl_attr:meta])*
299            impl[$($impl_:tt)*] $type:ty
300            where[ $($where:tt)* ];
301        )
302        (
303            $($everything:tt)*
304        )
305    )=>{
306        $(#[$impl_attr])*
307        impl<$($impl_)*> $crate::__impl_fmt_inner!(@self_ty $type, $is_std_type )
308        where
309            $($where)*
310        {
311            $($everything)*
312        }
313    };
314
315    (@self_ty $self:ty, /*is_std_type*/ true )=>{
316        $crate::pmr::PWrapper<$self>
317    };
318    (@self_ty $self:ty, /*is_std_type*/ false )=>{
319        $self
320    };
321
322}