starina_inlinedvec/
inlined_string.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
use core::fmt;

use crate::InlinedVec;
use crate::TooManyItemsError;

/// An inlined string. Unline `String`, this type is allocated on the stack
/// or inlined in a struct instead of the heap.
///
/// The internal buffer is a `InlinedVec<u8, CAP>`, where `CAP` is the capacity
/// of the string. It's guaranteed to be a valid UTF-8 string.
pub struct InlinedString<const CAP: usize>(InlinedVec<u8, CAP>);

impl<const CAP: usize> Default for InlinedString<CAP> {
    fn default() -> Self {
        Self::new()
    }
}

impl<const CAP: usize> InlinedString<CAP> {
    pub const fn new() -> Self {
        Self(InlinedVec::new())
    }

    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    pub fn len(&self) -> usize {
        self.0.len()
    }

    pub fn as_str(&self) -> &str {
        // SAFETY: We guarantee that the string is always a valid UTF-8 string.
        unsafe { core::str::from_utf8_unchecked(self.0.as_slice()) }
    }

    pub fn try_push_u8(&mut self, c: u8) -> Result<(), TooManyItemsError> {
        self.0.try_push(c).map_err(|_| TooManyItemsError)
    }
}

impl<const CAP: usize> fmt::Debug for InlinedString<CAP> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", self.as_str())
    }
}

impl<const CAP: usize> fmt::Display for InlinedString<CAP> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.as_str())
    }
}

impl<const CAP: usize> TryFrom<&str> for InlinedString<CAP> {
    type Error = TooManyItemsError;

    fn try_from(s: &str) -> Result<Self, Self::Error> {
        let mut string = Self::new();
        string.0.try_extend_from_slice(s.as_bytes())?;
        Ok(string)
    }
}