Skip to main content

multi_trait/
encoded_bytes.rs

1// SPDX-License-Identifier: Apache-2.0
2//! Validated newtype for varint-encoded byte sequences.
3//!
4//! This module provides the [`EncodedBytes`] type, a validated wrapper around
5//! `Vec<u8>` that guarantees the bytes represent a valid, complete varint-encoded
6//! value. This follows the "parse, don't validate" principle by making invalid
7//! states unrepresentable at the type level.
8
9#[cfg(not(feature = "std"))]
10use alloc::{format, vec::Vec};
11
12use crate::error::Error;
13use core::ops::Deref;
14use unsigned_varint::decode;
15
16/// A validated wrapper for varint-encoded bytes.
17///
18/// This newtype ensures that the contained bytes form a valid, complete
19/// varint-encoded value. The validation is performed at construction time,
20/// making it impossible to create an `EncodedBytes` instance with invalid data.
21///
22/// # Type Safety Benefits
23///
24/// Using `EncodedBytes` provides several advantages:
25///
26/// - **Validation at the boundary**: Invalid data is rejected at construction
27/// - **Type-level guarantees**: If you have an `EncodedBytes`, it's valid
28/// - **Clear API contracts**: Functions accepting `EncodedBytes` don't need validation
29/// - **Zero-cost abstraction**: No runtime overhead after construction
30///
31/// # Thread Safety
32///
33/// `EncodedBytes` is both `Send` and `Sync`, making it safe to share across
34/// thread boundaries. The contained data is immutable after validation.
35///
36/// # Examples
37///
38/// ## Creating from valid data
39///
40/// ```rust
41/// use multi_trait::EncodedBytes;
42///
43/// // Valid varint encoding of 42
44/// let bytes = vec![42u8];
45/// let encoded = EncodedBytes::try_from(bytes).unwrap();
46/// assert_eq!(encoded.as_ref(), &[42]);
47/// ```
48///
49/// ## Validation catches invalid data
50///
51/// ```rust
52/// use multi_trait::EncodedBytes;
53///
54/// // Invalid: continuation bit set but no following byte
55/// let invalid = vec![0x80];
56/// let result = EncodedBytes::try_from(invalid);
57/// assert!(result.is_err());
58/// ```
59///
60/// ## Zero-cost unwrapping
61///
62/// ```rust
63/// use multi_trait::EncodedBytes;
64///
65/// let bytes = vec![42u8];
66/// let encoded = EncodedBytes::try_from(bytes).unwrap();
67///
68/// // Convert back to Vec<u8> with no allocation
69/// let original: Vec<u8> = encoded.into();
70/// assert_eq!(original, vec![42]);
71/// ```
72#[derive(Debug, Clone, PartialEq, Eq, Hash)]
73pub struct EncodedBytes(Vec<u8>);
74
75impl EncodedBytes {
76    /// Create a new `EncodedBytes` from a byte slice, validating the data.
77    ///
78    /// This performs the same validation as `TryFrom<Vec<u8>>` but works
79    /// with slices, requiring an allocation.
80    ///
81    /// # Errors
82    ///
83    /// Returns an error if the bytes don't form a valid, complete varint.
84    ///
85    /// # Examples
86    ///
87    /// ```rust
88    /// use multi_trait::EncodedBytes;
89    ///
90    /// let encoded = EncodedBytes::new(&[42]).unwrap();
91    /// assert_eq!(encoded.as_ref(), &[42]);
92    /// ```
93    pub fn new(bytes: &[u8]) -> Result<Self, Error> {
94        Self::try_from(bytes.to_vec())
95    }
96
97    /// Returns the length of the encoded data in bytes.
98    ///
99    /// # Examples
100    ///
101    /// ```rust
102    /// use multi_trait::EncodedBytes;
103    ///
104    /// let encoded = EncodedBytes::new(&[42]).unwrap();
105    /// assert_eq!(encoded.len(), 1);
106    /// ```
107    #[inline]
108    #[must_use]
109    pub fn len(&self) -> usize {
110        self.0.len()
111    }
112
113    /// Returns `true` if the encoded data is empty.
114    ///
115    /// Note: Empty `EncodedBytes` cannot be constructed through normal means,
116    /// as empty bytes don't represent a valid varint. This method exists for
117    /// API completeness.
118    ///
119    /// # Examples
120    ///
121    /// ```rust
122    /// use multi_trait::EncodedBytes;
123    ///
124    /// let encoded = EncodedBytes::new(&[42]).unwrap();
125    /// assert!(!encoded.is_empty());
126    /// ```
127    #[inline]
128    #[must_use]
129    pub fn is_empty(&self) -> bool {
130        self.0.is_empty()
131    }
132
133    /// Returns a reference to the underlying bytes.
134    ///
135    /// # Examples
136    ///
137    /// ```rust
138    /// use multi_trait::EncodedBytes;
139    ///
140    /// let encoded = EncodedBytes::new(&[42]).unwrap();
141    /// assert_eq!(encoded.as_bytes(), &[42]);
142    /// ```
143    #[inline]
144    #[must_use]
145    pub fn as_bytes(&self) -> &[u8] {
146        &self.0
147    }
148
149    /// Consumes the `EncodedBytes` and returns the underlying `Vec<u8>`.
150    ///
151    /// This is a zero-cost operation that transfers ownership without cloning.
152    ///
153    /// # Examples
154    ///
155    /// ```rust
156    /// use multi_trait::EncodedBytes;
157    ///
158    /// let encoded = EncodedBytes::new(&[42]).unwrap();
159    /// let bytes = encoded.into_vec();
160    /// assert_eq!(bytes, vec![42]);
161    /// ```
162    #[inline]
163    #[must_use]
164    pub fn into_vec(self) -> Vec<u8> {
165        self.0
166    }
167}
168
169impl TryFrom<Vec<u8>> for EncodedBytes {
170    type Error = Error;
171
172    /// Attempt to create `EncodedBytes` from a `Vec<u8>`, validating the data.
173    ///
174    /// This validates that the bytes form a complete, valid varint encoding.
175    /// The validation checks:
176    /// 1. The bytes are not empty
177    /// 2. The varint can be successfully decoded
178    /// 3. All bytes are consumed (no trailing data)
179    ///
180    /// # Errors
181    ///
182    /// Returns [`Error::InsufficientData`] if the bytes are empty or incomplete.
183    /// Returns [`Error::UnsignedVarintDecode`] if the varint encoding is invalid.
184    /// Returns [`Error::InvalidEncoding`] if there are trailing bytes after a
185    /// valid varint.
186    ///
187    /// # Examples
188    ///
189    /// ```rust
190    /// use multi_trait::EncodedBytes;
191    ///
192    /// // Valid single-byte encoding
193    /// let valid = vec![42];
194    /// assert!(EncodedBytes::try_from(valid).is_ok());
195    ///
196    /// // Invalid: continuation bit without following byte
197    /// let invalid = vec![0x80];
198    /// assert!(EncodedBytes::try_from(invalid).is_err());
199    /// ```
200    fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
201        // Check for empty input
202        if bytes.is_empty() {
203            return Err(Error::InsufficientData {
204                expected: 1,
205                actual: 0,
206            });
207        }
208
209        // Validate that bytes form a complete varint by attempting decode
210        // We use u128 as it can represent any varint value
211        let remaining = match decode::u128(&bytes) {
212            Ok((_, remaining)) => remaining,
213            Err(source) => {
214                #[cfg(feature = "std")]
215                {
216                    return Err(Error::UnsignedVarintDecode { source });
217                }
218                #[cfg(not(feature = "std"))]
219                {
220                    return Err(Error::UnsignedVarintDecode {
221                        message: format!("{:?}", source),
222                    });
223                }
224            }
225        };
226
227        // Ensure no trailing bytes
228        if !remaining.is_empty() {
229            return Err(Error::InvalidEncoding {
230                reason: format!(
231                    "trailing bytes after valid varint: {} bytes remaining",
232                    remaining.len()
233                ),
234            });
235        }
236
237        Ok(Self(bytes))
238    }
239}
240
241impl From<EncodedBytes> for Vec<u8> {
242    /// Convert `EncodedBytes` back into a `Vec<u8>`.
243    ///
244    /// This is a zero-cost operation that consumes the `EncodedBytes`.
245    ///
246    /// # Examples
247    ///
248    /// ```rust
249    /// use multi_trait::EncodedBytes;
250    ///
251    /// let encoded = EncodedBytes::new(&[42]).unwrap();
252    /// let bytes: Vec<u8> = encoded.into();
253    /// assert_eq!(bytes, vec![42]);
254    /// ```
255    #[inline]
256    fn from(encoded: EncodedBytes) -> Self {
257        encoded.0
258    }
259}
260
261impl AsRef<[u8]> for EncodedBytes {
262    /// Returns a reference to the encoded bytes as a slice.
263    ///
264    /// # Examples
265    ///
266    /// ```rust
267    /// use multi_trait::EncodedBytes;
268    ///
269    /// let encoded = EncodedBytes::new(&[42]).unwrap();
270    /// let slice: &[u8] = encoded.as_ref();
271    /// assert_eq!(slice, &[42]);
272    /// ```
273    #[inline]
274    fn as_ref(&self) -> &[u8] {
275        &self.0
276    }
277}
278
279impl Deref for EncodedBytes {
280    type Target = [u8];
281
282    /// Dereferences to the underlying byte slice.
283    ///
284    /// This allows `EncodedBytes` to be used anywhere a `&[u8]` is expected.
285    ///
286    /// # Examples
287    ///
288    /// ```rust
289    /// use multi_trait::EncodedBytes;
290    ///
291    /// let encoded = EncodedBytes::new(&[42]).unwrap();
292    /// assert_eq!(encoded[0], 42); // Deref enables indexing
293    /// ```
294    #[inline]
295    fn deref(&self) -> &Self::Target {
296        &self.0
297    }
298}
299
300// `EncodedBytes` is `Send + Sync` automatically because its only field is a
301// `Vec<u8>` (which is `Send + Sync`), the data is immutable after
302// construction, and there is no interior mutability. No `unsafe impl` is
303// required; this is documented here because an earlier revision carried
304// redundant `unsafe impl Send/Sync` that violated the crate's
305// `#![deny(unsafe_code)]` policy.
306
307#[cfg(test)]
308mod tests {
309    use super::*;
310
311    #[test]
312    fn test_valid_single_byte() {
313        let bytes = vec![42];
314        let encoded = EncodedBytes::try_from(bytes).unwrap();
315        assert_eq!(encoded.as_ref(), &[42]);
316        assert_eq!(encoded.len(), 1);
317        assert!(!encoded.is_empty());
318    }
319
320    #[test]
321    fn test_valid_multi_byte() {
322        // Varint encoding of 128 requires 2 bytes
323        let bytes = vec![0x80, 0x01];
324        let encoded = EncodedBytes::try_from(bytes).unwrap();
325        assert_eq!(encoded.len(), 2);
326    }
327
328    #[test]
329    fn test_empty_bytes_rejected() {
330        let empty: Vec<u8> = vec![];
331        let result = EncodedBytes::try_from(empty);
332        assert!(result.is_err());
333        if let Err(Error::InsufficientData { expected, actual }) = result {
334            assert_eq!(expected, 1);
335            assert_eq!(actual, 0);
336        } else {
337            panic!("Expected InsufficientData error");
338        }
339    }
340
341    #[test]
342    fn test_truncated_varint_rejected() {
343        // Continuation bit set but no following byte
344        let truncated = vec![0x80];
345        let result = EncodedBytes::try_from(truncated);
346        assert!(result.is_err());
347    }
348
349    #[test]
350    fn test_trailing_bytes_rejected() {
351        // Valid varint followed by extra bytes
352        let mut bytes = vec![42];
353        bytes.extend_from_slice(&[0xFF, 0xEE]);
354        let result = EncodedBytes::try_from(bytes);
355        assert!(result.is_err());
356        if let Err(Error::InvalidEncoding { reason }) = result {
357            assert!(reason.contains("trailing bytes"));
358        } else {
359            panic!("Expected InvalidEncoding error");
360        }
361    }
362
363    #[test]
364    fn test_into_vec() {
365        // Use proper varint encoding
366        let original = vec![0x80, 0x01]; // Varint encoding of 128
367        let encoded = EncodedBytes::try_from(original.clone()).unwrap();
368        let recovered: Vec<u8> = encoded.into();
369        assert_eq!(recovered, original);
370    }
371
372    #[test]
373    fn test_deref() {
374        let encoded = EncodedBytes::new(&[42]).unwrap();
375        assert_eq!(encoded[0], 42); // Tests Deref
376    }
377
378    #[test]
379    fn test_clone() {
380        let encoded = EncodedBytes::new(&[42]).unwrap();
381        let cloned = encoded.clone();
382        assert_eq!(encoded, cloned);
383    }
384
385    #[test]
386    fn test_debug() {
387        let encoded = EncodedBytes::new(&[42]).unwrap();
388        let debug_str = format!("{encoded:?}");
389        assert!(debug_str.contains("EncodedBytes"));
390    }
391
392    // Compile-time verification of Send + Sync
393    #[test]
394    fn assert_send_sync() {
395        fn is_send<T: Send>() {}
396        fn is_sync<T: Sync>() {}
397        is_send::<EncodedBytes>();
398        is_sync::<EncodedBytes>();
399    }
400}