fuel_types/
bytes.rs

1use crate::Word;
2
3#[cfg(feature = "alloc")]
4use alloc::vec::Vec;
5
6/// A new type around `Vec<u8>` with useful utilities and optimizations.
7#[cfg(feature = "alloc")]
8#[derive(educe::Educe, Default, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
9#[educe(Debug)]
10#[derive(fuel_types::canonical::Deserialize, fuel_types::canonical::Serialize)]
11pub struct Bytes(#[educe(Debug(method(crate::fmt::fmt_truncated_hex::<16>)))] Vec<u8>);
12
13#[cfg(feature = "serde")]
14impl serde::Serialize for Bytes {
15    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
16    where
17        S: serde::Serializer,
18    {
19        serializer.serialize_bytes(&self.0)
20    }
21}
22
23#[cfg(feature = "serde")]
24impl<'de> serde::Deserialize<'de> for Bytes {
25    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
26    where
27        D: serde::Deserializer<'de>,
28    {
29        /// A visitor for deserializing a bytes.
30        struct BytesVisitor;
31
32        impl<'de> serde::de::Visitor<'de> for BytesVisitor {
33            type Value = Vec<u8>;
34
35            fn expecting(
36                &self,
37                formatter: &mut core::fmt::Formatter,
38            ) -> core::fmt::Result {
39                write!(formatter, "an array of bytes")
40            }
41
42            #[inline(always)]
43            fn visit_borrowed_bytes<E>(self, items: &'de [u8]) -> Result<Self::Value, E> {
44                Ok(items.to_vec())
45            }
46
47            #[inline(always)]
48            fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
49            where
50                E: serde::de::Error,
51            {
52                Ok(v)
53            }
54
55            #[inline(always)]
56            fn visit_seq<A>(self, mut value: A) -> Result<Self::Value, A::Error>
57            where
58                A: serde::de::SeqAccess<'de>,
59            {
60                let size = value.size_hint().unwrap_or(0);
61                let mut arr = Vec::with_capacity(size);
62
63                while let Some(elem) = value.next_element()? {
64                    arr.push(elem);
65                }
66                Ok(arr)
67            }
68        }
69
70        let bytes = deserializer.deserialize_bytes(BytesVisitor)?;
71
72        Ok(Self(bytes))
73    }
74}
75
76#[cfg(feature = "alloc")]
77impl Bytes {
78    /// Creates a new `Bytes` from a `Vec<u8>`.
79    pub const fn new(bytes: Vec<u8>) -> Self {
80        Self(bytes)
81    }
82
83    /// Consumes the `Bytes`, returning the underlying `Vec<u8>`.
84    pub fn into_inner(self) -> Vec<u8> {
85        self.0
86    }
87}
88
89#[cfg(feature = "alloc")]
90impl core::ops::Deref for Bytes {
91    type Target = Vec<u8>;
92
93    fn deref(&self) -> &Self::Target {
94        &self.0
95    }
96}
97
98#[cfg(feature = "alloc")]
99impl core::ops::DerefMut for Bytes {
100    fn deref_mut(&mut self) -> &mut Self::Target {
101        &mut self.0
102    }
103}
104
105#[cfg(feature = "alloc")]
106impl From<Vec<u8>> for Bytes {
107    fn from(value: Vec<u8>) -> Self {
108        Self(value)
109    }
110}
111
112#[cfg(feature = "alloc")]
113impl From<Bytes> for Vec<u8> {
114    fn from(value: Bytes) -> Self {
115        value.0
116    }
117}
118
119#[cfg(feature = "alloc")]
120impl AsRef<[u8]> for Bytes {
121    fn as_ref(&self) -> &[u8] {
122        &self.0
123    }
124}
125
126#[cfg(feature = "alloc")]
127impl AsMut<[u8]> for Bytes {
128    fn as_mut(&mut self) -> &mut [u8] {
129        &mut self.0
130    }
131}
132
133/// Size of a word, in bytes
134pub const WORD_SIZE: usize = core::mem::size_of::<Word>();
135
136/// Return the word-padded length of the buffer.
137/// Returns None if the length is too large to be represented as usize.
138pub const fn padded_len(bytes: &[u8]) -> Option<usize> {
139    padded_len_usize(bytes.len())
140}
141
142/// Return the word-padded length of an arbitrary length.
143/// Returns None if the length is too large to be represented as usize.
144#[allow(clippy::arithmetic_side_effects)] // Safety: (a % b) < b
145pub const fn padded_len_usize(len: usize) -> Option<usize> {
146    let modulo = len % WORD_SIZE;
147    if modulo == 0 {
148        Some(len)
149    } else {
150        let padding = WORD_SIZE - modulo;
151        len.checked_add(padding)
152    }
153}
154
155/// Return the word-padded length of an arbitrary length.
156/// Returns None if the length is too large to be represented as `Word`.
157#[allow(clippy::arithmetic_side_effects)] // Safety: (a % b) < b
158pub const fn padded_len_word(len: Word) -> Option<Word> {
159    let modulo = len % WORD_SIZE as Word;
160    if modulo == 0 {
161        Some(len)
162    } else {
163        let padding = WORD_SIZE as Word - modulo;
164        len.checked_add(padding)
165    }
166}
167
168#[cfg(feature = "unsafe")]
169#[allow(unsafe_code)]
170/// Add a conversion from arbitrary slices into arrays
171///
172/// # Safety
173///
174/// This function will not panic if the length of the slice is smaller than `N`. Instead,
175/// it will cause undefined behavior and read random disowned bytes.
176pub unsafe fn from_slice_unchecked<const N: usize>(buf: &[u8]) -> [u8; N] {
177    unsafe {
178        let ptr = buf.as_ptr() as *const [u8; N];
179
180        // Static assertions are not applicable to runtime length check (e.g. slices).
181        // This is safe if the size of `bytes` is consistent to `N`
182        *ptr
183    }
184}
185
186#[allow(non_snake_case)]
187#[cfg(test)]
188mod tests {
189    use crate::bytes::{
190        Bytes,
191        WORD_SIZE,
192        padded_len,
193        padded_len_usize,
194    };
195
196    #[test]
197    #[allow(clippy::erasing_op)]
198    #[allow(clippy::identity_op)]
199    fn padded_len_returns_multiple_of_word_len() {
200        assert_eq!(Some(WORD_SIZE * 0), padded_len(&[]));
201        assert_eq!(Some(WORD_SIZE * 1), padded_len(&[0]));
202        assert_eq!(Some(WORD_SIZE * 1), padded_len(&[0; WORD_SIZE]));
203        assert_eq!(Some(WORD_SIZE * 2), padded_len(&[0; WORD_SIZE + 1]));
204        assert_eq!(Some(WORD_SIZE * 2), padded_len(&[0; WORD_SIZE * 2]));
205    }
206
207    #[test]
208    fn padded_len_usize_returns_multiple_of_word_len() {
209        assert_eq!(padded_len_usize(0), Some(0));
210        assert_eq!(padded_len_usize(1), Some(8));
211        assert_eq!(padded_len_usize(2), Some(8));
212        assert_eq!(padded_len_usize(7), Some(8));
213        assert_eq!(padded_len_usize(8), Some(8));
214        assert_eq!(padded_len_usize(9), Some(16));
215    }
216
217    #[test]
218    fn padded_len_usize_handles_overflow() {
219        for i in 0..7 {
220            assert_eq!(padded_len_usize(usize::MAX - i), None);
221        }
222        assert_eq!(padded_len_usize(usize::MAX - 7), Some(usize::MAX - 7));
223    }
224
225    #[test]
226    fn bytes__postcard__serialization_correct() {
227        // Given
228        let original_bytes = vec![1u8, 2u8, 3u8, 4u8, 5u8];
229        let bytes = Bytes::new(original_bytes.clone());
230
231        // When
232        let serialized_bytes = postcard::to_allocvec(&bytes).unwrap();
233        let serialized_original_bytes = postcard::to_allocvec(&original_bytes).unwrap();
234
235        // Then
236        assert_eq!(serialized_bytes, serialized_original_bytes);
237    }
238
239    #[test]
240    fn bytes__postcard__deserialization_correct() {
241        // Given
242        let original_bytes = vec![1u8, 2u8, 3u8, 4u8, 5u8];
243        let serialized_original_bytes = postcard::to_allocvec(&original_bytes).unwrap();
244
245        // When
246        let deserialized_bytes: Bytes =
247            postcard::from_bytes(&serialized_original_bytes).unwrap();
248        let expected_bytes = Bytes::new(original_bytes);
249
250        // Then
251        assert_eq!(deserialized_bytes, expected_bytes);
252    }
253
254    #[test]
255    fn bytes__bincode__serialization_correct() {
256        // Given
257        let original_bytes = vec![1u8, 2u8, 3u8, 4u8, 5u8];
258        let bytes = Bytes::new(original_bytes.clone());
259
260        // When
261        let serialized_bytes = bincode::serialize(&bytes).unwrap();
262        let serialized_original_bytes = bincode::serialize(&original_bytes).unwrap();
263
264        // Then
265        assert_eq!(serialized_bytes, serialized_original_bytes);
266    }
267
268    #[test]
269    fn bytes__bincode__deserialization_correct() {
270        // Given
271        let original_bytes = vec![1u8, 2u8, 3u8, 4u8, 5u8];
272        let serialized_original_bytes = bincode::serialize(&original_bytes).unwrap();
273
274        // When
275        let deserialized_bytes: Bytes =
276            bincode::deserialize(&serialized_original_bytes).unwrap();
277        let expected_bytes = Bytes::new(original_bytes);
278
279        // Then
280        assert_eq!(deserialized_bytes, expected_bytes);
281    }
282
283    #[test]
284    fn bytes__json__serialization_correct() {
285        // Given
286        let original_bytes = vec![1u8, 2u8, 3u8, 4u8, 5u8];
287        let bytes = Bytes::new(original_bytes.clone());
288
289        // When
290        let serialized_bytes = serde_json::to_string(&bytes).unwrap();
291        let serialized_original_bytes = serde_json::to_string(&original_bytes).unwrap();
292
293        // Then
294        assert_eq!(serialized_bytes, serialized_original_bytes);
295    }
296
297    #[test]
298    fn bytes__json__deserialization_correct() {
299        // Given
300        let original_bytes = vec![1u8, 2u8, 3u8, 4u8, 5u8];
301        let serialized_original_bytes = serde_json::to_string(&original_bytes).unwrap();
302
303        // When
304        let deserialized_bytes: Bytes =
305            serde_json::from_str(&serialized_original_bytes).unwrap();
306        let expected_bytes = Bytes::new(original_bytes);
307
308        // Then
309        assert_eq!(deserialized_bytes, expected_bytes);
310    }
311}