|
| 1 | +//! A fixed capacity [`String`](https://doc.rust-lang.org/std/string/struct.String.html) |
| 2 | +
|
1 | 3 | use core::{
|
2 | 4 | cmp::Ordering,
|
3 | 5 | fmt,
|
4 |
| - fmt::Write, |
| 6 | + fmt::{Arguments, Write}, |
5 | 7 | hash, iter, ops,
|
6 | 8 | str::{self, Utf8Error},
|
7 | 9 | };
|
@@ -570,6 +572,53 @@ impl<const N: usize> Ord for String<N> {
|
570 | 572 | }
|
571 | 573 | }
|
572 | 574 |
|
| 575 | +/// Equivalent to [`format`](https://doc.rust-lang.org/std/fmt/fn.format.html). |
| 576 | +/// |
| 577 | +/// Please note that using [`format!`] might be preferable. |
| 578 | +/// |
| 579 | +/// [`format!`]: crate::format! |
| 580 | +pub fn format<const N: usize>(args: Arguments<'_>) -> String<N> { |
| 581 | + fn format_inner<const N: usize>(args: Arguments<'_>) -> String<N> { |
| 582 | + let mut output = String::new(); |
| 583 | + output |
| 584 | + .write_fmt(args) |
| 585 | + // cannot differentiate between these error cases because fmt::Error is empty |
| 586 | + .expect("capacity exceeded or a formatting trait implementation returned an error"); |
| 587 | + output |
| 588 | + } |
| 589 | + |
| 590 | + args.as_str() |
| 591 | + .map_or_else(|| format_inner(args), |s| s.try_into().expect("capacity exceeded")) |
| 592 | +} |
| 593 | + |
| 594 | +/// Macro that creates a fixed capacity [`String`]. Equivalent to [`format!`](https://doc.rust-lang.org/std/macro.format.html). |
| 595 | +/// |
| 596 | +/// The first argument is the capacity of the `String`. The following arguments work in the same way as the regular macro. |
| 597 | +/// |
| 598 | +/// # Panics |
| 599 | +/// |
| 600 | +/// `format!` panics if the formatted `String` would exceeded its capacity. |
| 601 | +/// `format!` also panics if a formatting trait implementation returns an error (same as the regular macro). |
| 602 | +/// |
| 603 | +/// # Examples |
| 604 | +/// |
| 605 | +/// ``` |
| 606 | +/// use heapless::format; |
| 607 | +/// |
| 608 | +/// format!(4, "test"); |
| 609 | +/// format!(15, "hello {}", "world!"); |
| 610 | +/// format!(20, "x = {}, y = {y}", 10, y = 30); |
| 611 | +/// let (x, y) = (1, 2); |
| 612 | +/// format!(12, "{x} + {y} = 3"); |
| 613 | +/// ``` |
| 614 | +#[macro_export] |
| 615 | +macro_rules! format { |
| 616 | + ($max:literal, $($arg:tt)*) => {{ |
| 617 | + let res = $crate::string::format::<$max>(core::format_args!($($arg)*)); |
| 618 | + res |
| 619 | + }} |
| 620 | +} |
| 621 | + |
573 | 622 | macro_rules! impl_try_from_num {
|
574 | 623 | ($num:ty, $size:expr) => {
|
575 | 624 | impl<const N: usize> core::convert::TryFrom<$num> for String<N> {
|
@@ -831,4 +880,25 @@ mod tests {
|
831 | 880 | assert_eq!(s.remove(2), '\u{0301}');
|
832 | 881 | assert_eq!(s.as_str(), "hey");
|
833 | 882 | }
|
| 883 | + |
| 884 | + #[test] |
| 885 | + fn format() { |
| 886 | + let number = 5; |
| 887 | + let float = 3.12; |
| 888 | + let formatted = format!(15, "{:0>3} plus {float}", number); |
| 889 | + assert_eq!(formatted, "005 plus 3.12") |
| 890 | + } |
| 891 | + |
| 892 | + #[test] |
| 893 | + #[should_panic] |
| 894 | + fn format_overflow() { |
| 895 | + let i = 1234567; |
| 896 | + format!(4, "13{}", i); |
| 897 | + } |
| 898 | + |
| 899 | + #[test] |
| 900 | + #[should_panic] |
| 901 | + fn format_plain_string_overflow() { |
| 902 | + format!(2, "123"); |
| 903 | + } |
834 | 904 | }
|
0 commit comments