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