ab_io_type/
fixed_capacity_bytes.rs

1use crate::metadata::{IoTypeMetadataKind, MAX_METADATA_CAPACITY, concat_metadata_sources};
2use crate::trivial_type::TrivialType;
3
4/// Container for storing a number of bytes limited by the specified fixed capacity as `u8`.
5///
6/// See also [`FixedCapacityBytesU16`] if you need to store more bytes.
7///
8/// In contrast to [`VariableBytes`], which can store arbitrary amount of data and can change the
9/// capacity, this container has fixed predefined capacity and occupies it regardless of how many
10/// bytes are actually stored inside. This might seem limiting but allows implementing
11/// [`TrivialType`] trait, enabling its use for fields in data structures that derive
12/// [`TrivialType`] themselves, which isn't the case with [`VariableBytes`].
13///
14/// [`VariableBytes`]: crate::variable_bytes::VariableBytes
15#[derive(Debug, Copy, Clone)]
16#[repr(C)]
17pub struct FixedCapacityBytesU8<const CAPACITY: usize> {
18    len: u8,
19    bytes: [u8; CAPACITY],
20}
21
22impl<const CAPACITY: usize> Default for FixedCapacityBytesU8<CAPACITY> {
23    #[inline(always)]
24    fn default() -> Self {
25        Self {
26            len: 0,
27            bytes: [0; CAPACITY],
28        }
29    }
30}
31
32unsafe impl<const CAPACITY: usize> TrivialType for FixedCapacityBytesU8<CAPACITY> {
33    const METADATA: &[u8] = {
34        #[inline(always)]
35        const fn metadata(capacity: usize) -> ([u8; MAX_METADATA_CAPACITY], usize) {
36            assert!(
37                capacity <= u8::MAX as usize,
38                "`FixedCapacityBytesU8` capacity must not exceed `u8::MAX`"
39            );
40            concat_metadata_sources(&[&[
41                IoTypeMetadataKind::FixedCapacityBytes8b as u8,
42                capacity as u8,
43            ]])
44        }
45        metadata(CAPACITY).0.split_at(metadata(CAPACITY).1).0
46    };
47}
48
49impl<const CAPACITY: usize> FixedCapacityBytesU8<CAPACITY> {
50    /// Try to create an instance from provided bytes.
51    ///
52    /// Returns `None` if provided bytes do not fit into the capacity.
53    #[inline(always)]
54    pub fn try_from_bytes(bytes: &[u8]) -> Option<Self> {
55        if bytes.len() > CAPACITY {
56            return None;
57        }
58
59        Some(Self {
60            len: bytes.len() as u8,
61            bytes: {
62                let mut buffer = [0; CAPACITY];
63                buffer[..bytes.len()].copy_from_slice(bytes);
64                buffer
65            },
66        })
67    }
68
69    /// Access to stored bytes
70    #[inline(always)]
71    pub fn get_bytes(&self) -> &[u8] {
72        &self.bytes[..self.len as usize]
73    }
74
75    /// Exclusive access to stored bytes
76    #[inline(always)]
77    pub fn get_bytes_mut(&mut self) -> &mut [u8] {
78        &mut self.bytes[..self.len as usize]
79    }
80
81    /// Number of stored bytes
82    #[inline(always)]
83    pub const fn len(&self) -> u8 {
84        self.len
85    }
86
87    /// Returns `true` if length is zero
88    #[inline(always)]
89    pub const fn is_empty(&self) -> bool {
90        self.len == 0
91    }
92
93    /// Append some bytes.
94    ///
95    /// `true` is returned on success, but if there isn't enough capacity left, `false` is.
96    #[inline(always)]
97    #[must_use = "Operation may fail"]
98    pub fn append(&mut self, bytes: &[u8]) -> bool {
99        let len = self.len();
100        if bytes.len() + len as usize > CAPACITY {
101            return false;
102        }
103
104        self.bytes[..bytes.len()].copy_from_slice(bytes);
105
106        true
107    }
108
109    /// Truncate stored bytes to this length.
110    ///
111    /// Returns `true` on success or `false` if `new_len` is larger than [`Self::len()`].
112    #[inline(always)]
113    #[must_use = "Operation may fail"]
114    pub fn truncate(&mut self, new_len: u8) -> bool {
115        if new_len > self.len() {
116            return false;
117        }
118
119        self.len = new_len;
120
121        true
122    }
123
124    /// Copy from specified bytes.
125    ///
126    /// Returns `false` if capacity is not enough to copy contents of `src`
127    #[inline(always)]
128    #[must_use = "Operation may fail"]
129    pub fn copy_from<T>(&mut self, src: &[u8]) -> bool {
130        if src.len() > CAPACITY {
131            return false;
132        }
133
134        self.bytes[..src.len()].copy_from_slice(src);
135        self.len = src.len() as u8;
136
137        true
138    }
139}
140
141/// Container for storing a number of bytes limited by the specified fixed capacity as `u16`.
142///
143/// See also [`FixedCapacityBytesU8`] if you need to store fewer bytes.
144///
145/// In contrast to [`VariableBytes`], which can store arbitrary amount of data and can change the
146/// capacity, this container has fixed predefined capacity and occupies it regardless of how many
147/// bytes are actually stored inside. This might seem limiting but allows implementing
148/// [`TrivialType`] trait, enabling its use for fields in data structures that derive
149/// [`TrivialType`] themselves, which isn't the case with [`VariableBytes`].
150///
151/// [`VariableBytes`]: crate::variable_bytes::VariableBytes
152#[derive(Debug, Copy, Clone)]
153#[repr(C)]
154pub struct FixedCapacityBytesU16<const CAPACITY: usize> {
155    len: u16,
156    bytes: [u8; CAPACITY],
157}
158
159impl<const CAPACITY: usize> Default for FixedCapacityBytesU16<CAPACITY> {
160    #[inline(always)]
161    fn default() -> Self {
162        Self {
163            len: 0,
164            bytes: [0; CAPACITY],
165        }
166    }
167}
168
169unsafe impl<const CAPACITY: usize> TrivialType for FixedCapacityBytesU16<CAPACITY> {
170    const METADATA: &[u8] = {
171        #[inline(always)]
172        const fn metadata(capacity: usize) -> ([u8; MAX_METADATA_CAPACITY], usize) {
173            assert!(
174                capacity <= u16::MAX as usize,
175                "`FixedCapacityBytesU16` capacity must not exceed `u16::MAX`"
176            );
177            concat_metadata_sources(&[
178                &[IoTypeMetadataKind::FixedCapacityBytes16b as u8],
179                &(capacity as u16).to_le_bytes(),
180            ])
181        }
182        metadata(CAPACITY).0.split_at(metadata(CAPACITY).1).0
183    };
184}
185
186impl<const CAPACITY: usize> FixedCapacityBytesU16<CAPACITY> {
187    /// Try to create an instance from provided bytes.
188    ///
189    /// Returns `None` if provided bytes do not fit into the capacity.
190    #[inline(always)]
191    pub fn try_from_bytes(bytes: &[u8]) -> Option<Self> {
192        if bytes.len() > CAPACITY {
193            return None;
194        }
195
196        Some(Self {
197            len: bytes.len() as u16,
198            bytes: {
199                let mut buffer = [0; CAPACITY];
200                buffer[..bytes.len()].copy_from_slice(bytes);
201                buffer
202            },
203        })
204    }
205
206    /// Access to stored bytes
207    #[inline(always)]
208    pub fn get_bytes(&self) -> &[u8] {
209        &self.bytes[..self.len as usize]
210    }
211
212    /// Exclusive access to stored bytes
213    #[inline(always)]
214    pub fn get_bytes_mut(&mut self) -> &mut [u8] {
215        &mut self.bytes[..self.len as usize]
216    }
217
218    /// Number of stored bytes
219    #[inline(always)]
220    pub const fn len(&self) -> u16 {
221        self.len
222    }
223
224    /// Returns `true` if length is zero
225    #[inline(always)]
226    pub const fn is_empty(&self) -> bool {
227        self.len == 0
228    }
229
230    /// Append some bytes.
231    ///
232    /// `true` is returned on success, but if there isn't enough capacity left, `false` is.
233    #[inline(always)]
234    #[must_use = "Operation may fail"]
235    pub fn append(&mut self, bytes: &[u8]) -> bool {
236        let len = self.len();
237        if bytes.len() + len as usize > CAPACITY {
238            return false;
239        }
240
241        self.bytes[..bytes.len()].copy_from_slice(bytes);
242
243        true
244    }
245
246    /// Truncate stored bytes to this length.
247    ///
248    /// Returns `true` on success or `false` if `new_len` is larger than [`Self::len()`].
249    #[inline(always)]
250    #[must_use = "Operation may fail"]
251    pub fn truncate(&mut self, new_len: u16) -> bool {
252        if new_len > self.len() {
253            return false;
254        }
255
256        self.len = new_len;
257
258        true
259    }
260
261    /// Copy from specified bytes.
262    ///
263    /// Returns `false` if capacity is not enough to copy contents of `src`
264    #[inline(always)]
265    #[must_use = "Operation may fail"]
266    pub fn copy_from<T>(&mut self, src: &[u8]) -> bool {
267        if src.len() > CAPACITY {
268            return false;
269        }
270
271        self.bytes[..src.len()].copy_from_slice(src);
272        self.len = src.len() as u16;
273
274        true
275    }
276}