const_format/fmt.rs
1//! [`std::fmt`](https://doc.rust-lang.org/std/fmt/)-like
2//! api that can be used at compile-time.
3//!
4//! # Features
5//!
6//! This module requires the "fmt" feature to be exported, and Rust 1.83.0,
7//! because it uses `&mut` in `const fn`s.
8//!
9//! # Implementing the formatting methods
10//!
11//! Users of this library can implement debug and display formatting by
12//! defining `const_debug_fmt` and `const_display_fmt` inherent methods
13//! with the
14//! ```ignore
15//! // use const_format::{Formatter, Error};
16//! const fn const_debug_fmt(&self, &mut Formatter<'_>) -> Result<(), Error>
17//! const fn const_display_fmt(&self, &mut Formatter<'_>) -> Result<(), Error>
18//! ```
19//! signatures,
20//! and implementing the [`FormatMarker`] trait.
21//!
22//! # Limitations
23//!
24//! ### Generic impls
25//!
26//! Because the formatting of custom types is implemented with duck typing,
27//! it's not possible to format generic types, instead you must do either of these:
28//!
29//! - Provide all the implementations ahead of time, what [`impl_fmt`] is for.
30//!
31//! - Provide a macro that formats the type.
32//! The `call_debug_fmt` macro is a version of this that formats generic std types.
33//!
34//! <span id = "fmtsyntax"></span>
35//! # Formatting Syntax
36//!
37//! The formatting macros all share the formatting syntax,
38//! modeled after the syntax of the formatting macros of the standard library.
39//!
40//! ### Arguments
41//!
42//! Arguments in the format string can be named and positional in these ways:
43//!
44//! - Implicitly positional(eg: `formatc!("{}", 20u8)`):<br>
45//! Starts at the 0th positional argument and increments with every use.
46//!
47//! - Explicit positional(eg: `formatc!("{0}", 10u8)`).
48//!
49//! - Named, passed to the macro as named arguments (eg: `formatc!("{foo}", foo = 10u8)`).
50//!
51//! - Named, from constant (eg: `formatc!("{FOO}")`):
52//! Uses the `FOO` constant from the enclosing scope.
53//!
54//! - Named, from locals (eg: `writec!(writable, "{foo}")`):
55//! Uses the `foo` local variable from the enclosing scope,
56//! only usable with the [`writec`] macro.
57//!
58//! ### Formatters
59//!
60//! The format arguments can be formatted in these ways:
61//!
62//! - Debug formatting (eg: `formatc!("{:?}", 0u8)` ):<br>
63//! Similar to how Debug formatting in the standard library works,
64//! except that it does not escape unicode characters.
65//!
66//! - Display formatting (eg: `formatc!("{}", 0u8)`, `formatc!("{:}", 0u8)` )
67//!
68//! - Lowercase hexadecimal formatting (eg: `formatc!("{:x}", 0u8)`):<br>
69//! Writes numbers in lowercase hexadecimal.
70//! This can be combined with debug formatting with the `"{:x?}"` formatter.
71//!
72//! - Uppercase hexadecimal formatting (eg: `formatc!("{:X}", 0u8)`):<br>
73//! Writes numbers in uppercase hexadecimal.
74//! This can be combined with debug formatting with the `"{:X?}"` formatter.
75//!
76//! - Binary formatting (eg: `formatc!("{:b}", 0u8)`):<br>
77//! This can be combined with debug formatting with the `"{:b?}"` formatter.
78//!
79//! ### Alternate flag
80//!
81//! The alternate flag allows types to format themselves in an alternate way,
82//! written as "#" in a format string argument. eg:`"{:#}", "{:#?}"`.
83//!
84//! This is the built-in behavior for the alternate flag:
85//!
86//! - The Debug formater (eg: `formatc!("{:#?}", FOO)`):
87//! pretty print structs and enums.
88//!
89//! - The hexadecimal formater (eg: `formatc!("{:#x}", FOO)`):
90//! prefixes numbers with `0x`.
91//!
92//! - The binary formater (eg: `formatc!("{:#b}", FOO)`):
93//! prefixes numbers with `0b`.
94//!
95//! ### Additional specifiers
96//!
97//! `const_format` macros don't support width, fill, alignment, sign,
98//! or precision specifiers.
99//!
100//! <span id="custom-formatting-section"></span>
101//! ### Custom formatting
102//!
103//! Arguments can access a [`Formatter`] for custom formatting with an
104//! `|identifier|` before the expression.
105//!
106//! The expression will be evaluated every time it is used in the formatting string.
107//!
108//! The expression can evaluate to either a `()` or a `Result<(), const_format::Error>`.
109//!
110//! Note: this doesn't distinguish between debug and display formatting.
111//!
112//! [Link to full example of custom formatting](#custom-formatting-example)
113//!
114//! # Examples
115//!
116//! ### Derive
117//!
118//! This example demonstrates how you can derive [`ConstDebug`], and use it with the `fmt` API.
119//!
120//! It uses the "derive" feature
121//!
122#![cfg_attr(feature = "derive", doc = "```rust")]
123#![cfg_attr(not(feature = "derive"), doc = "```ignore")]
124//!
125//! use const_format::{Error, Formatter, FormattingFlags, PWrapper, StrWriter};
126//! use const_format::{ConstDebug, try_, unwrap, writec};
127//!
128//! use std::ops::Range;
129//!
130//! #[derive(ConstDebug)]
131//! pub struct Foo {
132//! range: Option<Range<usize>>,
133//! point: Point,
134//! }
135//!
136//! #[derive(ConstDebug)]
137//! pub struct Point {
138//! x: u32,
139//! y: u32,
140//! }
141//!
142//! const CAP: usize = 90;
143//! const fn build_string() -> StrWriter<[u8; CAP]> {
144//! let mut writer = StrWriter::new([0; CAP]);
145//!
146//! let foo = Foo {
147//! range: Some(0..10),
148//! point: Point{ x: 13, y: 21 },
149//! };
150//!
151//! unwrap!(writec!(writer, "{:X?}", foo));
152//!
153//! writer
154//! }
155//!
156//! const STRING: &str = {
157//! const STR: &StrWriter = &build_string();
158//! STR.as_str_alt()
159//! };
160//!
161//! // The formatter
162//! assert_eq!(
163//! STRING,
164//! "Foo { range: Some(0..A), point: Point { x: D, y: 15 } }",
165//! );
166//!
167//! ```
168//!
169//!
170//! ### No proc macros
171//!
172//! This example demonstrates how you can use the `fmt` api without using any proc macros.
173//!
174//! ```rust
175//!
176//! use const_format::{Error, Formatter, FormattingFlags, PWrapper, StrWriter};
177//! use const_format::{call_debug_fmt, coerce_to_fmt, impl_fmt, try_};
178//!
179//! use std::cmp::Ordering;
180//!
181//! pub struct Foo<T, U> {
182//! a: u32,
183//! b: u32,
184//! c: T,
185//! d: [Ordering; 3],
186//! ignored: U,
187//! }
188//!
189//! //
190//! impl_fmt!{
191//! // The type parameters of the impl must be written with trailing commas
192//! impl[U,] Foo<u32, U>;
193//! impl[U,] Foo<&str, U>;
194//!
195//! pub const fn const_debug_fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
196//! let mut f = f.debug_struct("Foo");
197//!
198//! // PWrapper is a wrapper for std types, which defines the formatter methods for them.
199//! try_!(PWrapper(self.a).const_debug_fmt(f.field("a")));
200//!
201//! try_!(PWrapper(self.b).const_debug_fmt(f.field("b")));
202//!
203//! // The `coerce_to_fmt` macro automatically wraps std types in `PWrapper`
204//! // and does nothing with non-std types.
205//! try_!(coerce_to_fmt!(self.c).const_debug_fmt(f.field("c")));
206//!
207//! // This macro allows debug formatting of some generic types which
208//! // wrap non-std types, including:
209//! // - arrays - slices - Option - newtype wrappers
210//! call_debug_fmt!(array, self.d, f.field("d"));
211//!
212//! f.finish()
213//! }
214//! }
215//!
216//! const CAP: usize = 128;
217//!
218//! const fn build_string() -> StrWriter<[u8; CAP]> {
219//! let flags = FormattingFlags::NEW.set_alternate(true);
220//! let mut writer = StrWriter::new([0; CAP]);
221//!
222//! const_format::unwrap!(
223//! Foo {
224//! a: 5,
225//! b: 8,
226//! c: 13,
227//! d: [Ordering::Less, Ordering::Equal, Ordering::Greater],
228//! ignored: (),
229//! }.const_debug_fmt(&mut Formatter::from_sw(&mut writer, flags))
230//! );
231//!
232//! writer
233//! }
234//!
235//! const STRING: &str = {
236//! const S: &StrWriter = &build_string();
237//! S.as_str_alt()
238//! };
239//!
240//! assert_eq!(
241//! STRING,
242//! "\
243//! Foo {
244//! a: 5,
245//! b: 8,
246//! c: 13,
247//! d: [
248//! Less,
249//! Equal,
250//! Greater,
251//! ],
252//! }\
253//! ",
254//! );
255//!
256//!
257//! ```
258//!
259//! <span id="custom-formatting-example"></span>
260//! ### Custom formatting
261//!
262//! This example demonstrates how you can do [custom formatting](#custom-formatting-section),
263//! by using a `Formatter` directly.
264//!
265//! ```rust
266//!
267//! use const_format::{call_debug_fmt, formatc};
268//!
269//! // Positional argument
270//! assert_eq!(formatc!("{}", |fmt| fmt.write_ascii_repeated(b'a', 4) ), "aaaa");
271//!
272//! // Named argument
273//! assert_eq!(formatc!("{foo}", foo = |fmt| fmt.write_ascii_repeated(b'0', 10) ), "0000000000");
274//!
275//! // Repeating a positional argument multiple times
276//! assert_eq!(formatc!("{0}{0}{0}", |fmt| fmt.write_str("hi") ), "hihihi");
277//!
278//! // Using debug formatting is no different to display formatting:
279//! assert_eq!(formatc!("{0:?}{0:?}{0:?}", |fmt| fmt.write_str("hi") ), "hihihi");
280//!
281//! // But binary/hex formatting, and the alternate flag, do have an effect:
282//! assert_eq!(
283//! formatc!(
284//! "{0}\n{0:x}\n{0:X}\n{0:b}\n{0:#x}\n{0:#X}\n{0:#b}",
285//! |fmt| call_debug_fmt!(array, [3u8, 13], fmt),
286//! ),
287//! "\
288//! [3, 13]\n\
289//! [3, d]\n\
290//! [3, D]\n\
291//! [11, 1101]\n\
292//! [\n 0x3,\n 0xd,\n]\n\
293//! [\n 0x3,\n 0xD,\n]\n\
294//! [\n 0b11,\n 0b1101,\n]\
295//! ",
296//! );
297//!
298//! ```
299//!
300//!
301//! [`writec`]: ../macro.writec.html
302//! [`Formatter`]: ./struct.Formatter.html
303//! [`FormatMarker`]: ../marker_traits/trait.FormatMarker.html
304//! [`ConstDebug`]: ../derive.ConstDebug.html
305//!
306//!
307//!
308//!
309//!
310
311mod error;
312mod formatter;
313mod std_type_impls;
314mod str_writer;
315mod str_writer_mut;
316
317pub use crate::formatting::{FormattingFlags, NumberFormatting};
318
319pub use self::{
320 error::{Error, Result, ToResult},
321 formatter::{ComputeStrLength, DebugList, DebugSet, DebugStruct, DebugTuple, Formatter},
322 str_writer::StrWriter,
323 str_writer_mut::{NoEncoding, StrWriterMut, Utf8Encoding},
324};