aformat/
lib.rs

1//! A no-std and no-alloc version of [`format!`] using [`ToArrayString`].
2//!
3//! ## Example
4//!
5//! ```
6//! use aformat::{astr, aformat, CapStr};
7//!
8//! pub fn say_hello(name: &str, age: u8) {
9//!     let name = CapStr::<256>(name);
10//!
11//!     let formatted = aformat!("Hello {name}, you are {age} years old!");
12//!     println!("{}", formatted.as_str());
13//! }
14//!
15//! say_hello("Walter White", 50);
16//! ```
17//!
18//! ## Minimum Supported Rust Version
19//!
20//! This is currently `1.79`, and is considered a breaking change to increase.
21#![cfg_attr(not(doc), no_std)]
22#![warn(clippy::pedantic, rust_2018_idioms)]
23
24#[doc(no_inline)]
25pub use to_arraystring::{ArrayString, ToArrayString};
26
27pub use aformat_macros::{aformat, aformat_into};
28
29#[doc(hidden)]
30pub mod __internal;
31
32/// A simple and easy way to make a perfectly fitting [`ArrayString`] from a literal.
33///
34/// ## Expansion
35/// ```rust
36/// use aformat::astr;
37///
38/// let my_string = astr!("Hello World");
39/// ```
40/// expands to
41/// ```rust
42/// let my_string = {
43///     const STR_LEN: usize = str::len("Hello World");
44///     aformat::ArrayString::<STR_LEN>::from("Hello World").unwrap();
45/// };
46/// ```
47#[macro_export]
48macro_rules! astr {
49    ($val:expr) => {{
50        const STR_LEN: usize = ::core::primitive::str::len($val);
51        ::aformat::ArrayString::<STR_LEN>::from($val).unwrap()
52    }};
53}
54
55/// A transparent wrapper around `&str` to truncate the byte length to a compile time constant.
56///
57/// This implements [`ToArrayString`], allowing you to use it in [`aformat!`].
58///
59/// If you simply want to pass a string literal into [`aformat!`], use [`astr!`].
60#[derive(Clone, Copy)]
61pub struct CapStr<'a, const MAX_LENGTH: usize>(pub &'a str);
62
63impl<const MAX_LENGTH: usize> core::ops::Deref for CapStr<'_, MAX_LENGTH> {
64    type Target = str;
65
66    fn deref(&self) -> &Self::Target {
67        for i in (0..MAX_LENGTH).rev() {
68            if let Some(valid_slice) = self.0.get(..i) {
69                return valid_slice;
70            }
71        }
72
73        ""
74    }
75}
76
77impl<const MAX_LENGTH: usize> ToArrayString for CapStr<'_, MAX_LENGTH> {
78    const MAX_LENGTH: usize = MAX_LENGTH;
79    type ArrayString = ArrayString<MAX_LENGTH>;
80
81    fn to_arraystring(self) -> Self::ArrayString {
82        ArrayString::from(&self).unwrap()
83    }
84}