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}