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}