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