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}