ab_io_type/
fixed_capacity_string.rs

1use crate::fixed_capacity_bytes::{FixedCapacityBytesU8, FixedCapacityBytesU16};
2use crate::metadata::{IoTypeMetadataKind, MAX_METADATA_CAPACITY, concat_metadata_sources};
3use crate::trivial_type::TrivialType;
4use core::ops::{Deref, DerefMut};
5
6/// Container for storing a UTF-8 string limited by the specified fixed bytes capacity as `u8`.
7///
8/// This is a string only by convention, there is no runtime verification done, contents is
9/// treated as regular bytes.
10///
11/// See also [`FixedCapacityStringU16`] if you need to store more bytes.
12///
13/// This is just a wrapper for [`FixedCapacityBytesU8`] that the type dereferences to with a
14/// different semantic meaning.
15#[derive(Debug, Copy, Clone)]
16#[repr(C)]
17pub struct FixedCapacityStringU8<const CAPACITY: usize> {
18    bytes: FixedCapacityBytesU8<CAPACITY>,
19}
20
21impl<const CAPACITY: usize> Default for FixedCapacityStringU8<CAPACITY> {
22    #[inline(always)]
23    fn default() -> Self {
24        Self {
25            bytes: FixedCapacityBytesU8::default(),
26        }
27    }
28}
29
30impl<const CAPACITY: usize> Deref for FixedCapacityStringU8<CAPACITY> {
31    type Target = FixedCapacityBytesU8<CAPACITY>;
32
33    fn deref(&self) -> &Self::Target {
34        &self.bytes
35    }
36}
37
38impl<const CAPACITY: usize> DerefMut for FixedCapacityStringU8<CAPACITY> {
39    fn deref_mut(&mut self) -> &mut Self::Target {
40        &mut self.bytes
41    }
42}
43
44unsafe impl<const CAPACITY: usize> TrivialType for FixedCapacityStringU8<CAPACITY> {
45    const METADATA: &[u8] = {
46        #[inline(always)]
47        const fn metadata(capacity: usize) -> ([u8; MAX_METADATA_CAPACITY], usize) {
48            assert!(
49                capacity <= u8::MAX as usize,
50                "`FixedCapacityStringU8` capacity must not exceed `u8::MAX`"
51            );
52            concat_metadata_sources(&[&[
53                IoTypeMetadataKind::FixedCapacityString8b as u8,
54                capacity as u8,
55            ]])
56        }
57        metadata(CAPACITY).0.split_at(metadata(CAPACITY).1).0
58    };
59}
60
61impl<const CAPACITY: usize> FixedCapacityStringU8<CAPACITY> {
62    /// Try to create an instance from provided string.
63    ///
64    /// Returns `None` if provided string does not fit into the capacity.
65    #[inline(always)]
66    pub fn try_from_str(s: &str) -> Option<Self> {
67        Self::try_from_bytes(s.as_bytes())
68    }
69
70    /// Try to create an instance from provided bytes.
71    ///
72    /// Returns `None` if provided bytes do not fit into the capacity.
73    #[inline(always)]
74    pub fn try_from_bytes(bytes: &[u8]) -> Option<Self> {
75        Some(Self {
76            bytes: FixedCapacityBytesU8::try_from_bytes(bytes)?,
77        })
78    }
79}
80
81/// Container for storing a UTF-8 string limited by the specified fixed bytes capacity as `u16`.
82///
83/// This is a string only by convention, there is no runtime verification done, contents is
84/// treated as regular bytes.
85///
86/// See also [`FixedCapacityStringU8`] if you need to store fewer bytes.
87///
88/// This is just a wrapper for [`FixedCapacityBytesU16`] that the type dereferences to with a
89/// different semantic meaning.
90#[derive(Debug, Copy, Clone)]
91#[repr(C)]
92pub struct FixedCapacityStringU16<const CAPACITY: usize> {
93    bytes: FixedCapacityBytesU16<CAPACITY>,
94}
95
96impl<const CAPACITY: usize> Default for FixedCapacityStringU16<CAPACITY> {
97    #[inline(always)]
98    fn default() -> Self {
99        Self {
100            bytes: FixedCapacityBytesU16::default(),
101        }
102    }
103}
104
105impl<const CAPACITY: usize> Deref for FixedCapacityStringU16<CAPACITY> {
106    type Target = FixedCapacityBytesU16<CAPACITY>;
107
108    fn deref(&self) -> &Self::Target {
109        &self.bytes
110    }
111}
112
113impl<const CAPACITY: usize> DerefMut for FixedCapacityStringU16<CAPACITY> {
114    fn deref_mut(&mut self) -> &mut Self::Target {
115        &mut self.bytes
116    }
117}
118
119unsafe impl<const CAPACITY: usize> TrivialType for FixedCapacityStringU16<CAPACITY> {
120    const METADATA: &[u8] = {
121        #[inline(always)]
122        const fn metadata(capacity: usize) -> ([u8; MAX_METADATA_CAPACITY], usize) {
123            assert!(
124                capacity <= u16::MAX as usize,
125                "`FixedCapacityStringU16` capacity must not exceed `u16::MAX`"
126            );
127            concat_metadata_sources(&[
128                &[IoTypeMetadataKind::FixedCapacityString16b as u8],
129                &(capacity as u16).to_le_bytes(),
130            ])
131        }
132        metadata(CAPACITY).0.split_at(metadata(CAPACITY).1).0
133    };
134}
135
136impl<const CAPACITY: usize> FixedCapacityStringU16<CAPACITY> {
137    /// Try to create an instance from provided string.
138    ///
139    /// Returns `None` if provided string does not fit into the capacity.
140    #[inline(always)]
141    pub fn try_from_str(s: &str) -> Option<Self> {
142        Self::try_from_bytes(s.as_bytes())
143    }
144
145    /// Try to create an instance from provided bytes.
146    ///
147    /// Returns `None` if provided bytes do not fit into the capacity.
148    #[inline(always)]
149    pub fn try_from_bytes(bytes: &[u8]) -> Option<Self> {
150        Some(Self {
151            bytes: FixedCapacityBytesU16::try_from_bytes(bytes)?,
152        })
153    }
154}