cbor_core/value.rs
1mod array;
2mod bytes;
3mod default_eq_ord_hash;
4mod float;
5mod index;
6mod int;
7mod map;
8mod simple_value;
9mod string;
10
11use std::{
12 cmp,
13 collections::BTreeMap,
14 fmt,
15 hash::{Hash, Hasher},
16 io,
17 ops::{Index, IndexMut},
18 time::{Duration, SystemTime},
19};
20
21use crate::{
22 ArgLength, Array, CtrlByte, DataType, DateTime, EpochTime, Error, Float, IntegerBytes, Major, Map, Result,
23 SimpleValue, Tag, util::u128_from_slice,
24};
25
26const OOM_MITIGATION: usize = 100_000_000; // maximum size to reserve capacity
27const LENGTH_LIMIT: u64 = 1_000_000_000; // length limit for arrays, maps, test and byte strings
28const RECURSION_LIMIT: u16 = 200; // maximum hierarchical data structure depth
29
30/// A single CBOR data item.
31///
32/// `Value` covers all CBOR major types: integers, floats, byte and text
33/// strings, arrays, maps, tagged values, and simple values (null, booleans).
34/// It encodes deterministically and decodes only canonical input.
35///
36/// # Creating values
37///
38/// Rust primitives convert via [`From`]:
39///
40/// ```
41/// use cbor_core::Value;
42///
43/// let n = Value::from(42);
44/// let s = Value::from("hello");
45/// let b = Value::from(true);
46/// ```
47///
48/// For arrays and maps the `array!` and `map!` macros are convenient:
49///
50/// ```
51/// use cbor_core::{Value, array, map};
52///
53/// let a = array![1, 2, 3];
54/// let m = map! { "x" => 10, "y" => 20 };
55/// ```
56///
57/// Arrays and maps can also be built from standard Rust collections.
58/// Slices, `Vec`s, fixed-size arrays, `BTreeMap`s, `HashMap`s, and
59/// slices of key-value pairs all convert automatically:
60///
61/// ```
62/// use cbor_core::Value;
63/// use std::collections::HashMap;
64///
65/// // Array from a slice
66/// let a = Value::array([1, 2, 3].as_slice());
67///
68/// // Map from a HashMap
69/// let mut hm = HashMap::new();
70/// hm.insert(1, 2);
71/// let m = Value::map(&hm);
72///
73/// // Map from key-value pairs
74/// let m = Value::map([("x", 10), ("y", 20)]);
75/// ```
76///
77/// Use `()` to create empty arrays or maps without spelling out a type:
78///
79/// ```
80/// use cbor_core::Value;
81///
82/// let empty_array = Value::array(());
83/// let empty_map = Value::map(());
84///
85/// assert_eq!(empty_array.as_array().unwrap().len(), 0);
86/// assert_eq!(empty_map.as_map().unwrap().len(), 0);
87/// ```
88///
89/// Named constructors are available for cases where `From` is ambiguous:
90///
91/// | Constructor | Builds |
92/// |---|---|
93/// | [`Value::null()`] | Null simple value |
94/// | [`Value::simple_value(v)`](Value::simple_value) | Arbitrary simple value |
95/// | [`Value::float(v)`](Value::float) | Float in shortest CBOR form |
96/// | [`Value::array(v)`](Value::array) | Array from slice, `Vec`, or fixed-size array |
97/// | [`Value::map(v)`](Value::map) | Map from `BTreeMap`, `HashMap`, slice of pairs, etc. |
98/// | [`Value::tag(n, v)`](Value::tag) | Tagged value |
99///
100/// # Encoding and decoding
101///
102/// ```
103/// use cbor_core::Value;
104///
105/// let original = Value::from(-1000);
106/// let bytes = original.encode();
107/// let decoded = Value::decode(&bytes).unwrap();
108/// assert_eq!(original, decoded);
109/// ```
110///
111/// For streaming use, [`write_to`](Value::write_to) and
112/// [`read_from`](Value::read_from) operate on any `io::Write` / `io::Read`.
113///
114/// # Accessors
115///
116/// Accessor methods extract or borrow the inner data of each variant.
117/// All return `Result<T>`, yielding `Err(Error::IncompatibleType)` on a
118/// type mismatch. The naming follows Rust conventions:
119///
120/// | Prefix | Meaning | Returns |
121/// |---|---|---|
122/// | `as_*` | Borrow inner data | `&T` or `&mut T` (with `_mut`) |
123/// | `to_*` | Convert or narrow | Owned `Copy` type (`u8`, `f32`, ...) |
124/// | `into_*` | Consume self, extract | Owned `T` |
125/// | no prefix | Trivial property | `Copy` scalar |
126///
127/// ## Simple values
128///
129/// In CBOR, booleans and null are not distinct types but specific simple
130/// values: `false` is 20, `true` is 21, `null` is 22. This means a
131/// boolean value is always also a simple value. [`to_bool`](Self::to_bool)
132/// provides typed access to `true`/`false`, while
133/// [`to_simple_value`](Self::to_simple_value) works on any simple value
134/// including booleans and null.
135///
136/// | Method | Returns | Notes |
137/// |---|---|---|
138/// | [`to_simple_value`](Self::to_simple_value) | `Result<u8>` | Raw simple value number |
139/// | [`to_bool`](Self::to_bool) | `Result<bool>` | Only for `true`/`false` |
140///
141/// ```
142/// use cbor_core::Value;
143///
144/// let v = Value::from(true);
145/// assert_eq!(v.to_bool().unwrap(), true);
146/// assert_eq!(v.to_simple_value().unwrap(), 21); // CBOR true = simple(21)
147///
148/// // null is also a simple value
149/// let n = Value::null();
150/// assert!(n.to_bool().is_err()); // not a boolean
151/// assert_eq!(n.to_simple_value().unwrap(), 22); // but is simple(22)
152/// ```
153///
154/// ## Integers
155///
156/// CBOR has effectively four integer types (unsigned or negative, and
157/// normal or big integer) with different internal representations.
158/// This is handled transparently by the API.
159///
160/// The `to_*` accessors perform checked
161/// narrowing into any Rust integer type, returning `Err(Overflow)` if
162/// the value does not fit, or `Err(NegativeUnsigned)` when extracting a
163/// negative value into an unsigned type.
164///
165/// | Method | Returns |
166/// |---|---|
167/// | [`to_u8`](Self::to_u8) .. [`to_u128`](Self::to_u128), [`to_usize`](Self::to_usize) | `Result<uN>` |
168/// | [`to_i8`](Self::to_i8) .. [`to_i128`](Self::to_i128), [`to_isize`](Self::to_isize) | `Result<iN>` |
169///
170/// ```
171/// use cbor_core::Value;
172///
173/// let v = Value::from(1000);
174/// assert_eq!(v.to_u32().unwrap(), 1000);
175/// assert_eq!(v.to_i64().unwrap(), 1000);
176/// assert!(v.to_u8().is_err()); // overflow
177///
178/// let neg = Value::from(-5);
179/// assert_eq!(neg.to_i8().unwrap(), -5);
180/// assert!(neg.to_u32().is_err()); // negative unsigned
181/// ```
182///
183/// ## Floats
184///
185/// Floats are stored internally in their shortest CBOR encoding (`f16`,
186/// `f32`, or `f64`). [`to_f64`](Self::to_f64) always succeeds since every
187/// float can widen to `f64`. [`to_f32`](Self::to_f32) fails with
188/// `Err(Precision)` if the value is stored as `f64`.
189/// A float internally stored as `f16` can always be converted to either
190/// an `f32` or `f64` for obvious reasons.
191///
192/// | Method | Returns |
193/// |---|---|
194/// | [`to_f32`](Self::to_f32) | `Result<f32>` (fails for f64 values) |
195/// | [`to_f64`](Self::to_f64) | `Result<f64>` |
196///
197/// ```
198/// use cbor_core::Value;
199///
200/// let v = Value::from(2.5);
201/// assert_eq!(v.to_f64().unwrap(), 2.5);
202/// assert_eq!(v.to_f32().unwrap(), 2.5);
203/// ```
204///
205/// ## Byte strings
206///
207/// Byte strings are stored as `Vec<u8>`. Use [`as_bytes`](Self::as_bytes)
208/// for a borrowed slice, or [`into_bytes`](Self::into_bytes) to take
209/// ownership without copying.
210///
211/// | Method | Returns |
212/// |---|---|
213/// | [`as_bytes`](Self::as_bytes) | `Result<&[u8]>` |
214/// | [`as_bytes_mut`](Self::as_bytes_mut) | `Result<&mut Vec<u8>>` |
215/// | [`into_bytes`](Self::into_bytes) | `Result<Vec<u8>>` |
216///
217/// ```
218/// use cbor_core::Value;
219///
220/// let mut v = Value::from(vec![1, 2, 3]);
221/// v.as_bytes_mut().unwrap().push(4);
222/// assert_eq!(v.as_bytes().unwrap(), &[1, 2, 3, 4]);
223/// ```
224///
225/// ## Text strings
226///
227/// Text strings are stored as `String` (guaranteed valid UTF-8 by the
228/// decoder). Use [`as_str`](Self::as_str) for a borrowed `&str`, or
229/// [`into_string`](Self::into_string) to take ownership.
230///
231/// | Method | Returns |
232/// |---|---|
233/// | [`as_str`](Self::as_str) | `Result<&str>` |
234/// | [`as_string_mut`](Self::as_string_mut) | `Result<&mut String>` |
235/// | [`into_string`](Self::into_string) | `Result<String>` |
236///
237/// ```
238/// use cbor_core::Value;
239///
240/// let v = Value::from("hello");
241/// assert_eq!(v.as_str().unwrap(), "hello");
242///
243/// // Modify in place
244/// let mut v = Value::from("hello");
245/// v.as_string_mut().unwrap().push_str(" world");
246/// assert_eq!(v.as_str().unwrap(), "hello world");
247/// ```
248///
249/// ## Arrays
250///
251/// Arrays are stored as `Vec<Value>`. Use [`as_array`](Self::as_array)
252/// to borrow the elements as a slice, or [`as_array_mut`](Self::as_array_mut)
253/// to modify them in place.
254///
255/// | Method | Returns |
256/// |---|---|
257/// | [`as_array`](Self::as_array) | `Result<&[Value]>` |
258/// | [`as_array_mut`](Self::as_array_mut) | `Result<&mut Vec<Value>>` |
259/// | [`into_array`](Self::into_array) | `Result<Vec<Value>>` |
260///
261/// ```
262/// use cbor_core::{Value, array};
263///
264/// let v = array![10, 20, 30];
265/// let items = v.as_array().unwrap();
266/// assert_eq!(items[1].to_u32().unwrap(), 20);
267///
268/// // Modify in place
269/// let mut v = array![1, 2];
270/// v.as_array_mut().unwrap().push(3.into());
271/// assert_eq!(v.as_array().unwrap().len(), 3);
272/// ```
273///
274/// ## Maps
275///
276/// Maps are stored as `BTreeMap<Value, Value>`, giving canonical key
277/// order. Use standard `BTreeMap` methods on the result of
278/// [`as_map`](Self::as_map) to look up entries.
279///
280/// | Method | Returns |
281/// |---|---|
282/// | [`as_map`](Self::as_map) | `Result<&BTreeMap<Value, Value>>` |
283/// | [`as_map_mut`](Self::as_map_mut) | `Result<&mut BTreeMap<Value, Value>>` |
284/// | [`into_map`](Self::into_map) | `Result<BTreeMap<Value, Value>>` |
285///
286/// ```
287/// use cbor_core::{Value, map};
288///
289/// let v = map! { "name" => "Alice", "age" => 30 };
290/// assert_eq!(v["name"].as_str().unwrap(), "Alice");
291///
292/// // Modify in place
293/// let mut v = map! { "count" => 1 };
294/// v.as_map_mut().unwrap().insert("count".into(), 2.into());
295/// assert_eq!(v["count"].to_u32().unwrap(), 2);
296/// ```
297///
298/// ## Indexing
299///
300/// Arrays and maps support `Index` and `IndexMut` with any type that
301/// converts into `Value`. For arrays the index is converted to `usize`;
302/// for maps it is used as a key lookup. Panics on type mismatch or
303/// missing key, just like `Vec` and `BTreeMap`.
304///
305/// ```
306/// use cbor_core::{Value, array, map};
307///
308/// let a = array![10, 20, 30];
309/// assert_eq!(a[1].to_u32().unwrap(), 20);
310///
311/// let m = map! { "x" => 10, "y" => 20 };
312/// assert_eq!(m["x"].to_u32().unwrap(), 10);
313/// ```
314///
315/// ## Tags
316///
317/// A tag wraps another value with a numeric label (e.g. tag 1 for epoch
318/// timestamps, tag 32 for URIs). Tags can be nested.
319///
320/// | Method | Returns | Notes |
321/// |---|---|---|
322/// | [`tag_number`](Self::tag_number) | `Result<u64>` | Tag number |
323/// | [`tag_content`](Self::tag_content) | `Result<&Value>` | Borrowed content |
324/// | [`tag_content_mut`](Self::tag_content_mut) | `Result<&mut Value>` | Mutable content |
325/// | [`as_tag`](Self::as_tag) | `Result<(u64, &Value)>` | Both parts |
326/// | [`as_tag_mut`](Self::as_tag_mut) | `Result<(u64, &mut Value)>` | Mutable content |
327/// | [`into_tag`](Self::into_tag) | `Result<(u64, Value)>` | Consuming |
328///
329/// Use [`untagged`](Self::untagged) to look through tags without removing
330/// them, [`remove_tag`](Self::remove_tag) to strip the outermost tag, or
331/// [`remove_all_tags`](Self::remove_all_tags) to strip all layers at once.
332///
333/// ```
334/// use cbor_core::Value;
335///
336/// // Create a tagged value (tag 32 = URI)
337/// let mut uri = Value::tag(32, "https://example.com");
338///
339/// // Inspect
340/// let (tag_num, content) = uri.as_tag().unwrap();
341/// assert_eq!(tag_num, 32);
342/// assert_eq!(content.as_str().unwrap(), "https://example.com");
343///
344/// // Look through tags without removing them
345/// assert_eq!(uri.untagged().as_str().unwrap(), "https://example.com");
346///
347/// // Strip the tag in place
348/// let removed = uri.remove_tag();
349/// assert_eq!(removed, Some(32));
350/// assert_eq!(uri.as_str().unwrap(), "https://example.com");
351/// ```
352///
353/// Accessor methods see through tags transparently: calling `as_str()`
354/// on a tagged text string works without manually unwrapping the tag
355/// first. This applies to all accessors (`to_*`, `as_*`, `into_*`).
356///
357/// ```
358/// use cbor_core::Value;
359///
360/// let uri = Value::tag(32, "https://example.com");
361/// assert_eq!(uri.as_str().unwrap(), "https://example.com");
362///
363/// // Nested tags are also transparent
364/// let nested = Value::tag(100, Value::tag(200, 42));
365/// assert_eq!(nested.to_u32().unwrap(), 42);
366/// ```
367///
368/// Big integers are internally represented as tagged byte strings
369/// (tags 2 and 3). The integer accessors recognise these tags and
370/// decode the bytes automatically, even when wrapped in additional
371/// custom tags. Byte-level accessors like `as_bytes()` also see
372/// through tags, so calling `as_bytes()` on a big integer returns
373/// the raw payload bytes.
374///
375/// If a tag is removed via `remove_tag`, `remove_all_tags`, or by
376/// consuming through `into_tag`, the value becomes a plain byte
377/// string and can no longer be read as an integer.
378///
379/// # Type introspection
380///
381/// [`data_type`](Self::data_type) returns a [`DataType`] enum for
382/// lightweight type checks without matching on the full enum.
383///
384/// ```
385/// use cbor_core::Value;
386///
387/// let v = Value::from(3.14);
388/// assert!(v.data_type().is_float());
389/// ```
390#[derive(Clone)]
391pub enum Value {
392 /// Simple value such as `null`, `true`, or `false` (major type 7).
393 ///
394 /// In CBOR, booleans and null are simple values, not distinct types.
395 /// A `Value::from(true)` is stored as `SimpleValue(21)` and is
396 /// accessible through both [`to_bool`](Self::to_bool) and
397 /// [`to_simple_value`](Self::to_simple_value).
398 SimpleValue(SimpleValue),
399
400 /// Unsigned integer (major type 0). Stores values 0 through 2^64-1.
401 Unsigned(u64),
402
403 /// Negative integer (major type 1). The actual value is -1 - n,
404 /// covering -1 through -2^64.
405 Negative(u64),
406
407 /// IEEE 754 floating-point number (major type 7, additional info 25-27).
408 Float(Float),
409
410 /// Byte string (major type 2).
411 ByteString(Vec<u8>),
412
413 /// UTF-8 text string (major type 3).
414 TextString(String),
415
416 /// Array of data items (major type 4).
417 Array(Vec<Value>),
418
419 /// Map of key-value pairs in canonical order (major type 5).
420 Map(BTreeMap<Value, Value>),
421
422 /// Tagged data item (major type 6). The first field is the tag number,
423 /// the second is the enclosed content.
424 Tag(u64, Box<Value>),
425}
426
427// --- CBOR::Core diagnostic notation (Section 2.3.6) ---
428//
429// `Debug` outputs diagnostic notation. The `#` (alternate/pretty) flag
430// enables multi-line output for arrays and maps with indentation.
431impl fmt::Debug for Value {
432 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
433 match self {
434 Self::SimpleValue(sv) => match *sv {
435 SimpleValue::FALSE => f.write_str("false"),
436 SimpleValue::TRUE => f.write_str("true"),
437 SimpleValue::NULL => f.write_str("null"),
438 other => write!(f, "simple({})", other.0),
439 },
440
441 Self::Unsigned(n) => write!(f, "{n}"),
442
443 Self::Negative(n) => write!(f, "{actual}", actual = -i128::from(*n) - 1),
444
445 Self::Float(float) => {
446 let value = float.to_f64();
447 if value.is_nan() {
448 use crate::float::Inner;
449 match float.0 {
450 Inner::F16(0x7e00) => f.write_str("NaN"), // Default NaN is the canonical f16 quiet NaN (f97e00)
451 Inner::F16(bits) => write!(f, "float'{bits:04x}'"),
452 Inner::F32(bits) => write!(f, "float'{bits:08x}'"),
453 Inner::F64(bits) => write!(f, "float'{bits:016x}'"),
454 }
455 } else if value.is_infinite() {
456 if value.is_sign_positive() {
457 f.write_str("Infinity")
458 } else {
459 f.write_str("-Infinity")
460 }
461 } else {
462 let s = format!("{value}");
463 f.write_str(&s)?;
464 if !s.contains('.') && !s.contains('e') && !s.contains('E') {
465 f.write_str(".0")?; // ensure a decimal point is present
466 }
467 Ok(())
468 }
469 }
470
471 Self::ByteString(bytes) => {
472 f.write_str("h'")?;
473 for b in bytes {
474 write!(f, "{b:02x}")?;
475 }
476 f.write_str("'")
477 }
478
479 Self::TextString(s) => {
480 f.write_str("\"")?;
481 for c in s.chars() {
482 match c {
483 '"' => f.write_str("\\\"")?,
484 '\\' => f.write_str("\\\\")?,
485 '\u{08}' => f.write_str("\\b")?,
486 '\u{0C}' => f.write_str("\\f")?,
487 '\n' => f.write_str("\\n")?,
488 '\r' => f.write_str("\\r")?,
489 '\t' => f.write_str("\\t")?,
490 c if c.is_control() => write!(f, "\\u{:04x}", c as u32)?,
491 c => write!(f, "{c}")?,
492 }
493 }
494 f.write_str("\"")
495 }
496
497 Self::Array(items) => {
498 let mut list = f.debug_list();
499 for item in items {
500 list.entry(item);
501 }
502 list.finish()
503 }
504
505 Self::Map(map) => {
506 let mut m = f.debug_map();
507 for (key, value) in map {
508 m.entry(key, value);
509 }
510 m.finish()
511 }
512
513 Self::Tag(tag, content) => {
514 // Big integers: show as decimal when they fit in i128/u128
515 if self.data_type().is_integer() {
516 if let Ok(n) = self.to_u128() {
517 return write!(f, "{n}");
518 }
519 if let Ok(n) = self.to_i128() {
520 return write!(f, "{n}");
521 }
522 }
523
524 if f.alternate() {
525 write!(f, "{tag}({content:#?})")
526 } else {
527 write!(f, "{tag}({content:?})")
528 }
529 }
530 }
531 }
532}
533
534impl Value {
535 /// Take the value out, leaving `null` in its place.
536 ///
537 /// ```
538 /// use cbor_core::Value;
539 ///
540 /// let mut v = Value::from(42);
541 /// let taken = v.take();
542 /// assert_eq!(taken.to_u32().unwrap(), 42);
543 /// assert!(v.data_type().is_null());
544 /// ```
545 pub fn take(&mut self) -> Self {
546 std::mem::take(self)
547 }
548
549 /// Replace the value, returning the old one.
550 ///
551 /// ```
552 /// use cbor_core::Value;
553 ///
554 /// let mut v = Value::from("hello");
555 /// let old = v.replace(Value::from("world"));
556 /// assert_eq!(old.as_str().unwrap(), "hello");
557 /// assert_eq!(v.as_str().unwrap(), "world");
558 /// ```
559 pub fn replace(&mut self, value: Self) -> Self {
560 std::mem::replace(self, value)
561 }
562
563 /// Encode this value to binary CBOR bytes.
564 ///
565 /// This is a convenience wrapper around [`write_to`](Self::write_to).
566 ///
567 /// ```
568 /// use cbor_core::Value;
569 /// let bytes = Value::from(42).encode();
570 /// assert_eq!(bytes, [0x18, 42]);
571 /// ```
572 #[must_use]
573 pub fn encode(&self) -> Vec<u8> {
574 let len = self.cbor_len();
575 let mut bytes = Vec::with_capacity(len);
576 self.write_to(&mut bytes).unwrap();
577 debug_assert_eq!(bytes.len(), len);
578 bytes
579 }
580
581 /// Encode this value to a hex-encoded CBOR string.
582 ///
583 /// This is a convenience wrapper around [`write_hex_to`](Self::write_hex_to).
584 ///
585 /// ```
586 /// use cbor_core::Value;
587 /// let hex = Value::from(42).encode_hex();
588 /// assert_eq!(hex, "182a");
589 /// ```
590 #[must_use]
591 pub fn encode_hex(&self) -> String {
592 let len2 = self.cbor_len() * 2;
593 let mut hex = Vec::with_capacity(len2);
594 self.write_hex_to(&mut hex).unwrap();
595 debug_assert_eq!(hex.len(), len2);
596 String::from_utf8(hex).unwrap()
597 }
598
599 /// Decode a CBOR data item from binary bytes.
600 ///
601 /// Accepts any byte source (`&[u8]`, `&str`, `String`, `Vec<u8>`, etc.).
602 /// Returns `Err` if the encoding is not canonical.
603 ///
604 /// This is a convenience wrapper around [`read_from`](Self::read_from).
605 ///
606 /// ```
607 /// use cbor_core::Value;
608 /// let v = Value::decode([0x18, 42]).unwrap();
609 /// assert_eq!(v.to_u32().unwrap(), 42);
610 /// ```
611 pub fn decode(bytes: impl AsRef<[u8]>) -> crate::Result<Self> {
612 let mut bytes = bytes.as_ref();
613 Self::read_from(&mut bytes).map_err(|error| match error {
614 crate::IoError::Io(_io_error) => unreachable!(),
615 crate::IoError::Data(error) => error,
616 })
617 }
618
619 /// Decode a CBOR data item from hex-encoded bytes.
620 ///
621 /// Accepts any byte source (`&[u8]`, `&str`, `String`, `Vec<u8>`, etc.).
622 /// Both uppercase and lowercase hex digits are accepted.
623 /// Returns `Err` if the encoding is not canonical.
624 ///
625 /// This is a convenience wrapper around [`read_hex_from`](Self::read_hex_from).
626 ///
627 /// ```
628 /// use cbor_core::Value;
629 /// let v = Value::decode_hex("182a").unwrap();
630 /// assert_eq!(v.to_u32().unwrap(), 42);
631 /// ```
632 pub fn decode_hex(hex: impl AsRef<[u8]>) -> Result<Self> {
633 let mut bytes = hex.as_ref();
634 Self::read_hex_from(&mut bytes).map_err(|error| match error {
635 crate::IoError::Io(_io_error) => unreachable!(),
636 crate::IoError::Data(error) => error,
637 })
638 }
639
640 /// Read a single CBOR data item from a binary stream.
641 ///
642 /// ```
643 /// use cbor_core::Value;
644 /// let mut bytes: &[u8] = &[0x18, 42];
645 /// let v = Value::read_from(&mut bytes).unwrap();
646 /// assert_eq!(v.to_u32().unwrap(), 42);
647 /// ```
648 pub fn read_from(mut reader: impl io::Read) -> crate::IoResult<Self> {
649 Self::read_from_inner(&mut reader, RECURSION_LIMIT, OOM_MITIGATION)
650 }
651
652 fn read_from_inner(
653 reader: &mut impl io::Read,
654 recursion_limit: u16,
655 oom_mitigation: usize,
656 ) -> crate::IoResult<Self> {
657 let ctrl_byte = {
658 let mut buf = [0];
659 reader.read_exact(&mut buf)?;
660 buf[0]
661 };
662
663 let is_float = matches!(ctrl_byte, CtrlByte::F16 | CtrlByte::F32 | CtrlByte::F64);
664
665 let major = ctrl_byte >> 5;
666 let info = ctrl_byte & 0x1f;
667
668 let argument = {
669 let mut buf = [0; 8];
670
671 if info < ArgLength::U8 {
672 buf[7] = info;
673 } else {
674 match info {
675 ArgLength::U8 => reader.read_exact(&mut buf[7..])?,
676 ArgLength::U16 => reader.read_exact(&mut buf[6..])?,
677 ArgLength::U32 => reader.read_exact(&mut buf[4..])?,
678 ArgLength::U64 => reader.read_exact(&mut buf)?,
679 _ => return Error::Malformed.into(),
680 }
681 }
682
683 u64::from_be_bytes(buf)
684 };
685
686 if !is_float {
687 let non_deterministic = match info {
688 ArgLength::U8 => argument < u64::from(ArgLength::U8),
689 ArgLength::U16 => argument <= u64::from(u8::MAX),
690 ArgLength::U32 => argument <= u64::from(u16::MAX),
691 ArgLength::U64 => argument <= u64::from(u32::MAX),
692 _ => false,
693 };
694
695 if non_deterministic {
696 return Error::NonDeterministic.into();
697 }
698 }
699
700 let this = match major {
701 Major::UNSIGNED => Self::Unsigned(argument),
702 Major::NEGATIVE => Self::Negative(argument),
703
704 Major::BYTE_STRING => Self::ByteString(read_vec(reader, argument)?),
705
706 Major::TEXT_STRING => {
707 let bytes = read_vec(reader, argument)?;
708 let string = String::from_utf8(bytes)?;
709 Self::TextString(string)
710 }
711
712 Major::ARRAY => {
713 if argument > LENGTH_LIMIT {
714 return Error::LengthTooLarge.into();
715 }
716
717 let Some(recursion_limit) = recursion_limit.checked_sub(1) else {
718 return Error::LengthTooLarge.into();
719 };
720
721 let request: usize = argument.try_into().or(Err(Error::LengthTooLarge))?;
722 let granted = request.min(oom_mitigation / size_of::<Self>());
723 let oom_mitigation = oom_mitigation - granted * size_of::<Self>();
724
725 let mut vec = Vec::with_capacity(granted);
726
727 for _ in 0..argument {
728 vec.push(Self::read_from_inner(reader, recursion_limit, oom_mitigation)?);
729 }
730
731 Self::Array(vec)
732 }
733
734 Major::MAP => {
735 if argument > LENGTH_LIMIT {
736 return Error::LengthTooLarge.into();
737 }
738
739 let Some(recursion_limit) = recursion_limit.checked_sub(1) else {
740 return Error::LengthTooLarge.into();
741 };
742
743 let mut map = BTreeMap::new();
744 let mut prev = None;
745
746 for _ in 0..argument {
747 let key = Self::read_from_inner(reader, recursion_limit, oom_mitigation)?;
748 let value = Self::read_from_inner(reader, recursion_limit, oom_mitigation)?;
749
750 if let Some((prev_key, prev_value)) = prev.take() {
751 if prev_key >= key {
752 return Error::NonDeterministic.into();
753 }
754 map.insert(prev_key, prev_value);
755 }
756
757 prev = Some((key, value));
758 }
759
760 if let Some((key, value)) = prev.take() {
761 map.insert(key, value);
762 }
763
764 Self::Map(map)
765 }
766
767 Major::TAG => {
768 let Some(recursion_limit) = recursion_limit.checked_sub(1) else {
769 return Error::LengthTooLarge.into();
770 };
771
772 let content = Box::new(Self::read_from_inner(reader, recursion_limit, oom_mitigation)?);
773
774 // check if conforming bigint
775 if matches!(argument, Tag::POS_BIG_INT | Tag::NEG_BIG_INT)
776 && let Ok(bigint) = content.as_bytes()
777 {
778 let valid = bigint.len() >= 8 && bigint[0] != 0;
779 if !valid {
780 return Error::NonDeterministic.into();
781 }
782 }
783
784 Self::Tag(argument, content)
785 }
786
787 Major::SIMPLE_VALUE => match info {
788 0..ArgLength::U8 => Self::SimpleValue(SimpleValue(argument as u8)),
789 ArgLength::U8 if argument >= 32 => Self::SimpleValue(SimpleValue(argument as u8)),
790
791 ArgLength::U16 => Self::Float(Float::from_u16(argument as u16)),
792 ArgLength::U32 => Self::Float(Float::from_u32(argument as u32)?),
793 ArgLength::U64 => Self::Float(Float::from_u64(argument)?),
794
795 _ => return Error::Malformed.into(),
796 },
797
798 _ => unreachable!(),
799 };
800
801 Ok(this)
802 }
803
804 /// Read a single CBOR data item from a hex-encoded stream.
805 ///
806 /// Each byte of CBOR is expected as two hex digits (uppercase or
807 /// lowercase).
808 ///
809 /// ```
810 /// use cbor_core::Value;
811 /// let mut hex = "182a".as_bytes();
812 /// let v = Value::read_hex_from(&mut hex).unwrap();
813 /// assert_eq!(v.to_u32().unwrap(), 42);
814 /// ```
815 pub fn read_hex_from(reader: impl io::Read) -> crate::IoResult<Self> {
816 struct HexReader<R>(R, Option<Error>);
817
818 impl<R: io::Read> io::Read for HexReader<R> {
819 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
820 fn nibble(char: u8) -> Option<u8> {
821 match char {
822 b'0'..=b'9' => Some(char - b'0'),
823 b'a'..=b'f' => Some(char - b'a' + 10),
824 b'A'..=b'F' => Some(char - b'A' + 10),
825 _ => None,
826 }
827 }
828
829 for byte in buf.iter_mut() {
830 let mut hex = [0; 2];
831 self.0.read_exact(&mut hex)?;
832
833 if let Some(n0) = nibble(hex[0])
834 && let Some(n1) = nibble(hex[1])
835 {
836 *byte = n0 << 4 | n1
837 } else {
838 self.1 = Some(Error::InvalidHex);
839 return Err(io::Error::other("invalid hex character"));
840 }
841 }
842
843 Ok(buf.len())
844 }
845 }
846
847 let mut hex_reader = HexReader(reader, None);
848 let result = Self::read_from_inner(&mut hex_reader, RECURSION_LIMIT, OOM_MITIGATION);
849
850 if let Some(error) = hex_reader.1 {
851 error.into()
852 } else {
853 result
854 }
855 }
856
857 /// Write this value as binary CBOR to a stream.
858 ///
859 /// ```
860 /// use cbor_core::Value;
861 /// let mut buf = Vec::new();
862 /// Value::from(42).write_to(&mut buf).unwrap();
863 /// assert_eq!(buf, [0x18, 42]);
864 /// ```
865 pub fn write_to(&self, mut writer: impl io::Write) -> crate::IoResult<()> {
866 self.write_to_inner(&mut writer)
867 }
868
869 fn write_to_inner(&self, writer: &mut impl io::Write) -> crate::IoResult<()> {
870 let major = self.cbor_major();
871 let (info, argument) = self.cbor_argument();
872
873 let ctrl_byte = major << 5 | info;
874 writer.write_all(&[ctrl_byte])?;
875
876 let buf = argument.to_be_bytes();
877 match info {
878 ArgLength::U8 => writer.write_all(&buf[7..])?,
879 ArgLength::U16 => writer.write_all(&buf[6..])?,
880 ArgLength::U32 => writer.write_all(&buf[4..])?,
881 ArgLength::U64 => writer.write_all(&buf)?,
882 _ => (), // argument embedded in ctrl byte
883 }
884
885 match self {
886 Value::ByteString(bytes) => writer.write_all(bytes)?,
887 Value::TextString(string) => writer.write_all(string.as_bytes())?,
888
889 Value::Tag(_number, content) => content.write_to_inner(writer)?,
890
891 Value::Array(values) => {
892 for value in values {
893 value.write_to_inner(writer)?;
894 }
895 }
896
897 Value::Map(map) => {
898 for (key, value) in map {
899 key.write_to_inner(writer)?;
900 value.write_to_inner(writer)?;
901 }
902 }
903
904 _ => (),
905 }
906
907 Ok(())
908 }
909
910 /// Write this value as hex-encoded CBOR to a stream.
911 ///
912 /// Each binary byte is written as two lowercase hex digits. The
913 /// adapter encodes on the fly without buffering the full output.
914 ///
915 /// ```
916 /// use cbor_core::Value;
917 /// let mut buf = Vec::new();
918 /// Value::from(42).write_hex_to(&mut buf).unwrap();
919 /// assert_eq!(buf, b"182a");
920 /// ```
921 pub fn write_hex_to(&self, writer: impl io::Write) -> crate::IoResult<()> {
922 struct HexWriter<W>(W);
923
924 impl<W: io::Write> io::Write for HexWriter<W> {
925 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
926 for &byte in buf {
927 write!(self.0, "{byte:02x}")?;
928 }
929 Ok(buf.len())
930 }
931 fn flush(&mut self) -> io::Result<()> {
932 Ok(())
933 }
934 }
935
936 self.write_to_inner(&mut HexWriter(writer))
937 }
938
939 fn cbor_major(&self) -> u8 {
940 match self {
941 Value::Unsigned(_) => Major::UNSIGNED,
942 Value::Negative(_) => Major::NEGATIVE,
943 Value::ByteString(_) => Major::BYTE_STRING,
944 Value::TextString(_) => Major::TEXT_STRING,
945 Value::Array(_) => Major::ARRAY,
946 Value::Map(_) => Major::MAP,
947 Value::Tag(_, _) => Major::TAG,
948 Value::SimpleValue(_) => Major::SIMPLE_VALUE,
949 Value::Float(_) => Major::SIMPLE_VALUE,
950 }
951 }
952
953 fn cbor_argument(&self) -> (u8, u64) {
954 fn arg(value: u64) -> (u8, u64) {
955 if value < u64::from(ArgLength::U8) {
956 (value as u8, value)
957 } else {
958 let info = match value {
959 0x00..=0xFF => ArgLength::U8,
960 0x100..=0xFFFF => ArgLength::U16,
961 0x10000..=0xFFFF_FFFF => ArgLength::U32,
962 _ => ArgLength::U64,
963 };
964 (info, value)
965 }
966 }
967
968 match self {
969 Value::Unsigned(value) => arg(*value),
970 Value::Negative(value) => arg(*value),
971 Value::ByteString(vec) => arg(vec.len().try_into().unwrap()),
972 Value::TextString(str) => arg(str.len().try_into().unwrap()),
973 Value::Array(vec) => arg(vec.len().try_into().unwrap()),
974 Value::Map(map) => arg(map.len().try_into().unwrap()),
975 Value::Tag(number, _) => arg(*number),
976 Value::SimpleValue(value) => arg(value.0.into()),
977 Value::Float(float) => float.cbor_argument(),
978 }
979 }
980
981 /// Encoded length
982 fn cbor_len(&self) -> usize {
983 let (info, _) = self.cbor_argument();
984
985 let header_len = match info {
986 0..ArgLength::U8 => 1,
987 ArgLength::U8 => 2,
988 ArgLength::U16 => 3,
989 ArgLength::U32 => 5,
990 ArgLength::U64 => 9,
991 _ => unreachable!(),
992 };
993
994 let data_len = match self {
995 Self::ByteString(bytes) => bytes.len(),
996 Self::TextString(text) => text.len(),
997 Self::Array(vec) => vec.iter().map(Self::cbor_len).sum(),
998 Self::Map(map) => map.iter().map(|(k, v)| k.cbor_len() + v.cbor_len()).sum(),
999 Self::Tag(_, content) => content.cbor_len(),
1000 _ => 0,
1001 };
1002
1003 header_len + data_len
1004 }
1005
1006 // ------------------- constructors -------------------
1007
1008 /// Create a CBOR null value.
1009 #[must_use]
1010 pub const fn null() -> Self {
1011 Self::SimpleValue(SimpleValue::NULL)
1012 }
1013
1014 /// Create a CBOR simple value.
1015 ///
1016 /// # Panics
1017 ///
1018 /// Panics if the value is in the reserved range 24-31.
1019 /// Use [`SimpleValue::from_u8`] for a fallible alternative.
1020 pub fn simple_value(value: impl TryInto<SimpleValue>) -> Self {
1021 match value.try_into() {
1022 Ok(sv) => Self::SimpleValue(sv),
1023 Err(_) => panic!("Invalid simple value"),
1024 }
1025 }
1026
1027 /// Create a CBOR date/time string value (tag 0).
1028 ///
1029 /// Accepts `&str`, `String`, and [`SystemTime`] via the
1030 /// [`DateTime`] helper. The date must be within
1031 /// `0001-01-01T00:00:00Z` to `9999-12-31T23:59:59Z`.
1032 ///
1033 /// # Panics
1034 ///
1035 /// Panics if the input is not a valid RFC 3339 (ISO 8601 profile)
1036 /// UTC timestamp or is out of range.
1037 ///
1038 /// ```
1039 /// use cbor_core::{DataType, Value};
1040 ///
1041 /// let v = Value::date_time("2000-01-01T00:00:00.000Z");
1042 /// assert_eq!(v.data_type(), DataType::DateTime);
1043 /// assert_eq!(v.as_str(), Ok("2000-01-01T00:00:00.000Z"));
1044 ///
1045 /// use std::time::SystemTime;
1046 /// let v = Value::date_time(SystemTime::UNIX_EPOCH);
1047 /// assert_eq!(v.data_type(), DataType::DateTime);
1048 /// assert_eq!(v.as_str(), Ok("1970-01-01T00:00:00Z"));
1049 /// ```
1050 pub fn date_time(value: impl TryInto<DateTime>) -> Self {
1051 match value.try_into() {
1052 Ok(dt) => dt.into(),
1053 Err(_) => panic!("Invalid date/time"),
1054 }
1055 }
1056
1057 /// Create a CBOR epoch time value (tag 1).
1058 ///
1059 /// Accepts integers, floats, and [`SystemTime`] via the
1060 /// [`EpochTime`] helper. The value must be in the range 0 to
1061 /// 253402300799.
1062 ///
1063 /// # Panics
1064 ///
1065 /// Panics if the value is out of range or negative.
1066 ///
1067 /// ```
1068 /// use std::time::{Duration, UNIX_EPOCH};
1069 /// use cbor_core::Value;
1070 ///
1071 /// let v = Value::epoch_time(1_000_000);
1072 /// assert_eq!(v.to_system_time(), Ok(UNIX_EPOCH + Duration::from_secs(1_000_000)));
1073 /// ```
1074 pub fn epoch_time(value: impl TryInto<EpochTime>) -> Self {
1075 match value.try_into() {
1076 Ok(et) => et.into(),
1077 Err(_) => panic!("Invalid epoch time"),
1078 }
1079 }
1080
1081 /// Create a CBOR float.
1082 ///
1083 /// Via the [`Float`] type floats can be created out of integers and booleans too.
1084 ///
1085 /// ```
1086 /// use cbor_core::Value;
1087 ///
1088 /// let f1 = Value::float(1.0);
1089 /// assert!(f1.to_f64() == Ok(1.0));
1090 ///
1091 /// let f2 = Value::float(2);
1092 /// assert!(f2.to_f64() == Ok(2.0));
1093 ///
1094 /// let f3 = Value::float(true);
1095 /// assert!(f3.to_f64() == Ok(1.0));
1096 /// ```
1097 ///
1098 /// The value is stored in the shortest IEEE 754 form (f16, f32,
1099 /// or f64) that preserves it exactly.
1100 pub fn float(value: impl Into<Float>) -> Self {
1101 Self::Float(value.into())
1102 }
1103
1104 /// Create a CBOR array.
1105 ///
1106 /// Accepts any type that converts into [`Array`], including
1107 /// `Vec<T>`, `[T; N]`, `&[T]`, and `Box<[T]>` where `T: Into<Value>`.
1108 /// See [`Array`] for the full list of accepted types.
1109 ///
1110 /// ```
1111 /// # use cbor_core::Value;
1112 /// let a = Value::array([1, 2, 3]);
1113 /// assert_eq!(a.as_array().unwrap().len(), 3);
1114 /// ```
1115 pub fn array(array: impl Into<Array>) -> Self {
1116 Self::Array(array.into().0)
1117 }
1118
1119 /// Create a CBOR map. Keys are stored in canonical order.
1120 ///
1121 /// Accepts any type that converts into [`Map`], including
1122 /// `BTreeMap`, `&HashMap`, `Vec<(K, V)>`, `[(K, V); N]`, and
1123 /// `&[(K, V)]`. See [`Map`] for the full list of accepted types.
1124 ///
1125 /// ```
1126 /// # use cbor_core::Value;
1127 /// let m = Value::map([("x", 1), ("y", 2)]);
1128 /// assert_eq!(m.as_map().unwrap().len(), 2);
1129 /// ```
1130 pub fn map(map: impl Into<Map>) -> Self {
1131 Self::Map(map.into().0)
1132 }
1133
1134 /// Wrap a value with a CBOR tag.
1135 ///
1136 /// ```
1137 /// use cbor_core::Value;
1138 /// let uri = Value::tag(32, "https://example.com");
1139 /// assert_eq!(uri.tag_number().unwrap(), 32);
1140 /// ```
1141 pub fn tag(number: u64, content: impl Into<Value>) -> Self {
1142 Self::Tag(number, Box::new(content.into()))
1143 }
1144
1145 /// Return the [`DataType`] of this value for type-level dispatch.
1146 #[must_use]
1147 pub const fn data_type(&self) -> DataType {
1148 match self {
1149 Self::SimpleValue(sv) => sv.data_type(),
1150
1151 Self::Unsigned(_) | Self::Negative(_) => DataType::Int,
1152
1153 Self::Float(float) => float.data_type(),
1154
1155 Self::TextString(_) => DataType::Text,
1156 Self::ByteString(_) => DataType::Bytes,
1157
1158 Self::Array(_) => DataType::Array,
1159 Self::Map(_) => DataType::Map,
1160
1161 Self::Tag(Tag::DATE_TIME, content) if content.data_type().is_text() => DataType::DateTime,
1162 Self::Tag(Tag::EPOCH_TIME, content) if content.data_type().is_numeric() => DataType::EpochTime,
1163
1164 Self::Tag(Tag::POS_BIG_INT | Tag::NEG_BIG_INT, content) if content.data_type().is_bytes() => {
1165 DataType::BigInt
1166 }
1167
1168 Self::Tag(_, _) => DataType::Tag,
1169 }
1170 }
1171
1172 /// Internal shortcut helper
1173 pub(crate) const fn is_bytes(&self) -> bool {
1174 self.data_type().is_bytes()
1175 }
1176
1177 /// Extract a boolean. Returns `Err` for non-boolean values.
1178 pub const fn to_bool(&self) -> Result<bool> {
1179 match self {
1180 Self::SimpleValue(sv) => sv.to_bool(),
1181 Self::Tag(_number, content) => content.untagged().to_bool(),
1182 _ => Err(Error::IncompatibleType(self.data_type())),
1183 }
1184 }
1185
1186 /// Extract the raw simple value number (0-255, excluding 24-31).
1187 pub const fn to_simple_value(&self) -> Result<u8> {
1188 match self {
1189 Self::SimpleValue(sv) => Ok(sv.0),
1190 Self::Tag(_number, content) => content.untagged().to_simple_value(),
1191 _ => Err(Error::IncompatibleType(self.data_type())),
1192 }
1193 }
1194
1195 fn to_uint<T>(&self) -> Result<T>
1196 where
1197 T: TryFrom<u64> + TryFrom<u128>,
1198 {
1199 match self {
1200 Self::Unsigned(x) => T::try_from(*x).or(Err(Error::Overflow)),
1201 Self::Negative(_) => Err(Error::NegativeUnsigned),
1202
1203 Self::Tag(Tag::POS_BIG_INT, content) if content.is_bytes() => {
1204 T::try_from(u128_from_slice(self.as_bytes()?)?).or(Err(Error::Overflow))
1205 }
1206
1207 Self::Tag(Tag::NEG_BIG_INT, content) if content.is_bytes() => Err(Error::NegativeUnsigned),
1208 Self::Tag(_other_number, content) => content.peeled().to_uint(),
1209 _ => Err(Error::IncompatibleType(self.data_type())),
1210 }
1211 }
1212
1213 /// Narrow to `u8`. Returns `Err(Overflow)` or `Err(NegativeUnsigned)` on mismatch.
1214 pub fn to_u8(&self) -> Result<u8> {
1215 self.to_uint()
1216 }
1217
1218 /// Narrow to `u16`.
1219 pub fn to_u16(&self) -> Result<u16> {
1220 self.to_uint()
1221 }
1222
1223 /// Narrow to `u32`.
1224 pub fn to_u32(&self) -> Result<u32> {
1225 self.to_uint()
1226 }
1227
1228 /// Narrow to `u64`.
1229 pub fn to_u64(&self) -> Result<u64> {
1230 self.to_uint()
1231 }
1232
1233 /// Narrow to `u128`. Handles big integers (tag 2) transparently.
1234 pub fn to_u128(&self) -> Result<u128> {
1235 self.to_uint()
1236 }
1237
1238 /// Narrow to `usize`.
1239 pub fn to_usize(&self) -> Result<usize> {
1240 self.to_uint()
1241 }
1242
1243 #[allow(dead_code)]
1244 pub(crate) fn as_integer_bytes(&self) -> Result<IntegerBytes<'_>> {
1245 match self {
1246 Self::Unsigned(x) => Ok(IntegerBytes::UnsignedOwned(x.to_be_bytes())),
1247 Self::Negative(x) => Ok(IntegerBytes::NegativeOwned(x.to_be_bytes())),
1248
1249 Self::Tag(Tag::POS_BIG_INT, content) if content.is_bytes() => {
1250 Ok(IntegerBytes::UnsignedBorrowed(content.as_bytes()?))
1251 }
1252
1253 Self::Tag(Tag::NEG_BIG_INT, content) if content.is_bytes() => {
1254 Ok(IntegerBytes::NegativeBorrowed(content.as_bytes()?))
1255 }
1256
1257 Self::Tag(_other_number, content) => content.peeled().as_integer_bytes(),
1258 _ => Err(Error::IncompatibleType(self.data_type())),
1259 }
1260 }
1261
1262 fn to_sint<T>(&self) -> Result<T>
1263 where
1264 T: TryFrom<u64> + TryFrom<u128> + std::ops::Not<Output = T>,
1265 {
1266 match self {
1267 Self::Unsigned(x) => T::try_from(*x).or(Err(Error::Overflow)),
1268 Self::Negative(x) => T::try_from(*x).map(T::not).or(Err(Error::Overflow)),
1269
1270 Self::Tag(Tag::POS_BIG_INT, content) if content.is_bytes() => {
1271 T::try_from(u128_from_slice(self.as_bytes()?)?).or(Err(Error::Overflow))
1272 }
1273
1274 Self::Tag(Tag::NEG_BIG_INT, content) if content.is_bytes() => {
1275 T::try_from(u128_from_slice(self.as_bytes()?)?)
1276 .map(T::not)
1277 .or(Err(Error::Overflow))
1278 }
1279
1280 Self::Tag(_other_number, content) => content.peeled().to_sint(),
1281 _ => Err(Error::IncompatibleType(self.data_type())),
1282 }
1283 }
1284
1285 /// Narrow to `i8`.
1286 pub fn to_i8(&self) -> Result<i8> {
1287 self.to_sint()
1288 }
1289
1290 /// Narrow to `i16`.
1291 pub fn to_i16(&self) -> Result<i16> {
1292 self.to_sint()
1293 }
1294
1295 /// Narrow to `i32`.
1296 pub fn to_i32(&self) -> Result<i32> {
1297 self.to_sint()
1298 }
1299
1300 /// Narrow to `i64`.
1301 pub fn to_i64(&self) -> Result<i64> {
1302 self.to_sint()
1303 }
1304
1305 /// Narrow to `i128`. Handles big integers (tags 2 and 3) transparently.
1306 pub fn to_i128(&self) -> Result<i128> {
1307 self.to_sint()
1308 }
1309
1310 /// Narrow to `isize`.
1311 pub fn to_isize(&self) -> Result<isize> {
1312 self.to_sint()
1313 }
1314
1315 /// Convert to `f32`.
1316 ///
1317 /// Returns `Err(Precision)` for f64-width values.
1318 pub fn to_f32(&self) -> Result<f32> {
1319 match self {
1320 Self::Float(float) => float.to_f32(),
1321 Self::Tag(_number, content) => content.untagged().to_f32(),
1322 _ => Err(Error::IncompatibleType(self.data_type())),
1323 }
1324 }
1325
1326 /// Convert to `f64`.
1327 ///
1328 /// Always succeeds for float values.
1329 pub fn to_f64(&self) -> Result<f64> {
1330 match self {
1331 Self::Float(float) => Ok(float.to_f64()),
1332 Self::Tag(_number, content) => content.untagged().to_f64(),
1333 _ => Err(Error::IncompatibleType(self.data_type())),
1334 }
1335 }
1336
1337 /// Convert a time value to [`SystemTime`].
1338 ///
1339 /// Accepts date/time strings (tag 0), epoch time values (tag 1),
1340 /// and untagged integers or floats. Numeric values must be
1341 /// non-negative and in the range 0 to 253402300799. Date/time
1342 /// strings may include a timezone offset, which is converted to
1343 /// UTC.
1344 ///
1345 /// Returns `Err(IncompatibleType)` for values that are neither
1346 /// numeric nor text, `Err(InvalidValue)` if a numeric value is out of
1347 /// range, and `Err(InvalidFormat)` if a text string is not a
1348 /// valid RFC 3339 timestamp. Leap seconds (`:60`) are rejected
1349 /// because [`SystemTime`] cannot represent them.
1350 ///
1351 /// ```
1352 /// use std::time::{Duration, UNIX_EPOCH};
1353 /// use cbor_core::Value;
1354 ///
1355 /// let v = Value::tag(1, 1_000_000);
1356 /// let t = v.to_system_time().unwrap();
1357 /// assert_eq!(t, UNIX_EPOCH + Duration::from_secs(1_000_000));
1358 /// ```
1359 pub fn to_system_time(&self) -> Result<SystemTime> {
1360 if let Ok(s) = self.as_str() {
1361 Ok(s.parse::<crate::iso3339::Timestamp>()?.try_into()?)
1362 } else if let Ok(f) = self.to_f64() {
1363 if f.is_finite() && (0.0..=253402300799.0).contains(&f) {
1364 Ok(SystemTime::UNIX_EPOCH + Duration::from_secs_f64(f))
1365 } else {
1366 Err(Error::InvalidValue)
1367 }
1368 } else {
1369 match self.to_u64() {
1370 Ok(secs) if secs <= 253402300799 => Ok(SystemTime::UNIX_EPOCH + Duration::from_secs(secs)),
1371 Ok(_) | Err(Error::NegativeUnsigned) => Err(Error::InvalidValue),
1372 Err(error) => Err(error),
1373 }
1374 }
1375 }
1376
1377 /// Borrow the byte string as a slice.
1378 pub fn as_bytes(&self) -> Result<&[u8]> {
1379 match self {
1380 Self::ByteString(vec) => Ok(vec.as_slice()),
1381 Self::Tag(_number, content) => content.untagged().as_bytes(),
1382 _ => Err(Error::IncompatibleType(self.data_type())),
1383 }
1384 }
1385
1386 /// Borrow the byte string as a mutable `Vec`.
1387 pub const fn as_bytes_mut(&mut self) -> Result<&mut Vec<u8>> {
1388 match self {
1389 Self::ByteString(vec) => Ok(vec),
1390 Self::Tag(_number, content) => content.untagged_mut().as_bytes_mut(),
1391 _ => Err(Error::IncompatibleType(self.data_type())),
1392 }
1393 }
1394
1395 /// Take ownership of the byte string.
1396 pub fn into_bytes(self) -> Result<Vec<u8>> {
1397 match self {
1398 Self::ByteString(vec) => Ok(vec),
1399 Self::Tag(_number, content) => content.into_untagged().into_bytes(),
1400 _ => Err(Error::IncompatibleType(self.data_type())),
1401 }
1402 }
1403
1404 /// Borrow the text string as a `&str`.
1405 pub fn as_str(&self) -> Result<&str> {
1406 match self {
1407 Self::TextString(s) => Ok(s.as_str()),
1408 Self::Tag(_number, content) => content.untagged().as_str(),
1409 _ => Err(Error::IncompatibleType(self.data_type())),
1410 }
1411 }
1412
1413 /// Borrow the text string as a mutable `String`.
1414 pub const fn as_string_mut(&mut self) -> Result<&mut String> {
1415 match self {
1416 Self::TextString(s) => Ok(s),
1417 Self::Tag(_number, content) => content.untagged_mut().as_string_mut(),
1418 _ => Err(Error::IncompatibleType(self.data_type())),
1419 }
1420 }
1421
1422 /// Take ownership of the text string.
1423 pub fn into_string(self) -> Result<String> {
1424 match self {
1425 Self::TextString(s) => Ok(s),
1426 Self::Tag(_number, content) => content.into_untagged().into_string(),
1427 _ => Err(Error::IncompatibleType(self.data_type())),
1428 }
1429 }
1430
1431 /// Borrow the array elements as a slice.
1432 pub fn as_array(&self) -> Result<&[Value]> {
1433 match self {
1434 Self::Array(v) => Ok(v.as_slice()),
1435 Self::Tag(_number, content) => content.untagged().as_array(),
1436 _ => Err(Error::IncompatibleType(self.data_type())),
1437 }
1438 }
1439
1440 /// Borrow the array as a mutable `Vec`.
1441 pub const fn as_array_mut(&mut self) -> Result<&mut Vec<Value>> {
1442 match self {
1443 Self::Array(v) => Ok(v),
1444 Self::Tag(_number, content) => content.untagged_mut().as_array_mut(),
1445 _ => Err(Error::IncompatibleType(self.data_type())),
1446 }
1447 }
1448
1449 /// Take ownership of the array.
1450 pub fn into_array(self) -> Result<Vec<Value>> {
1451 match self {
1452 Self::Array(v) => Ok(v),
1453 Self::Tag(_number, content) => content.into_untagged().into_array(),
1454 _ => Err(Error::IncompatibleType(self.data_type())),
1455 }
1456 }
1457
1458 /// Borrow the map.
1459 pub const fn as_map(&self) -> Result<&BTreeMap<Value, Value>> {
1460 match self {
1461 Self::Map(m) => Ok(m),
1462 Self::Tag(_number, content) => content.untagged().as_map(),
1463 _ => Err(Error::IncompatibleType(self.data_type())),
1464 }
1465 }
1466
1467 /// Borrow the map mutably.
1468 pub const fn as_map_mut(&mut self) -> Result<&mut BTreeMap<Value, Value>> {
1469 match self {
1470 Self::Map(m) => Ok(m),
1471 Self::Tag(_number, content) => content.untagged_mut().as_map_mut(),
1472 _ => Err(Error::IncompatibleType(self.data_type())),
1473 }
1474 }
1475
1476 /// Take ownership of the map.
1477 pub fn into_map(self) -> Result<BTreeMap<Value, Value>> {
1478 match self {
1479 Self::Map(m) => Ok(m),
1480 Self::Tag(_number, content) => content.into_untagged().into_map(),
1481 _ => Err(Error::IncompatibleType(self.data_type())),
1482 }
1483 }
1484
1485 // --------------- Index access ---------------
1486
1487 /// Look up an element by index (arrays) or key (maps).
1488 ///
1489 /// Returns `None` if the value is not an array or map, the index
1490 /// is out of bounds, or the key is missing.
1491 ///
1492 /// ```
1493 /// use cbor_core::{Value, array, map};
1494 ///
1495 /// let a = array![10, 20, 30];
1496 /// assert_eq!(a.get(1).unwrap().to_u32().unwrap(), 20);
1497 /// assert!(a.get(5).is_none());
1498 ///
1499 /// let m = map! { "x" => 10 };
1500 /// assert_eq!(m.get("x").unwrap().to_u32().unwrap(), 10);
1501 /// assert!(m.get("missing").is_none());
1502 /// ```
1503 pub fn get(&self, index: impl Into<Value>) -> Option<&Value> {
1504 let key = index.into();
1505 match self.untagged() {
1506 Value::Array(arr) => key.to_usize().ok().and_then(|i| arr.get(i)),
1507 Value::Map(map) => map.get(&key),
1508 _ => None,
1509 }
1510 }
1511
1512 /// Mutable version of [`get`](Self::get).
1513 ///
1514 /// ```
1515 /// use cbor_core::{Value, array};
1516 ///
1517 /// let mut a = array![10, 20, 30];
1518 /// *a.get_mut(1).unwrap() = Value::from(99);
1519 /// assert_eq!(a[1].to_u32().unwrap(), 99);
1520 /// ```
1521 pub fn get_mut(&mut self, index: impl Into<Value>) -> Option<&mut Value> {
1522 let key = index.into();
1523 match self.untagged_mut() {
1524 Value::Array(arr) => key.to_usize().ok().and_then(|i| arr.get_mut(i)),
1525 Value::Map(map) => map.get_mut(&key),
1526 _ => None,
1527 }
1528 }
1529
1530 // ------------------- Tags ------------------
1531
1532 /// Return the tag number.
1533 pub const fn tag_number(&self) -> Result<u64> {
1534 match self {
1535 Self::Tag(number, _content) => Ok(*number),
1536 _ => Err(Error::IncompatibleType(self.data_type())),
1537 }
1538 }
1539
1540 /// Borrow the tag content.
1541 pub const fn tag_content(&self) -> Result<&Self> {
1542 match self {
1543 Self::Tag(_tag, content) => Ok(content),
1544 _ => Err(Error::IncompatibleType(self.data_type())),
1545 }
1546 }
1547
1548 /// Mutably borrow the tag content.
1549 pub const fn tag_content_mut(&mut self) -> Result<&mut Self> {
1550 match self {
1551 Self::Tag(_, value) => Ok(value),
1552 _ => Err(Error::IncompatibleType(self.data_type())),
1553 }
1554 }
1555
1556 /// Borrow tag number and content together.
1557 pub fn as_tag(&self) -> Result<(u64, &Value)> {
1558 match self {
1559 Self::Tag(number, content) => Ok((*number, content)),
1560 _ => Err(Error::IncompatibleType(self.data_type())),
1561 }
1562 }
1563
1564 /// Borrow tag number and mutable content together.
1565 pub fn as_tag_mut(&mut self) -> Result<(u64, &mut Value)> {
1566 match self {
1567 Self::Tag(number, content) => Ok((*number, content)),
1568 _ => Err(Error::IncompatibleType(self.data_type())),
1569 }
1570 }
1571
1572 /// Consume self and return tag number and content.
1573 pub fn into_tag(self) -> Result<(u64, Value)> {
1574 match self {
1575 Self::Tag(number, content) => Ok((number, *content)),
1576 _ => Err(Error::IncompatibleType(self.data_type())),
1577 }
1578 }
1579
1580 /// Remove the outermost tag, returning its number. Returns `None` if
1581 /// the value is not tagged.
1582 pub fn remove_tag(&mut self) -> Option<u64> {
1583 let mut result = None;
1584 if let Self::Tag(number, content) = self {
1585 result = Some(*number);
1586 *self = std::mem::take(content);
1587 }
1588 result
1589 }
1590
1591 /// Remove all nested tags, returning their numbers from outermost to
1592 /// innermost.
1593 pub fn remove_all_tags(&mut self) -> Vec<u64> {
1594 let mut tags = Vec::new();
1595 while let Self::Tag(number, content) = self {
1596 tags.push(*number);
1597 *self = std::mem::take(content);
1598 }
1599 tags
1600 }
1601
1602 /// Skip all tag wrappers except the innermost one.
1603 /// Returns `self` unchanged if not tagged or only single-tagged.
1604 #[must_use]
1605 pub(crate) const fn peeled(&self) -> &Self {
1606 let mut result = self;
1607 while let Self::Tag(_, content) = result
1608 && content.data_type().is_tag()
1609 {
1610 result = content;
1611 }
1612 result
1613 }
1614
1615 /// Borrow the innermost non-tag value, skipping all tag wrappers.
1616 #[must_use]
1617 pub const fn untagged(&self) -> &Self {
1618 let mut result = self;
1619 while let Self::Tag(_, content) = result {
1620 result = content;
1621 }
1622 result
1623 }
1624
1625 /// Mutable version of [`untagged`](Self::untagged).
1626 pub const fn untagged_mut(&mut self) -> &mut Self {
1627 let mut result = self;
1628 while let Self::Tag(_, content) = result {
1629 result = content;
1630 }
1631 result
1632 }
1633
1634 /// Consuming version of [`untagged`](Self::untagged).
1635 #[must_use]
1636 pub fn into_untagged(mut self) -> Self {
1637 while let Self::Tag(_number, content) = self {
1638 self = *content;
1639 }
1640 self
1641 }
1642}
1643
1644// -------------------- Helpers --------------------
1645
1646fn read_vec(reader: &mut impl io::Read, len: u64) -> crate::IoResult<Vec<u8>> {
1647 use io::Read;
1648
1649 if len > LENGTH_LIMIT {
1650 return Error::LengthTooLarge.into();
1651 }
1652
1653 let len_usize = usize::try_from(len).or(Err(Error::LengthTooLarge))?;
1654 let mut buf = Vec::with_capacity(len_usize.min(OOM_MITIGATION)); // Mitigate OOM
1655 let bytes_read = reader.take(len).read_to_end(&mut buf)?;
1656
1657 if bytes_read == len_usize {
1658 Ok(buf)
1659 } else {
1660 Error::UnexpectedEof.into()
1661 }
1662}