Skip to main content

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}