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