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