to_arraystring/
lib.rs

1//! A no-alloc version of [`ToString`] implemented for bool/integer/float types formatting into an [`ArrayString`].
2//!
3//! ## Minimum Supported Rust Version
4//!
5//! This is currently 1.56, and is considered a breaking update to increase.
6//!
7//! - Using the `nonzero_impls` feature, this increases to 1.79.
8
9#![no_std]
10#![warn(clippy::pedantic)]
11#![allow(clippy::wildcard_imports)]
12
13#[cfg(any(doc, test))]
14extern crate alloc;
15
16#[cfg(any(doc, test))]
17use alloc::string::ToString;
18
19pub use arrayvec::ArrayString;
20
21use macros::{fmt_float_to_buf, fmt_int_to_buf, impl_float, impl_int};
22
23mod erased;
24mod macros;
25
26/// A no-alloc version of [`ToString`] implemented for bool/integer/float types formatting into an [`ArrayString`].
27pub trait ToArrayString: Copy {
28    /// The maximum length that Self can be formatted into. This is used for the capacity generic of [`ArrayString`].
29    ///
30    /// # Note for implementors
31    /// This must match the capacity generic used in [`ArrayString`], otherwise logic bugs and panics may occur.
32    const MAX_LENGTH: usize;
33
34    /// An associated type to turn [`ArrayString`]'s const generic into a type generic,
35    /// working around limitations of the current type system.
36    ///
37    /// This is always [`ArrayString`], but in generic code this only usable as `impl Deref<Target = str>`.
38    type ArrayString: erased::ArrayStringErased;
39
40    /// Returns the value's formatted representation in an appropriately sized [`ArrayString`].
41    fn to_arraystring(self) -> Self::ArrayString;
42}
43
44impl<const MAX_LENGTH: usize> ToArrayString for ArrayString<MAX_LENGTH> {
45    const MAX_LENGTH: usize = MAX_LENGTH;
46    type ArrayString = ArrayString<MAX_LENGTH>;
47
48    #[inline]
49    fn to_arraystring(self) -> Self::ArrayString {
50        self
51    }
52}
53
54impl ToArrayString for char {
55    const MAX_LENGTH: usize = 4;
56    type ArrayString = ArrayString<4>;
57
58    #[inline]
59    fn to_arraystring(self) -> Self::ArrayString {
60        let mut buffer = [0; 4];
61        let char_str = self.encode_utf8(&mut buffer);
62
63        ArrayString::from(char_str).unwrap()
64    }
65}
66
67impl ToArrayString for bool {
68    const MAX_LENGTH: usize = 5;
69    type ArrayString = ArrayString<5>;
70
71    #[inline]
72    fn to_arraystring(self) -> Self::ArrayString {
73        if self {
74            ArrayString::from("true").unwrap()
75        } else {
76            ArrayString::from("false").unwrap()
77        }
78    }
79}
80
81impl_float!(ToArrayString<16> for f32);
82impl_float!(ToArrayString<24> for f64);
83
84impl_int!(ToArrayString<3> for u8);
85impl_int!(ToArrayString<4> for i8);
86impl_int!(ToArrayString<5> for u16);
87impl_int!(ToArrayString<6> for i16);
88impl_int!(ToArrayString<10> for u32);
89impl_int!(ToArrayString<11> for i32);
90impl_int!(ToArrayString<20> for u64);
91impl_int!(ToArrayString<21> for i64);
92impl_int!(ToArrayString<39> for u128);
93impl_int!(ToArrayString<40> for i128);
94
95#[cfg(target_pointer_width = "16")]
96mod usize_impls {
97    use super::*;
98
99    impl_int!(ToArrayString<5> for usize);
100    impl_int!(ToArrayString<6> for isize);
101}
102
103#[cfg(target_pointer_width = "32")]
104mod usize_impls {
105    use super::*;
106
107    impl_int!(ToArrayString<10> for usize);
108    impl_int!(ToArrayString<11> for isize);
109}
110
111#[cfg(target_pointer_width = "64")]
112mod usize_impls {
113    use super::*;
114
115    impl_int!(ToArrayString<20> for usize);
116    impl_int!(ToArrayString<21> for isize);
117}
118
119#[cfg(test)]
120mod tests {
121    use super::*;
122
123    fn test_impl<T: ToArrayString + ToString>(min: T, max: T) {
124        assert_eq!(&*min.to_arraystring(), min.to_string());
125        assert_eq!(&*max.to_arraystring(), max.to_string());
126    }
127
128    crate::macros::generate_test!(u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize);
129}