const_format/macros/
fmt_macros.rs

1/// Concatenates constants of primitive types into a `&'static str`.
2///
3/// Each argument is stringified after evaluating it, so `concatcp!(1u8 + 3) == "4"`
4///
5/// [For **examples** look here](#examples)
6///
7/// `concatcp` stands for "concatenate constants (of) primitives"
8///
9/// # Limitations
10///
11/// This macro can only take constants of these types as inputs:
12///
13/// - `&str`
14///
15/// - `i*`/`u*` (all the primitive integer types).
16///
17/// - `char`
18///
19/// - `bool`
20///
21/// This macro also shares
22/// [the limitations described in here](./index.html#macro-limitations)
23/// as well.
24///
25/// # Examples
26///
27/// ### Literal arguments
28///
29///
30/// ```rust
31/// use const_format::concatcp;
32///
33/// const MSG: &str = concatcp!(2u8, "+", 2u8, '=', 2u8 + 2);
34///
35/// assert_eq!(MSG, "2+2=4");
36///
37/// ```
38///
39/// ### `const` arguments
40///
41/// ```rust
42/// use const_format::concatcp;
43///
44/// const PASSWORD: &str = "password";
45///
46/// const fn times() -> u64 { 10 }
47///
48/// const MSG: &str =
49///     concatcp!("The password is \"", PASSWORD, "\", you can only guess ", times(), " times.");
50///
51/// assert_eq!(MSG, r#"The password is "password", you can only guess 10 times."#);
52///
53/// ```
54///
55#[macro_export]
56macro_rules! concatcp {
57    ()=>{""};
58    ($($arg: expr),* $(,)?)=>(
59        $crate::__str_const! {{
60            use $crate::__cf_osRcTFl4A;
61            $crate::pmr::__concatcp_impl!{
62                $( ( $arg ), )*
63            }
64        }}
65    );
66}
67
68#[doc(hidden)]
69#[macro_export]
70macro_rules! __concatcp_inner {
71    ($variables:expr) => {{
72        #[doc(hidden)]
73        const ARR_LEN: usize = $crate::pmr::PArgument::calc_len($variables);
74
75        #[doc(hidden)]
76        const CONCAT_ARR: &$crate::pmr::LenAndArray<[u8; ARR_LEN]> =
77            &$crate::pmr::__priv_concatenate($variables);
78
79        #[doc(hidden)]
80        #[allow(clippy::transmute_ptr_to_ptr)]
81        const CONCAT_STR: &str = unsafe {
82            // This transmute truncates the length of the array to the amound of written bytes.
83            let slice =
84                $crate::pmr::transmute::<&[u8; ARR_LEN], &[u8; CONCAT_ARR.len]>(&CONCAT_ARR.array);
85
86            $crate::__priv_transmute_bytes_to_str!(slice)
87        };
88        CONCAT_STR
89    }};
90}
91
92////////////////////////////////////////////////////////////////////////////////
93
94/// Formats constants of primitive types into a `&'static str`
95///
96/// [For **examples** look here](#examples)
97///
98/// `formatcp` stands for "format constants (of) primitives"
99///
100/// # Syntax
101///
102/// This macro uses a limited version of the syntax from the standard library [`format`] macro,
103/// it can do these things:
104///
105/// - Take positional arguments: `formatcp!("{}{0}", "hello" )`
106///
107/// - Take named arguments: `formatcp!("{a}{a}", a = "hello" )`
108///
109/// - Use constants from scope as arguments: `formatcp!("{FOO}")`<br>
110/// equivalent to the [`format_args_implicits` RFC]
111///
112/// - Use Debug-like formatting (eg: `formatcp!("{:?}", "hello" )`:<br>
113/// Similar to how `Debug` formatting in the standard library works,
114/// except that it does not escape unicode characters.
115///
116/// - Use LowerHex formatting (eg: `formatcp!("{:x}", "hello" )`):<br>
117/// Formats numbers as lowercase hexadecimal.
118/// The alternate version (written as `"{:#x}"`) prefixes the number with `0x`
119///
120/// - Use UpperHex formatting (eg: `formatcp!("{:X}", "hello" )`):<br>
121/// Formats numbers as capitalized hexadecimal.
122/// The alternate version (written as `"{:#X}"`) prefixes the number with `0x`
123///
124/// - Use Binary formatting (eg: `formatcp!("{:b}", "hello" )`)<br>
125/// The alternate version (written as `"{:#b}"`) prefixes the number with `0b`
126///
127/// - Use Display formatting: `formatcp!("{}", "hello" )`
128///
129///
130/// # Limitations
131///
132/// This macro can only take constants of these types as inputs:
133///
134/// - `&str`
135///
136/// - `i*`/`u*` (all the primitive integer types).
137///
138/// - `char`
139///
140/// - `bool`
141///
142/// This macro also shares
143/// [the limitations described in here](./index.html#macro-limitations)
144/// as well.
145///
146/// # Formating behavior
147///
148/// ### Debug-like
149///
150/// The `{:?}` formatter formats things similarly to how Debug does it.
151///
152/// For `&'static str` it does these things:
153/// - Prepend and append the double quote character (`"`).
154/// - Escape the `'\t'`,`'\n'`,`'\r'`,`'\\'`, `'\''`, and`'\"'` characters.
155/// - Escape control characters with `\xYY`,
156/// where `YY` is the hexadecimal value of the control character.
157///
158/// Example:
159/// ```
160/// use const_format::formatcp;
161///
162/// assert_eq!(formatcp!("{:?}", r#" \ " ó "#), r#"" \\ \" ó ""#);
163/// ```
164///
165/// For `char` it does these things:
166/// - Prepend and append the single quote character (`'`).
167/// - Uses the same escapes as `&'static str`.
168///
169/// ### Display
170///
171/// The `{}`/`{:}` formatter produces the same output as in [`format`].
172///
173///
174/// # Examples
175///
176/// ### Implicit argument
177///
178/// ```rust
179/// use const_format::formatcp;
180///
181/// const NAME: &str = "John";
182///
183/// const MSG: &str = formatcp!("Hello {NAME}, your name is {} bytes long", NAME.len());
184///
185/// assert_eq!(MSG, "Hello John, your name is 4 bytes long");
186///
187/// ```
188///
189/// ### Repeating arguments
190///
191/// ```rust
192/// use const_format::formatcp;
193///
194/// const MSG: &str = formatcp!("{0}{S}{0}{S}{0}", "SPAM", S = "   ");
195///
196/// assert_eq!(MSG, "SPAM   SPAM   SPAM");
197///
198/// ```
199///
200/// ### Debug-like and Display formatting
201///
202/// ```rust
203/// use const_format::formatcp;
204///
205/// {
206///     const TEXT: &str = r#"hello " \ world"#;
207///     const MSG: &str = formatcp!("{TEXT}____{TEXT:?}");
208///    
209///     assert_eq!(MSG, r#"hello " \ world____"hello \" \\ world""#);
210/// }
211/// {
212///     const CHARS: &str = formatcp!("{0:?} - {0} - {1} - {1:?}", '"', '👀');
213///    
214///     assert_eq!(CHARS, r#"'\"' - " - 👀 - '👀'"#);
215/// }
216/// ```
217///
218/// ### Additional specifiers
219///
220/// `const_format` macros don't support width, fill, alignment, sign,
221/// or precision specifiers.
222///
223/// [`format`]: https://doc.rust-lang.org/std/macro.format.html
224///
225/// [`format_args_implicits` RFC]:
226/// https://github.com/rust-lang/rfcs/blob/master/text/2795-format-args-implicit-identifiers.md
227///
228///
229#[macro_export]
230macro_rules! formatcp {
231    ($format_string:expr $( $(, $expr:expr )+ )? $(,)? ) => (
232        $crate::__str_const! {{
233            use $crate::__cf_osRcTFl4A;
234
235            $crate::pmr::__formatcp_impl!(
236                ($format_string)
237                $(, $($expr,)+)?
238            )
239        }}
240    );
241}
242
243////////////////////////////////////////////////////////////////////////////////
244
245/// Concatenates constants of standard library and/or user-defined types into a `&'static str`.
246///
247/// User defined types must implement the [`FormatMarker`] trait and
248/// and have a `const_display_fmt` method (as described in the trait) to be concatenated.
249///
250/// # Stable equivalent
251///
252/// For an equivalent macro which can be used in stable Rust,
253/// but can only concatenate primitive types,
254/// you can use the [`concatcp`](crate::concatcp) macro.
255///
256/// # Limitations
257///
258/// This macro has [the limitations described in here](./index.html#macro-limitations).
259///
260/// # Examples
261///
262/// ### With standard library types
263///
264/// ```rust
265///
266/// use const_format::concatc;
267///
268/// assert_eq!(concatc!("There is ", 99u8, " monkeys!"), "There is 99 monkeys!");
269///
270/// ```
271///
272/// ### With user-defined types
273///
274/// ```rust
275///
276/// use const_format::{Formatter, Sliced, concatc, impl_fmt};
277///
278/// const STRING: &str = "foo bar baz";
279///
280/// assert_eq!(concatc!(Sliced(STRING, 4..7), ' ', Foo), "bar table");
281///
282/// struct Foo;
283///
284/// impl_fmt!{
285///     impl Foo;
286///     const fn const_display_fmt(&self, fmt: &mut Formatter<'_>) -> const_format::Result {
287///         fmt.write_str("table")
288///     }
289/// }
290/// ```
291///
292///
293/// [`FormatMarker`]: ./marker_traits/trait.FormatMarker.html
294///
295#[cfg_attr(feature = "__docsrs", doc(cfg(feature = "fmt")))]
296#[cfg(feature = "fmt")]
297#[macro_export]
298macro_rules! concatc {
299    ()=>{""};
300    ($($anything:tt)*)=>(
301        $crate::__str_const! {{
302            use $crate::__cf_osRcTFl4A;
303
304            $crate::__concatc_expr!(($($anything)*) ($($anything)*))
305            as &'static $crate::pmr::str
306        }}
307    )
308}
309
310#[doc(hidden)]
311#[cfg(feature = "fmt")]
312#[macro_export]
313macro_rules! __concatc_expr {
314    (($($arg: expr),* $(,)?) ($($span:tt)*) )=>({
315        const fn fmt_NHPMWYD3NJA(
316            mut fmt: $crate::fmt::Formatter<'_>,
317        ) -> $crate::Result {
318            use $crate::coerce_to_fmt as __cf_coerce_to_fmt;
319            use $crate::pmr::respan_to as __cf_respan_to;
320            use $crate::try_ as __cf_try;
321
322            $({
323                let __cf_respan_to!(($arg) fmt) = &mut fmt;
324                __cf_respan_to!(($arg)
325                    __cf_try!(__cf_coerce_to_fmt!($arg).const_display_fmt(fmt))
326                );
327            })*
328
329            $crate::pmr::Ok(())
330        }
331
332        $crate::__concatc_inner!(fmt_NHPMWYD3NJA, true, $($span)*)
333    })
334}
335
336#[doc(hidden)]
337#[macro_export]
338macro_rules! __concatc_inner {
339    ($debug_fmt_fn:ident, $cond:expr, $($span:tt)*) => {{
340        const fn len_nhpmwyd3nj() -> usize {
341            if $cond {
342                let mut strlen = __cf_osRcTFl4A::pmr::ComputeStrLength::new();
343                let fmt = strlen.make_formatter(__cf_osRcTFl4A::FormattingFlags::NEW);
344                match $debug_fmt_fn(fmt) {
345                    __cf_osRcTFl4A::pmr::Ok(()) => strlen.len(),
346                    __cf_osRcTFl4A::pmr::Err(_) => 0,
347                }
348            } else {
349                0
350            }
351        }
352
353        const LEN_NHPMWYD3NJA: usize = len_nhpmwyd3nj();
354
355        const fn str_writer_nhpmwyd3nja(
356        ) -> __cf_osRcTFl4A::msg::ErrorTupleAndStrWriter<[u8; LEN_NHPMWYD3NJA]> {
357            let mut writer = __cf_osRcTFl4A::pmr::StrWriter::new([0; LEN_NHPMWYD3NJA]);
358            let error = if $cond {
359                $debug_fmt_fn(__cf_osRcTFl4A::pmr::Formatter::from_sw(
360                    &mut writer,
361                    __cf_osRcTFl4A::FormattingFlags::NEW,
362                ))
363            } else {
364                __cf_osRcTFl4A::pmr::Ok(())
365            };
366
367            __cf_osRcTFl4A::msg::ErrorTupleAndStrWriter {
368                error: __cf_osRcTFl4A::msg::ErrorTuple::new(error, &writer),
369                writer,
370            }
371        }
372
373        const STR_WRITER_NHPMWYD3NJA: &__cf_osRcTFl4A::msg::ErrorTupleAndStrWriter<
374            [u8; LEN_NHPMWYD3NJA],
375        > = &str_writer_nhpmwyd3nja();
376
377        const _: __cf_osRcTFl4A::msg::Ok = <<__cf_osRcTFl4A::msg::ErrorPicker<
378            [(); STR_WRITER_NHPMWYD3NJA.error.error_variant],
379            [(); STR_WRITER_NHPMWYD3NJA.error.capacity],
380        > as __cf_osRcTFl4A::msg::ErrorAsType>::Type>::NEW;
381
382        const STR_NHPMWYD3NJA: &str = STR_WRITER_NHPMWYD3NJA.writer.unsize().as_str_alt();
383
384        STR_NHPMWYD3NJA
385    }};
386}
387
388////////////////////////////////////////////////////////////////////////////////
389
390/// Formats constants of standard library and/or user-defined types into a `&'static str`.
391///
392/// User-defined types must implement the [`FormatMarker`] trait
393/// (as described in the docs for that trait) to be usable with this macro.
394///
395/// # Stable equivalent
396///
397/// For an equivalent macro which can be used in stable Rust,
398/// but can only format primitive types,
399/// you can use the [`formatcp`](crate::formatcp) macro.
400///
401/// # Syntax
402///
403/// This macro uses the syntax described in
404/// [the const_format::fmt module](./fmt/index.html#fmtsyntax)
405///
406/// # Limitations
407///
408/// This macro has [the limitations described in here](./index.html#macro-limitations).
409///
410/// # Example
411///
412/// ```rust
413///
414/// use const_format::for_examples::Point3;
415/// use const_format::formatc;
416///
417/// // Formatting a non-std struct.
418/// const POINT: &str = formatc!("{:?}", Point3{x: 8, y: 13, z: 21});
419///
420/// // Formatting a number as decimal, hexadecimal, and binary
421/// const NUMBER: &str = formatc!("{0},{0:x},{0:b}", 10u8);
422///
423/// // Formatting the numbers in an array as decimal, hexadecimal, and binary.
424/// // You can use the name of cnstants from scope, as well as named arguments.
425/// const ARR: &[u32] = &[9, 25];
426/// const ARRAY: &str = formatc!("{ARR:?},{ARR:X},{ARR:b}");
427///
428///
429/// assert_eq!(POINT, "Point3 { x: 8, y: 13, z: 21 }");
430/// assert_eq!(NUMBER, "10,a,1010");
431/// assert_eq!(ARRAY, "[9, 25],[9, 19],[1001, 11001]");
432///
433/// ```
434///
435/// ### Custom formatting.
436///
437/// This example demonstrates how you can access the [`Formatter`] in arguments
438/// to do custom formatting.
439///
440/// For more details on this you can look
441/// [in the fmt module](./fmt/index.html#custom-formatting-section).
442///
443/// ```rust
444///
445/// use const_format::for_examples::Point3;
446/// use const_format::{formatc, try_};
447///
448/// const P: Point3 = Point3{x: 5, y: 13, z: 21};
449///
450/// const STR: &str = formatc!("{0};{0:#X};{0:#b}", |fmt|{
451///     try_!(fmt.write_u32_debug(P.x));
452///     try_!(fmt.write_str(" "));
453///     try_!(fmt.write_u32_debug(P.y));
454///     try_!(fmt.write_char('.'));
455/// });
456///
457/// assert_eq!(STR, "5 13.;0x5 0xD.;0b101 0b1101.");
458///
459/// ```
460/// [`Formatter`]: crate::fmt::Formatter
461/// [`FormatMarker`]: crate::marker_traits::FormatMarker
462///
463///
464#[macro_export]
465#[cfg_attr(feature = "__docsrs", doc(cfg(feature = "fmt")))]
466#[cfg(feature = "fmt")]
467macro_rules! formatc {
468    ($format_string:expr $( $(, $expr:expr )+ )? $(,)? ) => (
469        $crate::__str_const! {{
470            use $crate::__cf_osRcTFl4A;
471
472            $crate::pmr::__formatc_impl!{
473                ($format_string)
474                $(, $($expr,)+)?
475            }
476        }}
477    );
478}
479
480/// Writes some formatted standard library and/or user-defined types into a buffer.
481///
482/// This macro evaluates to a `Result<(), const_format::Error>` which must be handled.
483///
484/// # Syntax
485///
486/// The syntax is similar to that of other formatting macros in this crate:
487///
488/// ```ignore
489/// ẁritec!(
490///     writer_expression,
491///     "formatting literal",
492///     positional_arg_0_expression,
493///     positional_arg_1_expression,
494///     named_arg_foo = expression,
495///     named_arg_bar = expression,
496/// )
497/// ```
498///
499/// The syntax is otherwise the same as described in
500/// [the `const_format::fmt` module](./fmt/index.html#fmtsyntax).
501///
502/// # Writers
503///
504/// The first argument must be a type that implements the [`WriteMarker`] trait,
505/// and has these inherent methods:
506/// ```ignore
507/// const fn borrow_mutably(&mut self) -> &mut Self
508/// const fn make_formatter(&mut self, flags: FormattingFlags) -> Formatter<'_>
509/// ```
510///
511/// [This example](#custom-writable-example) below shows how to use this macro
512/// with a custom type.
513///
514/// # Limitations
515///
516/// Integer arguments must have a type inferrable from context,
517/// [more details in the Integer arguments section](./index.html#integer-args).
518///
519/// # Examples
520///
521/// ### Ẁriting a Display impl.
522///
523/// ```
524///
525/// use const_format::{Error, Formatter, StrWriter};
526/// use const_format::{impl_fmt, try_, writec};
527///
528/// pub struct Foo(u32, &'static str);
529///
530/// impl_fmt!{
531///     impl Foo;
532///     pub const fn const_display_fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
533///         try_!(writec!(f, "{},", self.0));
534///         try_!(writec!(f, "{:?};", self.1));
535///         Ok(())
536///     }
537/// }
538///
539/// // Coerces the `&mut StrWriter<[u8; 128]>` to `&mut StrWriter<[u8]>`.
540/// // This is necessary because the `as_str` method is defined for `StrWriter<[u8]>`.
541/// let writer: &mut StrWriter = &mut StrWriter::new([0; 128]);
542/// writec!(writer, "{}", Foo(100, "bar"))?;
543///
544/// assert_eq!(writer.as_str(), r#"100,"bar";"#);
545///
546/// # Ok::<(), const_format::Error>(())
547/// ```
548///
549/// <span id="custom-writable-example"></span>
550/// ### Writing to a custom type
551///
552/// This example demonstrates how you can use the `ẁritec` macro with a custom type,
553/// in this case it's a buffer that is cleared every time it's written.
554///
555/// ```rust
556///
557/// use const_format::marker_traits::{IsNotAStrWriter, WriteMarker};
558/// use const_format::{Formatter, FormattingFlags};
559/// use const_format::writec;
560///
561/// const ARRAY_CAP: usize = 20;
562/// struct Array {
563///     len: usize,
564///     arr: [u8; ARRAY_CAP],
565/// }
566///
567/// impl WriteMarker for Array{
568///     type Kind = IsNotAStrWriter;
569///     type This = Self;
570/// }
571///
572/// impl Array {
573///     // Gets the part of the array that has been written to.
574///     pub const fn as_bytes(&self) -> &[u8] {
575///         const_format::utils::slice_up_to_len_alt(&self.arr, self.len)
576///     }
577///
578///     pub const fn borrow_mutably(&mut self) -> &mut Self {
579///         self
580///     }
581///
582///     pub const fn make_formatter(&mut self, flags: FormattingFlags) -> Formatter<'_> {
583///         Formatter::from_custom_cleared(&mut self.arr, &mut self.len, flags)
584///     }
585/// }
586///
587///
588/// let mut buffer = Array{ arr: [0; ARRAY_CAP], len: 0 };
589///
590/// writec!(buffer, "{:?}", [3u8, 5, 8, 13, 21])?;
591/// assert_eq!(buffer.as_bytes(), b"[3, 5, 8, 13, 21]");
592///
593/// writec!(buffer, "{}{}", "Hello, world!", 100u16)?;
594/// assert_eq!(buffer.as_bytes(), b"Hello, world!100");
595///
596/// # Ok::<(), const_format::Error>(())
597/// ```
598///
599/// ### Custom formatting.
600///
601/// This example demonstrates how you can access the [`Formatter`] in arguments
602/// to do custom formatting.
603///
604/// Note that `return` inside arguments returns from the function around the `writec`.
605///
606/// For more details on this you can look
607/// [in the fmt module](./fmt/index.html#custom-formatting-section).
608///
609/// ```rust
610///
611/// use const_format::for_examples::Point3;
612/// use const_format::{StrWriter, call_debug_fmt, try_, writec};
613///
614/// const P: Point3 = Point3{x: 5, y: 13, z: 21};
615///
616/// let writer: &mut StrWriter = &mut StrWriter::new([0; 128]);
617///
618/// writec!(
619///     writer,
620///     "The options are: {}, and {}",
621///     |fmt| call_debug_fmt!(Option, Some(P), fmt),
622///     |fmt| call_debug_fmt!(Option, None::<Point3>, fmt),
623/// )?;
624///
625/// assert_eq!(writer.as_str(), "The options are: Some(Point3 { x: 5, y: 13, z: 21 }), and None");
626///
627/// # Ok::<(), const_format::Error>(())
628/// ```
629///
630/// ### Locals in the format string
631///
632/// This example demonstrates how you can format local variables,
633/// by using their identifiers in the format string.
634///
635/// ```rust
636///
637/// use const_format::{Formatter, FormattingFlags, StrWriter, try_, writec};
638///
639/// const fn writeit(mut fmt: Formatter<'_>, foo: u32, bar: &str) -> const_format::Result {
640///     try_!(writec!(fmt, "{foo},{foo:?},{foo:#x},{foo:#b};"));
641///     try_!(writec!(fmt, "{bar},{bar:?}"));
642///     Ok(())
643/// }
644///
645/// let writer: &mut StrWriter = &mut StrWriter::new([0; 128]);
646///
647/// writeit(writer.make_formatter(FormattingFlags::NEW), 100, "hello")?;
648///
649/// assert_eq!(writer.as_str(), r#"100,100,0x64,0b1100100;hello,"hello""#);
650///
651/// # Ok::<(), const_format::Error>(())
652/// ```
653///
654/// [`Formatter`]: ./fmt/struct.Formatter.html
655/// [`WriteMarker`]: ./marker_traits/trait.WriteMarker.html
656///
657///
658///
659///
660#[macro_export]
661#[cfg_attr(feature = "__docsrs", doc(cfg(feature = "fmt")))]
662#[cfg(feature = "fmt")]
663macro_rules! writec {
664    ( $writer:expr, $format_string:expr $( $(, $expr:expr )+ )? $(,)? ) => ({
665        use $crate::__cf_osRcTFl4A;
666
667        $crate::pmr::__writec_impl!{
668            ($writer)
669            ($format_string)
670            $(, $($expr,)+)?
671        }
672    });
673}