tiny_str/
lib.rs

1/*  Copyright (C) 2025 Saúl Valdelvira
2 *
3 *  This program is free software: you can redistribute it and/or modify
4 *  it under the terms of the GNU General Public License as published by
5 *  the Free Software Foundation, version 3.
6 *
7 *  This program is distributed in the hope that it will be useful,
8 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
9 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 *  GNU General Public License for more details.
11 *
12 *  You should have received a copy of the GNU General Public License
13 *  along with this program.  If not, see <https://www.gnu.org/licenses/>. */
14
15use core::ops::{Deref, DerefMut};
16use core::str::Utf8Error;
17
18use tiny_vec::TinyVec;
19
20pub struct TinyString<const N: usize>(TinyVec<u8, N>);
21
22impl<const N: usize> TinyString<N> {
23    #[inline]
24    pub const fn new() -> Self {
25        Self(TinyVec::new())
26    }
27
28    pub fn with_capacity(cap: usize) -> Self {
29        Self(TinyVec::with_capacity(cap))
30
31    }
32
33    pub fn from_utf8(utf8: Vec<u8>) -> Result<Self,Utf8Error> {
34        str::from_utf8(&utf8)?;
35        Ok(Self(utf8.into()))
36    }
37
38    /// # Safety
39    /// The caller must ensure that the given buffer is valid utf8
40    #[inline(always)]
41    pub const unsafe fn from_utf8_unchecked(utf8: TinyVec<u8, N>) -> Self {
42        Self(utf8)
43    }
44
45    pub fn push(&mut self, c: char) {
46        let len = c.len_utf8();
47        let mut buf = [0_u8; 4];
48        c.encode_utf8(&mut buf);
49        self.0.push_slice(&buf[..len]);
50    }
51
52    pub fn push_str(&mut self, s: &str) {
53        self.0.push_slice(s.as_bytes());
54    }
55
56    pub fn shrink_to_fit(&mut self) {
57        self.0.shrink_to_fit();
58    }
59
60    pub const fn capacity(&self) -> usize { self.0.capacity() }
61}
62
63impl<const N: usize> Default for TinyString<N> {
64    fn default() -> Self {
65        Self::new()
66    }
67}
68
69impl<const N: usize> Deref for TinyString<N> {
70    type Target = str;
71
72    fn deref(&self) -> &Self::Target {
73        unsafe {
74            str::from_utf8_unchecked(&self.0)
75        }
76    }
77}
78
79impl<const N: usize> DerefMut for TinyString<N> {
80    fn deref_mut(&mut self) -> &mut Self::Target {
81        unsafe {
82            str::from_utf8_unchecked_mut(&mut self.0)
83        }
84    }
85}
86
87impl<S, const N: usize> From<S> for TinyString<N>
88where
89    S: AsRef<str>,
90{
91    fn from(value: S) -> Self {
92        let value = value.as_ref();
93        let mut s = Self::with_capacity(value.len());
94        s.push_str(value);
95        s
96    }
97}
98
99#[cfg(test)]
100mod test;