Skip to content

Commit 1b18dd5

Browse files
ede1998Dirbaio
authored andcommitted
add format macro implementation
1 parent ee3a308 commit 1b18dd5

File tree

2 files changed

+72
-2
lines changed

2 files changed

+72
-2
lines changed

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ mod histbuf;
9797
mod indexmap;
9898
mod indexset;
9999
mod linear_map;
100-
mod string;
100+
pub mod string;
101101
mod vec;
102102

103103
#[cfg(feature = "serde")]

src/string.rs

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
//! A fixed capacity [`String`](https://doc.rust-lang.org/std/string/struct.String.html)
2+
13
use core::{
24
cmp::Ordering,
35
fmt,
4-
fmt::Write,
6+
fmt::{Arguments, Write},
57
hash, iter, ops,
68
str::{self, Utf8Error},
79
};
@@ -570,6 +572,53 @@ impl<const N: usize> Ord for String<N> {
570572
}
571573
}
572574

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+
573622
macro_rules! impl_try_from_num {
574623
($num:ty, $size:expr) => {
575624
impl<const N: usize> core::convert::TryFrom<$num> for String<N> {
@@ -831,4 +880,25 @@ mod tests {
831880
assert_eq!(s.remove(2), '\u{0301}');
832881
assert_eq!(s.as_str(), "hey");
833882
}
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+
}
834904
}

0 commit comments

Comments
 (0)