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