|
1 |
| -use core::{cmp::Ordering, fmt, fmt::Write, hash, iter, ops, str}; |
| 1 | +//! A fixed capacity [`String`](https://doc.rust-lang.org/std/string/struct.String.html) |
| 2 | +
|
| 3 | +use core::{cmp::Ordering, fmt, fmt::{Arguments, Write}, hash, iter, ops, str}; |
2 | 4 |
|
3 | 5 | use crate::Vec;
|
4 | 6 |
|
@@ -290,7 +292,7 @@ impl<const N: usize> Default for String<N> {
|
290 | 292 | impl<'a, const N: usize> From<&'a str> for String<N> {
|
291 | 293 | fn from(s: &'a str) -> Self {
|
292 | 294 | let mut new = String::new();
|
293 |
| - new.push_str(s).unwrap(); |
| 295 | + new.push_str(s).expect("capacity exceeded"); |
294 | 296 | new
|
295 | 297 | }
|
296 | 298 | }
|
@@ -474,6 +476,53 @@ impl<const N: usize> Ord for String<N> {
|
474 | 476 | }
|
475 | 477 | }
|
476 | 478 |
|
| 479 | +/// Equivalent to [`format`](https://doc.rust-lang.org/std/fmt/fn.format.html). |
| 480 | +/// |
| 481 | +/// Please note that using [`format!`] might be preferable. |
| 482 | +/// |
| 483 | +/// [`format!`]: crate::format! |
| 484 | +pub fn format<const N: usize>(args: Arguments<'_>) -> String<N> { |
| 485 | + fn format_inner<const N: usize>(args: Arguments<'_>) -> String<N> { |
| 486 | + let mut output = String::new(); |
| 487 | + output |
| 488 | + .write_fmt(args) |
| 489 | + // cannot differentiate between these error cases because fmt::Error is empty |
| 490 | + .expect("capacity exceeded or a formatting trait implementation returned an error"); |
| 491 | + output |
| 492 | + } |
| 493 | + |
| 494 | + args.as_str() |
| 495 | + .map_or_else(|| format_inner(args), String::from) |
| 496 | +} |
| 497 | + |
| 498 | +/// Macro that creates a fixed capacity [`String`]. Equivalent to [`format!`](https://doc.rust-lang.org/std/macro.format.html). |
| 499 | +/// |
| 500 | +/// The first argument is the capacity of the `String`. The following arguments work in the same way as the regular macro. |
| 501 | +/// |
| 502 | +/// # Panics |
| 503 | +/// |
| 504 | +/// `format!` panics if the formatted `String` would exceeded its capacity. |
| 505 | +/// `format!` also panics if a formatting trait implementation returns an error (same as the regular macro). |
| 506 | +/// |
| 507 | +/// # Examples |
| 508 | +/// |
| 509 | +/// ``` |
| 510 | +/// use heapless::format; |
| 511 | +/// |
| 512 | +/// format!(4, "test"); |
| 513 | +/// format!(15, "hello {}", "world!"); |
| 514 | +/// format!(20, "x = {}, y = {y}", 10, y = 30); |
| 515 | +/// let (x, y) = (1, 2); |
| 516 | +/// format!(12, "{x} + {y} = 3"); |
| 517 | +/// ``` |
| 518 | +#[macro_export] |
| 519 | +macro_rules! format { |
| 520 | + ($max:literal, $($arg:tt)*) => {{ |
| 521 | + let res = $crate::string::format::<$max>(core::format_args!($($arg)*)); |
| 522 | + res |
| 523 | + }} |
| 524 | +} |
| 525 | + |
477 | 526 | macro_rules! impl_from_num {
|
478 | 527 | ($num:ty, $size:expr) => {
|
479 | 528 | impl<const N: usize> From<$num> for String<N> {
|
@@ -708,4 +757,25 @@ mod tests {
|
708 | 757 | assert_eq!(0, s.len());
|
709 | 758 | assert_eq!(8, s.capacity());
|
710 | 759 | }
|
| 760 | + |
| 761 | + #[test] |
| 762 | + fn format() { |
| 763 | + let number = 5; |
| 764 | + let float = 3.12; |
| 765 | + let formatted = format!(15, "{:0>3} plus {float}", number); |
| 766 | + assert_eq!(formatted, "005 plus 3.12") |
| 767 | + } |
| 768 | + |
| 769 | + #[test] |
| 770 | + #[should_panic] |
| 771 | + fn format_overflow() { |
| 772 | + let i = 1234567; |
| 773 | + format!(4, "13{}", i); |
| 774 | + } |
| 775 | + |
| 776 | + #[test] |
| 777 | + #[should_panic] |
| 778 | + fn format_plain_string_overflow() { |
| 779 | + format!(2, "123"); |
| 780 | + } |
711 | 781 | }
|
0 commit comments