dcbor/
byte_string.rs

1import_stdlib!();
2
3use crate::{CBOR, Error};
4
5/// Represents a CBOR byte string (major type 2).
6///
7/// `ByteString` is a wrapper around a byte vector, optimized for use in CBOR
8/// encoding and decoding operations. It provides a richer API for working with
9/// byte data in the context of CBOR compared to using raw `Vec<u8>` values.
10///
11/// In dCBOR, byte strings follow the general deterministic encoding rules:
12/// - They must use definite-length encoding
13/// - Their length must be encoded in the shortest possible form
14///
15/// # Use Cases
16///
17/// Byte strings in CBOR are commonly used for:
18/// - Binary data such as images, audio, or other non-text content
19/// - Cryptographic values like hashes, signatures, and public keys
20/// - Embedded CBOR (wrapped with tag 24)
21/// - Other serialized data formats embedded in CBOR
22///
23/// # Examples
24///
25/// ```
26/// use dcbor::prelude::*;
27///
28/// // Creating a byte string from various sources
29/// let bytes1 = ByteString::new(vec![1, 2, 3, 4]);
30/// let bytes2 = ByteString::from([5, 6, 7, 8]);
31/// let bytes3 = ByteString::from(&[9, 10, 11, 12][..]);
32///
33/// // Converting to and from CBOR
34/// let cbor = CBOR::from(bytes1.clone());
35/// assert_eq!(cbor.diagnostic(), "h'01020304'");
36///
37/// // The byte string can be extracted from CBOR
38/// let extracted: ByteString = cbor.try_into().unwrap();
39/// assert_eq!(extracted, bytes1);
40///
41/// // ByteString provides Vec<u8>-like operations
42/// let mut bytes = ByteString::new(vec![1, 2]);
43/// bytes.extend(vec![3, 4]);
44/// assert_eq!(bytes.len(), 4);
45/// assert_eq!(bytes.data(), &[1, 2, 3, 4]);
46/// ```
47#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
48pub struct ByteString(Vec<u8>);
49
50impl ByteString {
51    /// Creates a new `ByteString` from any type that can be converted into a
52    /// byte vector.
53    ///
54    /// This constructor accepts any type that implements `Into<Vec<u8>>`, which
55    /// includes common types like `Vec<u8>`, arrays `[u8; N]`, slices
56    /// `&[u8]`, and string slices `&str` (via the `From<&str>`
57    /// implementation).
58    ///
59    /// # Examples
60    ///
61    /// ```
62    /// use dcbor::prelude::*;
63    ///
64    /// // From a vector
65    /// let bytes1 = ByteString::new(vec![1, 2, 3, 4]);
66    ///
67    /// // From a byte array
68    /// let bytes2 = ByteString::new([5, 6, 7, 8]);
69    ///
70    /// // From a byte slice
71    /// let bytes3 = ByteString::new(&[9, 10, 11, 12][..]);
72    ///
73    /// // From a hex string (using an implementation elsewhere)
74    /// let hex = "deadbeef";
75    /// let bytes4 = ByteString::new(hex::decode(hex).unwrap());
76    /// ```
77    pub fn new(data: impl AsRef<[u8]>) -> Self { Self(data.as_ref().to_vec()) }
78
79    /// Returns a reference to the underlying byte data.
80    ///
81    /// This method provides access to the raw bytes without cloning them.
82    ///
83    /// # Examples
84    ///
85    /// ```
86    /// use dcbor::prelude::*;
87    ///
88    /// let bytes = ByteString::new([1, 2, 3, 4]);
89    /// assert_eq!(bytes.data(), &[1, 2, 3, 4]);
90    ///
91    /// // You can use standard slice operations on the result
92    /// assert_eq!(bytes.data()[1..3], [2, 3]);
93    /// ```
94    pub fn data(&self) -> &[u8] { &self.0 }
95
96    /// Returns the length of the byte string in bytes.
97    ///
98    /// # Examples
99    ///
100    /// ```
101    /// use dcbor::prelude::*;
102    ///
103    /// let empty = ByteString::new(vec![]);
104    /// assert_eq!(empty.len(), 0);
105    ///
106    /// let bytes = ByteString::new([1, 2, 3, 4]);
107    /// assert_eq!(bytes.len(), 4);
108    /// ```
109    pub fn len(&self) -> usize { self.0.len() }
110
111    /// Returns `true` if the byte string contains no bytes.
112    ///
113    /// # Examples
114    ///
115    /// ```
116    /// use dcbor::prelude::*;
117    ///
118    /// let empty = ByteString::new(vec![]);
119    /// assert!(empty.is_empty());
120    ///
121    /// let bytes = ByteString::new([1, 2, 3, 4]);
122    /// assert!(!bytes.is_empty());
123    /// ```
124    pub fn is_empty(&self) -> bool { self.0.is_empty() }
125
126    /// Extends the byte string with additional bytes.
127    ///
128    /// This method appends the bytes from the provided value to the end of
129    /// the existing byte string.
130    ///
131    /// # Examples
132    ///
133    /// ```
134    /// use dcbor::prelude::*;
135    ///
136    /// let mut bytes = ByteString::new([1, 2]);
137    /// bytes.extend([3, 4]);
138    /// assert_eq!(bytes.data(), &[1, 2, 3, 4]);
139    ///
140    /// // You can extend with different types
141    /// bytes.extend(vec![5, 6]);
142    /// assert_eq!(bytes.data(), &[1, 2, 3, 4, 5, 6]);
143    /// ```
144    pub fn extend(&mut self, other: impl AsRef<[u8]>) {
145        self.0.extend(other.as_ref());
146    }
147
148    /// Creates a new vector containing a copy of the byte string's data.
149    ///
150    /// # Examples
151    ///
152    /// ```
153    /// use dcbor::prelude::*;
154    ///
155    /// let bytes = ByteString::new([1, 2, 3, 4]);
156    /// let vec = bytes.to_vec();
157    /// assert_eq!(vec, vec![1, 2, 3, 4]);
158    ///
159    /// // The returned vector is a clone, so you can modify it independently
160    /// let mut vec2 = bytes.to_vec();
161    /// vec2.push(5);
162    /// assert_eq!(vec2, vec![1, 2, 3, 4, 5]);
163    /// assert_eq!(bytes.data(), &[1, 2, 3, 4]); // original unchanged
164    /// ```
165    pub fn to_vec(&self) -> Vec<u8> { self.0.clone() }
166
167    /// Returns an iterator over the bytes in the byte string.
168    ///
169    /// The iterator yields references to each byte in the byte string.
170    ///
171    /// # Examples
172    ///
173    /// ```
174    /// use dcbor::prelude::*;
175    ///
176    /// let bytes = ByteString::new([1, 2, 3]);
177    /// let mut iter = bytes.iter();
178    ///
179    /// assert_eq!(iter.next(), Some(&1));
180    /// assert_eq!(iter.next(), Some(&2));
181    /// assert_eq!(iter.next(), Some(&3));
182    /// assert_eq!(iter.next(), None);
183    ///
184    /// // You can also use for loops
185    /// let mut sum = 0;
186    /// for byte in bytes.iter() {
187    ///     sum += *byte;
188    /// }
189    /// assert_eq!(sum, 6);
190    /// ```
191    pub fn iter(&self) -> ByteStringIterator<'_> {
192        ByteStringIterator { slice: &self.0, pos: 0 }
193    }
194}
195
196/// Converts a `ByteString` into a `Vec<u8>`.
197///
198/// This allows consuming a byte string and getting ownership of the underlying
199/// byte vector.
200///
201/// # Examples
202///
203/// ```
204/// use dcbor::prelude::*;
205///
206/// let bytes = ByteString::new([1, 2, 3, 4]);
207/// let vec: Vec<u8> = bytes.into();
208/// assert_eq!(vec, vec![1, 2, 3, 4]);
209///
210/// // This is useful when you need to pass the data to a function that expects Vec<u8>
211/// fn process_bytes(data: Vec<u8>) -> usize {
212///     data.len()
213/// }
214///
215/// let bytes = ByteString::new([1, 2, 3, 4]);
216/// let size = process_bytes(bytes.into());
217/// assert_eq!(size, 4);
218/// ```
219impl From<ByteString> for Vec<u8> {
220    fn from(value: ByteString) -> Self { value.0 }
221}
222
223/// Converts a `Vec<u8>` into a `ByteString`.
224///
225/// This conversion takes ownership of the vector, avoiding a copy operation.
226///
227/// # Examples
228///
229/// ```
230/// use dcbor::prelude::*;
231///
232/// let vec = vec![1, 2, 3, 4];
233/// let bytes = ByteString::from(vec);
234/// assert_eq!(bytes.data(), &[1, 2, 3, 4]);
235///
236/// // You can also use the .into() method
237/// let vec = vec![5, 6, 7, 8];
238/// let bytes: ByteString = vec.into();
239/// assert_eq!(bytes.data(), &[5, 6, 7, 8]);
240/// ```
241impl From<Vec<u8>> for ByteString {
242    fn from(value: Vec<u8>) -> Self { Self(value) }
243}
244
245/// Converts a reference to a `Vec<u8>` into a `ByteString`.
246///
247/// This conversion clones the vector data since it only has a reference.
248///
249/// # Examples
250///
251/// ```
252/// use dcbor::prelude::*;
253///
254/// let vec = vec![1, 2, 3, 4];
255/// let bytes = ByteString::from(&vec);
256/// assert_eq!(bytes.data(), &[1, 2, 3, 4]);
257///
258/// // The original vector is unchanged
259/// assert_eq!(vec, vec![1, 2, 3, 4]);
260/// ```
261impl From<&Vec<u8>> for ByteString {
262    fn from(value: &Vec<u8>) -> Self { Self(value.clone()) }
263}
264
265/// Converts a byte slice into a `ByteString`.
266///
267/// This conversion clones the slice data since it only has a reference.
268///
269/// # Examples
270///
271/// ```
272/// use dcbor::prelude::*;
273///
274/// let slice: &[u8] = &[1, 2, 3, 4];
275/// let bytes = ByteString::from(slice);
276/// assert_eq!(bytes.data(), &[1, 2, 3, 4]);
277///
278/// // You can also use the From trait with array slices
279/// let array = [5, 6, 7, 8];
280/// let bytes = ByteString::from(&array[..]);
281/// assert_eq!(bytes.data(), &[5, 6, 7, 8]);
282/// ```
283impl From<&[u8]> for ByteString {
284    fn from(value: &[u8]) -> Self { Self(value.to_vec()) }
285}
286
287/// Converts a string slice into a `ByteString`.
288///
289/// This conversion treats the string as UTF-8 and stores its raw byte
290/// representation. Note that this doesn't perform any additional encoding or
291/// normalization - it simply uses the raw UTF-8 bytes of the string.
292///
293/// # Examples
294///
295/// ```
296/// use dcbor::prelude::*;
297///
298/// let s = "hello";
299/// let bytes = ByteString::from(s);
300/// assert_eq!(bytes.data(), b"hello");
301///
302/// // UTF-8 multi-byte characters work as expected
303/// let s = "こんにちは"; // "hello" in Japanese
304/// let bytes = ByteString::from(s);
305/// assert_eq!(bytes.data(), "こんにちは".as_bytes());
306/// ```
307impl From<&str> for ByteString {
308    fn from(value: &str) -> Self { Self(value.as_bytes().to_vec()) }
309}
310
311/// Converts a `ByteString` into a CBOR byte string value.
312///
313/// This conversion creates a CBOR item of major type 2 (byte string)
314/// containing the byte string's data.
315///
316/// # Examples
317///
318/// ```
319/// use dcbor::prelude::*;
320///
321/// let bytes = ByteString::new([1, 2, 3, 4]);
322/// let cbor = CBOR::from(bytes);
323///
324/// // The result is a CBOR byte string
325/// assert_eq!(cbor.diagnostic(), "h'01020304'");
326///
327/// // The encoding follows dCBOR rules
328/// assert_eq!(cbor.to_cbor_data(), vec![0x44, 0x01, 0x02, 0x03, 0x04]);
329/// //           0x44: byte string (major type 2) of length 4
330/// ```
331impl From<ByteString> for CBOR {
332    fn from(value: ByteString) -> Self { CBOR::to_byte_string(value) }
333}
334
335/// Attempts to convert a CBOR value into a `ByteString`.
336///
337/// This conversion succeeds if the CBOR value is a byte string (major type 2),
338/// otherwise it returns a `WrongType` error.
339///
340/// # Examples
341///
342/// ```
343/// use dcbor::prelude::*;
344///
345/// // Converting from a CBOR byte string works
346/// let cbor = CBOR::to_byte_string([1, 2, 3, 4]);
347/// let bytes: ByteString = cbor.try_into().unwrap();
348/// assert_eq!(bytes.data(), &[1, 2, 3, 4]);
349///
350/// // Converting from a different CBOR type fails
351/// let cbor = CBOR::from(42);
352/// let result: dcbor::Result<ByteString> = cbor.try_into();
353/// assert!(result.is_err());
354/// ```
355impl TryFrom<CBOR> for ByteString {
356    type Error = Error;
357
358    fn try_from(cbor: CBOR) -> Result<Self, Self::Error> {
359        Ok(CBOR::try_into_byte_string(cbor)?.into())
360    }
361}
362
363/// Converts a fixed-size byte array into a `ByteString`.
364///
365/// This provides a convenient way to create byte strings from array literals.
366///
367/// # Examples
368///
369/// ```
370/// use dcbor::prelude::*;
371///
372/// let bytes = ByteString::from([1, 2, 3, 4]);
373/// assert_eq!(bytes.data(), &[1, 2, 3, 4]);
374///
375/// // Works with arrays of any size
376/// let bytes = ByteString::from([0; 10]);
377/// assert_eq!(bytes.data(), &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
378/// ```
379impl<const N: usize> From<[u8; N]> for ByteString {
380    fn from(value: [u8; N]) -> Self { Self(value.to_vec()) }
381}
382
383/// Converts a reference to a fixed-size byte array into a `ByteString`.
384///
385/// This avoids moving ownership of the array while still creating a byte string
386/// from it.
387///
388/// # Examples
389///
390/// ```
391/// use dcbor::prelude::*;
392///
393/// let array = [1, 2, 3, 4];
394/// let bytes = ByteString::from(&array);
395/// assert_eq!(bytes.data(), &[1, 2, 3, 4]);
396///
397/// // The original array is unchanged
398/// assert_eq!(array, [1, 2, 3, 4]);
399/// ```
400impl<const N: usize> From<&[u8; N]> for ByteString {
401    fn from(value: &[u8; N]) -> Self { Self(value.to_vec()) }
402}
403
404/// Attempts to convert a `ByteString` into a fixed-size byte array.
405///
406/// This conversion succeeds only if the byte string has exactly the right
407/// length for the target array. If it has a different length, it returns a
408/// `TryFromSliceError`.
409///
410/// # Examples
411///
412/// ```
413/// use dcbor::prelude::*;
414///
415/// // When the lengths match, conversion succeeds
416/// let bytes = ByteString::new([1, 2, 3, 4]);
417/// let array: [u8; 4] = bytes.try_into().unwrap();
418/// assert_eq!(array, [1, 2, 3, 4]);
419/// // When the lengths don't match, conversion fails
420/// let bytes = ByteString::new([1, 2, 3]);
421/// let result: core::result::Result<[u8; 4], _> = bytes.try_into();
422/// assert!(result.is_err());
423/// ```
424impl<const N: usize> TryFrom<ByteString> for [u8; N] {
425    type Error = TryFromSliceError;
426
427    fn try_from(value: ByteString) -> Result<Self, Self::Error> {
428        value.0.as_slice().try_into()
429    }
430}
431
432/// Implements the `IntoIterator` trait for references to `ByteString`.
433///
434/// This allows using a byte string directly in a `for` loop, which will
435/// iterate over references to each byte.
436///
437/// # Examples
438///
439/// ```
440/// use dcbor::prelude::*;
441///
442/// let bytes = ByteString::new([1, 2, 3, 4]);
443///
444/// // You can use a for loop directly on a ByteString reference
445/// let mut sum = 0;
446/// for byte in &bytes {
447///     sum += *byte;
448/// }
449/// assert_eq!(sum, 10);
450///
451/// // This is equivalent to using the iter() method
452/// let mut product = 1;
453/// for byte in bytes.iter() {
454///     product *= *byte;
455/// }
456/// assert_eq!(product, 24);
457/// ```
458impl<'a> IntoIterator for &'a ByteString {
459    type Item = &'a u8;
460    type IntoIter = ByteStringIterator<'a>;
461
462    fn into_iter(self) -> Self::IntoIter { self.iter() }
463}
464
465/// Implements the `AsRef<[u8]>` trait for `ByteString`.
466///
467/// This allows a byte string to be used with functions that accept
468/// references to byte slices.
469///
470/// # Examples
471///
472/// ```
473/// use dcbor::prelude::*;
474///
475/// let bytes = ByteString::new([1, 2, 3, 4]);
476///
477/// // Function that takes anything that can be referenced as a byte slice
478/// fn first_byte(data: impl AsRef<[u8]>) -> Option<u8> {
479///     let slice = data.as_ref();
480///     slice.first().copied()
481/// }
482///
483/// assert_eq!(first_byte(&bytes), Some(1));
484/// ```
485impl AsRef<[u8]> for ByteString {
486    fn as_ref(&self) -> &[u8] { &self.0 }
487}
488
489/// Implements the `Deref` trait for `ByteString`, allowing it to be treated as
490/// a slice.
491///
492/// This implementation makes it possible to use slice methods directly on a
493/// `ByteString` without explicitly calling `.data()` or `.as_ref()`.
494///
495/// # Examples
496///
497/// ```
498/// use dcbor::prelude::*;
499///
500/// let bytes = ByteString::new([1, 2, 3, 4]);
501///
502/// // You can use slice indexing directly
503/// assert_eq!(bytes[0], 1);
504/// assert_eq!(bytes[1..3], [2, 3]);
505///
506/// // You can use slice methods directly
507/// assert_eq!(bytes.first(), Some(&1));
508/// assert_eq!(bytes.last(), Some(&4));
509/// ```
510impl Deref for ByteString {
511    type Target = [u8];
512
513    fn deref(&self) -> &Self::Target { &self.0 }
514}
515
516/// An iterator over the bytes in a `ByteString`.
517///
518/// This iterator yields references to each byte in the byte string in sequence.
519/// It is created by the `ByteString::iter()` method or by using the
520/// `IntoIterator` trait on a reference to a `ByteString`.
521///
522/// # Examples
523///
524/// ```
525/// use dcbor::prelude::*;
526///
527/// let bytes = ByteString::new([1, 2, 3]);
528/// let mut iter = bytes.iter();
529///
530/// assert_eq!(iter.next(), Some(&1));
531/// assert_eq!(iter.next(), Some(&2));
532/// assert_eq!(iter.next(), Some(&3));
533/// assert_eq!(iter.next(), None);
534/// ```
535pub struct ByteStringIterator<'a> {
536    /// The slice being iterated over
537    slice: &'a [u8],
538
539    /// The current position in the slice
540    pos: usize,
541}
542
543/// Implements the `Iterator` trait for `ByteStringIterator`.
544///
545/// This provides the core functionality for iterating over a byte string's
546/// contents.
547impl<'a> Iterator for ByteStringIterator<'a> {
548    type Item = &'a u8;
549
550    fn next(&mut self) -> Option<Self::Item> {
551        if self.pos < self.slice.len() {
552            let item = &self.slice[self.pos];
553            self.pos += 1;
554            Some(item)
555        } else {
556            None
557        }
558    }
559}
560
561#[cfg(test)]
562mod tests {
563    #[test]
564    fn test_1() {
565        use crate::prelude::*;
566        // When the lengths match, conversion succeeds
567        let bytes = ByteString::new([1, 2, 3, 4]);
568        let array: [u8; 4] = bytes.try_into().unwrap();
569        assert_eq!(array, [1, 2, 3, 4]);
570        // When the lengths don't match, conversion fails
571        let bytes = ByteString::new([1, 2, 3]);
572        let result: core::result::Result<[u8; 4], _> = bytes.try_into();
573        assert!(result.is_err());
574    }
575}