cds/arraystring/format.rs
1use crate::{arraystring::ArrayString, len::LengthType, mem::SpareMemoryPolicy};
2use core::fmt::{self, Arguments, Write};
3
4struct LossyWriter<'a, const C: usize, L: LengthType, SM: SpareMemoryPolicy<u8>>(
5 &'a mut ArrayString<C, L, SM>,
6);
7
8impl<'a, L, SM, const C: usize> Write for LossyWriter<'a, C, L, SM>
9where
10 L: LengthType,
11 SM: SpareMemoryPolicy<u8>,
12{
13 #[inline]
14 fn write_str(&mut self, s: &str) -> core::fmt::Result {
15 self.0.add_str(s);
16 Ok(())
17 }
18
19 #[inline]
20 fn write_char(&mut self, c: char) -> core::fmt::Result {
21 self.0.try_push(c).ok();
22 Ok(())
23 }
24}
25
26/// Formats an `ArrayString` possibly truncating the result.
27///
28/// This function allows formatting a string, similar to the standard [`format`] function,
29/// but with `ArrayString` as the resulting type. This allows formatting a string on stack,
30/// without memory allocation.
31///
32/// The [`Arguments`] instance can be created with the [`format_args!`] macro.
33///
34/// Note that, as `ArrayString` is a fixed-capacity non-growable string,
35/// the result may be truncated (on character boundary) to fit the given capacity.
36///
37/// # Examples
38///
39/// ```rust
40/// # use cds::{arraystring::{format_lossy, ArrayString}, len::U8};
41/// # use core::format_args;
42/// type S = ArrayString<16, U8>;
43/// let s: S = format_lossy(format_args!("Hello, world!"));
44/// assert_eq!(s, "Hello, world!");
45/// ```
46///
47/// The result may be silently truncated if there is no enough capacity. Use only when lossy
48/// formatting is appropriate, or when the capacity is ensured to be enough.
49/// ```rust
50/// # use cds::{arraystring::{format_lossy, ArrayString}, len::U8};
51/// # use core::format_args;
52/// type S = ArrayString<4, U8>; // <-- not enough capacity
53/// let s: S = format_lossy(format_args!("25€"));
54/// assert_eq!(s, "25"); // <-- the result is truncated on character boundary
55///
56/// let s: S = format_lossy(format_args!("a=2500"));
57/// assert_eq!(s, "a=25"); // <-- !! the result may be completely wrong in some use cases
58/// ```
59///
60/// [`format`]: std::fmt::format
61/// [`format_args!`]: core::format_args
62#[inline]
63pub fn format_lossy<const C: usize, L, SM>(args: Arguments<'_>) -> ArrayString<C, L, SM>
64where
65 L: LengthType,
66 SM: SpareMemoryPolicy<u8>,
67{
68 let mut s = ArrayString::<C, L, SM>::new();
69 let mut pw = LossyWriter(&mut s);
70 pw.write_fmt(args).ok();
71 s
72}
73
74/// Formats an `ArrayString`.
75///
76/// This function allows formatting an `ArrayString` similar to the standard [`format`] function.
77/// However, as `ArrayString` is a non-growable string, formatting it may fail due to lack of
78/// capacity. Thus, unlike the standard function, this function returns `Result<ArrayString>`
79/// instead. See [`format_lossy`] for a function that returns a plain `ArrayString`, possibly
80/// truncating the result when capacity is insufficient.
81///
82/// The [`Arguments`] instance can be created with the [`format_args!`] macro.
83/// See the [`aformat!`] macro for a convenience wrapper of this function.
84///
85/// # Examples
86///
87/// ```rust
88/// # use cds::{arraystring::{format, ArrayString}, len::U8};
89/// # use core::format_args;
90/// # fn foo() -> core::fmt::Result{
91/// type S = ArrayString<16, U8>;
92/// let s: S = format(format_args!("Hello, world!"))?;
93/// assert_eq!(s, "Hello, world!");
94/// # Ok(())
95/// # }
96/// # foo().unwrap();
97/// ```
98/// Note that the function may fail when there is no enough capacity in `ArrayString`.
99///
100/// ```rust
101/// # use cds::{arraystring::{format, ArrayString}, len::U8};
102/// # use core::{fmt, format_args};
103/// type S = ArrayString<5, U8>;
104/// let res: Result<S, fmt::Error> = format(format_args!("Hello, world!"));
105/// assert!(res.is_err());
106/// ```
107///
108/// [`format`]: std::fmt::format
109/// [`aformat!`]: crate::aformat
110#[inline]
111pub fn format<const C: usize, L, SM>(
112 args: Arguments<'_>,
113) -> Result<ArrayString<C, L, SM>, fmt::Error>
114where
115 L: LengthType,
116 SM: SpareMemoryPolicy<u8>,
117{
118 let mut s = ArrayString::<C, L, SM>::new();
119 s.write_fmt(args)?;
120 Ok(s)
121}
122
123#[cfg(test)]
124mod testing {
125 use crate as cds;
126
127 #[test]
128 fn test_format_lossy() {
129 let s = cds::lformat!(16, "Hello, world!");
130 assert_eq!(s, "Hello, world!");
131
132 let s = cds::lformat!(16, "{}", 'A');
133 assert_eq!(s, "A");
134
135 let s = cds::lformat!(5, "2€€");
136 assert_eq!(s, "2€");
137
138 let s = cds::lformat!(0, "cds");
139 assert_eq!(s, "");
140 }
141}