const_format/
const_debug_derive.rs

1/// Derives const debug formatting for a type.
2///
3/// Derives the [`FormatMarker`] trait, and defines an `const_debug_fmt` inherent
4/// method to format a type at compile-time.
5/// 
6/// # Features 
7/// 
8/// This derive macro is only available with the "derive" feature,
9/// and Rust 1.83.0, because is uses mutable references in const.
10///
11/// # Limitations
12///
13/// Compile-time formatting currently imposes these limitations on users,
14/// this derive macro has some mitigations for some of them.
15///
16/// ### Generic impls
17///
18/// Because the formatting of custom types is implemented with duck typing,
19/// it's not possible to format generic types, instead you must do either of these:
20///
21/// - Provide all the implementations ahead of time, what the [`impls attribute`] is for.
22///
23/// - Provide a macro that formats the type.
24/// The `call_debug_fmt` macro is a version of this that formats generic std types,
25/// then it can be used to format fields of the type with the 
26/// [`#[cdeb(with_macro = "....")]`](#cdeb_with_macro) attribute.
27///
28/// These are the things that this macro does to mitigate the limitations:
29///
30/// - Allows users to provide a function/macro/wrapper to format a field.
31///
32/// - Automatically detect some builtin/standard library types that are generic.
33///
34/// - Allow users to ignore a field.
35///
36/// # Container Attributes 
37///
38/// These attributes go on the type itself, rather than the fields.
39///
40/// ### `#[cdeb(debug_print)]`
41///
42/// Panics with the output of the expanded derive.
43///
44/// ### `#[cdeb(impls(....))]`
45///
46/// Allows users to implement const debug formatting for multiple different
47/// concrete instances of the type.
48/// 
49/// When this attribute is used it disables the default implementation
50/// that uses the type parameters generically.
51///
52/// Example:
53/// 
54/// ```rust
55/// #[derive(const_format::ConstDebug)]
56/// #[cdeb(impls(
57///     "Foo<u8, u64>",
58///     "<T> Foo<u16, T>",
59///     "<T> Foo<u32, T> where T: 'static",
60/// ))]
61/// struct Foo<A, B>(A, *const B);
62/// ```
63///
64/// In this example, there's exactly three impls of 
65/// the `const_debug_fmt` method and [`FormatMarker`] trait.
66///
67/// ### `#[cdeb(crate = "foo::bar")]`
68///
69/// The path to the `const_format` crate, useful if you want to reexport the ConstDebug macro,
70/// or rename the `const_format` crate in the Cargo.toml .
71///
72/// Example of renaming the `const_format` crate in the Cargo.toml file:
73/// ```toml
74/// cfmt = {version = "0.*", package = "const_format"}
75/// ```
76///
77/// # Field attributes
78///
79/// ### `#[cdeb(ignore)]`
80///
81/// Ignores the field, pretending that it doesn't exist.
82///
83/// ### `#[cdeb(with = "module::function")]`
84///
85/// Uses the function at the passed-in path to format the field.
86///
87/// The function is expected to have this signature:
88/// ```ignored
89/// const fn(&FieldType, &mut const_format::Formatter<'_>) -> Result<(), const_format::Error>
90/// ```
91///
92/// <span id = "cdeb_with_macro"> </span>
93///
94/// ### `#[cdeb(with_macro = "module::the_macro")]`
95///
96/// Uses the macro at the passed-in path to format the field.
97///
98/// The macro is expected to be callable like a function with this signature: 
99/// ```ignored
100/// const fn(&FieldType, &mut const_format::Formatter<'_>) -> Result<(), const_format::Error>
101/// ```
102/// 
103/// ### `#[cdeb(with_wrapper = "module::Wrapper")]`
104/// 
105/// Uses the wrapper type to print the field.
106///
107/// The wrapper is expected to wrap a reference to the field type,
108/// to have an implementation of the [`FormatMarker`] trait,
109/// and have a method with this signature:
110/// ```ignored
111/// const fn const_debug_fmt(
112///     self,
113///     &mut const_format::Formatter<'_>,
114/// ) -> Result<(), const_format::Error>
115/// ```
116/// (`self` can be taken by reference or by value)
117///
118/// ### `#[cdeb(is_a(....))]`
119/// 
120/// Gives the derive macro a hint of what the type is.
121///
122/// For standard library types,
123/// this is necessary if you're using a type alias, since the derive macro detects 
124/// those types syntactically.
125///
126/// These are the valid ways to use this attribute:
127///
128/// - `#[cdeb(is_a(array))]`/`#[cdeb(is_a(slice))]`:
129/// Treats the field as being a slice/array,
130/// printing the elements of std or user-defined type with const debug formatting.
131///
132/// - `#[cdeb(is_a(Option))]`/`#[cdeb(is_a(option))]`:
133/// Treats the field as being an Option, 
134/// printing the contents of std or user-defined type with const debug formatting.
135///
136/// - `#[cdeb(is_a(newtype))]`:
137/// Treats the field as being being a single field tuple struct, 
138/// using the identifier of the field type as the name of the struct,
139/// then printing the single field of std or user-defined type with const debug formatting.
140///
141/// - `#[cdeb(is_a(non_std))]`/`#[cdeb(is_a(not_std))]`:
142/// This acts as an opt-out for the automatic detection of std types,
143/// most likely needed for types named `Option`.
144/// 
145/// # Examples
146/// 
147/// ### Basic
148/// 
149/// This example demonstrates using the derive without using any helper attributes.
150/// 
151/// ```rust
152/// 
153/// use const_format::{ConstDebug, formatc};
154/// 
155/// use std::cmp::Ordering;
156/// 
157/// const E_FOO: &str = formatc!("{:?}", Enum::Foo);
158/// const E_BAR: &str = formatc!("{:?}", Enum::Bar(10));
159/// const E_BAZ: &str = formatc!("{:?}", Enum::Baz{order: Ordering::Less});
160/// 
161/// const S_UNIT: &str = formatc!("{:?}", Unit);
162/// const S_BRACED: &str = formatc!("{:?}", Braced{is_true: false, optional: Some(Unit)});
163/// 
164/// assert_eq!(E_FOO, "Foo");
165/// assert_eq!(E_BAR, "Bar(10)");
166/// assert_eq!(E_BAZ, "Baz { order: Less }");
167/// 
168/// assert_eq!(S_UNIT, "Unit");
169/// assert_eq!(S_BRACED, "Braced { is_true: false, optional: Some(Unit) }");
170/// 
171/// 
172/// #[derive(ConstDebug)]
173/// enum Enum {
174///     Foo,
175///     Bar(u32),
176///     Baz{
177///         order: Ordering,
178///     },
179/// }
180/// 
181/// #[derive(ConstDebug)]
182/// struct Unit;
183/// 
184/// #[derive(ConstDebug)]
185/// struct Braced {
186///     is_true: bool,
187///     optional: Option<Unit>,
188/// }
189/// 
190/// ```
191/// 
192/// ### Generic type
193/// 
194/// This example demonstrates the `#[cdeb(impls)]` attribute,
195/// a workaround for deriving this trait for generic types,
196/// specifying a list of impls of types that unconditionally implement const debug formatting
197/// 
198/// ```rust
199/// 
200/// use const_format::{ConstDebug, formatc};
201/// 
202/// use std::marker::PhantomData;
203/// 
204/// 
205/// const S_U32: &str = formatc!("{:?}", Foo(10));
206///
207/// const S_STR: &str = formatc!("{:?}", Foo("hello"));
208/// 
209/// const S_PHANTOM: &str = formatc!("{:?}", Foo(PhantomData::<()>));
210/// 
211/// assert_eq!(S_U32, r#"Foo(10)"#);
212/// assert_eq!(S_STR, r#"Foo("hello")"#);
213/// assert_eq!(S_PHANTOM, r#"Foo(PhantomData)"#);
214/// 
215/// 
216/// // This type implements const debug formatting three times:
217/// // - `Foo<u32>`
218/// // - `Foo<&str>`
219/// // - `Foo<PhantomData<T>>`: with a generic `T`
220/// #[derive(ConstDebug)]
221/// #[cdeb(impls(
222///     "Foo<u32>",
223///     "Foo<&str>",
224///     "<T> Foo<PhantomData<T>>",
225/// ))]
226/// struct Foo<T>(T);
227/// 
228/// ```
229/// 
230/// ### `is_a` attributes
231/// 
232/// This example demonstrates when you would use the `is_a` attributes.
233/// 
234/// ```rust
235/// 
236/// use const_format::{ConstDebug, formatc};
237/// 
238/// use std::{
239///     cmp::Ordering,
240///     marker::PhantomData,
241///     num::Wrapping,
242/// };
243/// 
244/// const STRUCT: &Struct = &Struct {
245///     arr: [Ordering::Less, Ordering::Equal, Ordering::Greater, Ordering::Less],
246///     opt: Some(Unit),
247///     wrap: Wrapping(21),
248///     not_option: Option(PhantomData), // This is not the standard library `Option`
249/// };
250/// 
251/// const S_STRUCT: &str = formatc!("{STRUCT:#?}");
252/// 
253/// const EXPECTED: &str = "\
254/// Struct {
255///     arr: [
256///         Less,
257///         Equal,
258///         Greater,
259///         Less,
260///     ],
261///     opt: Some(
262///         Unit,
263///     ),
264///     wrap: Wrapping(
265///         21,
266///     ),
267///     not_option: Option(
268///         PhantomData,
269///     ),
270/// }";
271/// 
272/// fn main(){
273///     assert_eq!(S_STRUCT, EXPECTED);
274/// }
275/// 
276/// #[derive(ConstDebug)]
277/// struct Struct {
278///     // `Ordering` implements const debug formatting,
279///     // but `[Ordering; 4]` does not, so this attribute is required for the 
280///     // derive macro to generate code to format this array field.
281///     #[cdeb(is_a(array))]
282///     arr: Array,
283///     
284///     // Attribute is required to tell the derive macro that this is an
285///     // `Option` wrapping a user-defined type,
286///     // since `Option<Unit>` doesn't implement const debug formatting.
287///     #[cdeb(is_a(option))]
288///     opt: Opt,
289///     
290///     // Attribute is required because `Wrapping<usize>` is a newtype struct
291///     // that doesn't implement const debug formatting,
292///     // so the derive generates code to format it.
293///     #[cdeb(is_a(newtype))]
294///     wrap: Wrapping<usize>,
295///
296///     // Attribute is required for the field to be treated as a user-defined type,
297///     // otherwise it'd be assumed to be `Option` from the standard library.
298///     #[cdeb(is_a(not_std))]
299///     not_option: Option<u32>, 
300///     
301/// }
302/// 
303/// type Array = [Ordering; 4];
304/// 
305/// type Opt = std::option::Option<Unit>;
306/// 
307/// #[derive(ConstDebug)]
308/// struct Unit;
309/// 
310/// #[derive(ConstDebug)]
311/// struct Option<T>(PhantomData<T>);
312/// 
313/// ```
314///
315/// [`FormatMarker`]: ./marker_traits/trait.FormatMarker.html
316/// [`impls attribute`]: #cdebimpls
317///
318///
319///
320/// 
321/// ### Renamed import
322/// 
323/// This example demonstrates that you can use all the macros when the `const_format`
324/// crate is renamed.
325/// 
326/// ```rust
327/// # extern crate self as const_format;
328/// # extern crate const_format as cfmt;
329/// # fn main() {
330/// use cfmt::{
331///     for_examples::Unit,
332///     ConstDebug, formatc,
333/// };
334/// 
335/// #[derive(ConstDebug)]
336/// #[cdeb(crate = "cfmt")]
337/// struct Foo {
338///     bar: &'static str,
339///     baz: Unit
340/// }
341/// 
342/// const TEXT: &str = formatc!("{:?}", Foo{ bar: "hello", baz: Unit });
343/// 
344/// assert_eq!(TEXT, r#"Foo { bar: "hello", baz: Unit }"#);
345/// 
346/// # }
347/// ```
348///
349#[cfg_attr(feature = "__docsrs", doc(cfg(feature = "derive")))]
350#[cfg(feature = "derive")]
351pub use const_format_proc_macros::ConstDebug;