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!`](crate::array) and [`map!`](crate::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)`](Value::new) 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>`](crate::Result), yielding [`Err(Error::IncompatibleType)`](Error::IncompatibleType)
175/// on a 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>`](crate::Result) | Raw simple value number |
196/// | [`to_bool`](Self::to_bool) | [`Result<bool>`](crate::Result) | 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)`](Error::Overflow)
219/// if the value does not fit, or [`Err(NegativeUnsigned)`](Error::NegativeUnsigned)
220/// when extracting a 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>`](crate::Result) |
225/// | [`to_i8`](Self::to_i8) .. [`to_i128`](Self::to_i128), [`to_isize`](Self::to_isize) | [`Result<iN>`](crate::Result) |
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)`](Error::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>`](crate::Result) (fails for f64 values) |
252/// | [`to_f64`](Self::to_f64) | [`Result<f64>`](crate::Result) |
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()`](Self::as_bytes)
520/// also see through tags, so calling [`as_bytes()`](Self::as_bytes)
521/// on a big integer returns the raw payload bytes.
522///
523/// If a tag is removed via [`remove_tag`](Self::remove_tag),
524/// [`remove_all_tags`](Self::remove_all_tags), or by consuming through
525/// [`into_tag`](Self::into_tag), the value becomes a plain byte
526/// string and can no longer be read as an integer.
527///
528/// # Type introspection
529///
530/// [`data_type`](Self::data_type) returns a [`DataType`] enum for
531/// lightweight type checks without matching on the full enum.
532///
533/// ```
534/// use cbor_core::Value;
535///
536/// let v = Value::from(3.14);
537/// assert!(v.data_type().is_float());
538/// ```
539#[derive(Clone)]
540pub enum Value {
541 /// Simple value such as `null`, `true`, or `false` (major type 7).
542 ///
543 /// In CBOR, booleans and null are simple values, not distinct types.
544 /// A `Value::from(true)` is stored as `SimpleValue(21)` and is
545 /// accessible through both [`to_bool`](Self::to_bool) and
546 /// [`to_simple_value`](Self::to_simple_value).
547 ///
548 /// ```
549 /// # use cbor_core::Value;
550 /// let sv = Value::null();
551 /// assert!(sv.data_type().is_simple_value() && sv.data_type().is_null());
552 ///
553 /// let sv = Value::new(false);
554 /// assert!(sv.data_type().is_simple_value() && sv.data_type().is_bool());
555 /// ```
556 SimpleValue(SimpleValue),
557
558 /// Unsigned integer (major type 0). Stores values 0 through 2^64-1.
559 ///
560 /// ```
561 /// # use cbor_core::Value;
562 /// let v = Value::new(42);
563 /// # assert!(v.data_type().is_integer());
564 /// ```
565 Unsigned(u64),
566
567 /// Negative integer (major type 1). The actual value is -1 - n,
568 /// covering -1 through -2^64.
569 ///
570 /// ```
571 /// # use cbor_core::Value;
572 /// let v = Value::new(-42);
573 /// # assert!(v.data_type().is_integer());
574 /// ```
575 Negative(u64),
576
577 /// IEEE 754 floating-point number (major type 7, additional info 25-27).
578 ///
579 /// ```
580 /// # use cbor_core::Value;
581 /// let v = Value::new(1.234);
582 /// # assert!(v.data_type().is_float());
583 /// ```
584 Float(Float),
585
586 /// Byte string (major type 2).
587 ///
588 /// ```
589 /// # use cbor_core::Value;
590 /// let v = Value::new(b"this is a byte string");
591 /// # assert!(v.data_type().is_bytes());
592 /// ```
593 ByteString(Vec<u8>),
594
595 /// UTF-8 text string (major type 3).
596 ///
597 /// ```
598 /// # use cbor_core::Value;
599 /// let v = Value::new("Rust + CBOR::Core");
600 /// # assert!(v.data_type().is_text());
601 /// ```
602 TextString(String),
603
604 /// Array of data items (major type 4).
605 ///
606 /// ```
607 /// use cbor_core::array;
608 /// let v = array![1, 2, 3, "text", b"bytes", true, 1.234, array![4,5,6]];
609 /// # assert!(v.data_type().is_array());
610 /// ```
611 Array(Vec<Value>),
612
613 /// Map of key-value pairs in canonical order (major type 5).
614 ///
615 /// ```
616 /// use cbor_core::{map, array};
617 /// let v = map!{"answer" => 42, array![1,2,3] => "arrays as keys" };
618 /// # assert!(v.data_type().is_map());
619 /// ```
620 Map(BTreeMap<Value, Value>),
621
622 /// Tagged data item (major type 6). The first field is the tag number,
623 /// the second is the enclosed content.
624 ///
625 /// ```
626 /// # use cbor_core::Value;
627 /// let v = Value::tag(0, "1955-11-12T22:04:00-08:00");
628 /// # assert!(v.data_type().is_tag());
629 /// ```
630 Tag(u64, Box<Value>),
631}
632
633impl Default for Value {
634 fn default() -> Self {
635 Self::null()
636 }
637}
638
639impl From<()> for Value {
640 fn from(_: ()) -> Self {
641 Value::null()
642 }
643}
644
645/// Constructors
646impl Value {
647 /// Create a CBOR null value.
648 ///
649 /// In CBOR, null is the simple value 22.
650 ///
651 /// ```
652 /// use cbor_core::Value;
653 ///
654 /// let v = Value::null();
655 /// assert!(v.data_type().is_null());
656 /// assert!(v.data_type().is_simple_value());
657 /// assert_eq!(v.to_simple_value(), Ok(22));
658 /// ```
659 #[must_use]
660 pub const fn null() -> Self {
661 Self::SimpleValue(SimpleValue::NULL)
662 }
663
664 /// Create a CBOR simple value. Usable in `const` context.
665 ///
666 /// # Panics
667 ///
668 /// Panics if the value is in the reserved range 24-31.
669 /// Use [`SimpleValue::from_u8`] for a fallible alternative.
670 ///
671 /// ```
672 /// use cbor_core::Value;
673 ///
674 /// const V: Value = Value::simple_value(42);
675 /// assert_eq!(V.to_simple_value(), Ok(42));
676 /// ```
677 #[must_use]
678 pub const fn simple_value(value: u8) -> Self {
679 match SimpleValue::from_u8(value) {
680 Ok(sv) => Self::SimpleValue(sv),
681 Err(_) => panic!("Invalid simple value"),
682 }
683 }
684
685 /// Create a boolean `Value`, usable in `const` context.
686 ///
687 /// `const` counterpart of `Value::from(value)` for booleans. In CBOR,
688 /// `false` is simple value 20 and `true` is simple value 21.
689 ///
690 /// ```
691 /// use cbor_core::Value;
692 ///
693 /// const T: Value = Value::from_bool(true);
694 /// assert_eq!(T.to_bool(), Ok(true));
695 /// ```
696 #[must_use]
697 pub const fn from_bool(value: bool) -> Self {
698 Self::SimpleValue(SimpleValue::from_bool(value))
699 }
700
701 /// Create an unsigned integer `Value`, usable in `const` context.
702 ///
703 /// `const` counterpart of `Value::from(value)` for unsigned integers.
704 /// Smaller widths (`u8`, `u16`, `u32`) are intentionally not provided
705 /// as separate constructors: the `as u64` widening is lossless and
706 /// the resulting `Value` is identical regardless of the source width.
707 ///
708 /// `u128` has no `const` constructor because values above `u64::MAX`
709 /// require the big-integer path, which allocates a tagged byte string.
710 ///
711 /// ```
712 /// use cbor_core::Value;
713 ///
714 /// const V: Value = Value::from_u64(42);
715 /// assert_eq!(V.to_u64(), Ok(42));
716 /// ```
717 #[must_use]
718 pub const fn from_u64(value: u64) -> Value {
719 Self::Unsigned(value)
720 }
721
722 /// Create a signed integer `Value`, usable in `const` context.
723 ///
724 /// `const` counterpart of `Value::from(value)` for signed integers.
725 /// Smaller widths (`i8`, `i16`, `i32`) are intentionally not provided
726 /// as separate constructors: the `as i64` widening is lossless and
727 /// the resulting `Value` is identical regardless of the source width.
728 ///
729 /// `i128` has no `const` constructor for the same reason as
730 /// [`from_u64`](Self::from_u64): out-of-`i64`-range values need the
731 /// big-integer path, which allocates.
732 ///
733 /// ```
734 /// use cbor_core::Value;
735 ///
736 /// const V: Value = Value::from_i64(-42);
737 /// assert_eq!(V.to_i64(), Ok(-42));
738 /// ```
739 #[must_use]
740 pub const fn from_i64(value: i64) -> Value {
741 if value >= 0 {
742 Self::Unsigned(value as u64)
743 } else {
744 Self::Negative((!value) as u64)
745 }
746 }
747
748 /// Create a float `Value` from `f32`, usable in `const` context.
749 ///
750 /// `const` counterpart of `Value::from(value)` for `f32`. NaN
751 /// payloads are preserved. The result is stored in the shortest
752 /// CBOR form (f16, f32, or f64) that represents the value exactly.
753 ///
754 /// Prefer this over `Value::from_f64(x as f64)` when `x` is already
755 /// an `f32`: the `as f64` cast is lossless, but routing through
756 /// `from_f32` is clearer about intent and preserves NaN payloads
757 /// without relying on hardware canonicalization.
758 ///
759 /// ```
760 /// use cbor_core::Value;
761 ///
762 /// const V: Value = Value::from_f32(1.0);
763 /// assert_eq!(V.to_f32(), Ok(1.0));
764 /// ```
765 #[must_use]
766 pub const fn from_f32(value: f32) -> Value {
767 Self::Float(Float::from_f32(value))
768 }
769
770 /// Create a float `Value` from `f64`, usable in `const` context.
771 ///
772 /// `const` counterpart of `Value::from(value)` for `f64`. The result
773 /// is stored in the shortest CBOR form (f16, f32, or f64) that
774 /// represents the value exactly, NaN payloads included.
775 ///
776 /// ```
777 /// use cbor_core::Value;
778 ///
779 /// const V: Value = Value::from_f64(1.5);
780 /// assert_eq!(V.to_f64(), Ok(1.5));
781 /// ```
782 #[must_use]
783 pub const fn from_f64(value: f64) -> Value {
784 Self::Float(Float::from_f64(value))
785 }
786
787 /// Create a non-finite float `Value` from a 53-bit payload, usable
788 /// in `const` context.
789 ///
790 /// Payloads encode the kind of non-finite float (Infinity, NaN) and
791 /// its signalling bits in a width-invariant layout. The typical use
792 /// is defining `const` sentinel values that signal application-level
793 /// conditions through NaN payloads. See [`Float::with_payload`] for
794 /// the payload layout and panic conditions.
795 ///
796 /// ```
797 /// use cbor_core::Value;
798 ///
799 /// const INF: Value = Value::from_payload(0);
800 /// assert!(INF.to_f64().unwrap().is_infinite());
801 /// ```
802 #[must_use]
803 pub const fn from_payload(payload: u64) -> Value {
804 Self::Float(Float::with_payload(payload))
805 }
806
807 /// Create a CBOR value, inferring the variant from the input type.
808 ///
809 /// Equivalent to `Value::try_from(value).unwrap()`.
810 ///
811 /// Not every CBOR variant is reachable this way. Use the dedicated
812 /// constructors for the remaining cases.
813 ///
814 /// Whether this can panic depends on which conversion the input
815 /// type provides:
816 ///
817 /// - Types with `impl From<T> for Value` never panic here. `From`
818 /// is infallible by contract, and the standard blanket
819 /// `impl<T, U: Into<T>> TryFrom<U> for T` routes through it
820 /// without introducing a failure case. For these types,
821 /// [`Value::from`] is the more direct spelling.
822 /// - Types with an explicit `impl TryFrom<T> for Value` (mainly
823 /// the date- and time-related ones) can fail. `Value::new`
824 /// unwraps the error and panics. Call `Value::try_from` instead
825 /// to handle it.
826 ///
827 /// # Panics
828 ///
829 /// Panics if the input cannot be converted into a CBOR value.
830 #[must_use]
831 pub fn new(value: impl TryInto<Value>) -> Self {
832 match value.try_into() {
833 Ok(value) => value,
834 Err(_) => panic!("Invalid CBOR value"),
835 }
836 }
837
838 /// Create a CBOR byte string (major type 2).
839 ///
840 /// Accepts anything that converts into `Vec<u8>`:
841 /// - owned `Vec<u8>`, borrowed `&[u8]` and fixed-size `[u8; N]` (copied)
842 /// - `Box<[u8]>`, and `Cow<'_, [u8]>`
843 ///
844 /// Owned inputs are moved without copying.
845 ///
846 /// ```
847 /// use cbor_core::Value;
848 ///
849 /// let v = Value::byte_string("ABC");
850 /// assert_eq!(v.as_bytes(), Ok([65, 66, 67].as_slice()));
851 /// ```
852 #[must_use]
853 pub fn byte_string(value: impl Into<Vec<u8>>) -> Self {
854 Self::ByteString(value.into())
855 }
856
857 /// Create a CBOR text string (major type 3).
858 ///
859 /// Accepts anything that converts into `String`:
860 /// - owned `String`, `&str` (copied), `Box<str>`
861 /// - `Cow<'_, str>`, and `char`.
862 ///
863 /// Owned inputs are moved without reallocating.
864 ///
865 /// ```
866 /// use cbor_core::Value;
867 ///
868 /// let v = Value::text_string('A'); // char
869 /// assert_eq!(v.as_str(), Ok("A")); // &str
870 /// ```
871 #[must_use]
872 pub fn text_string(value: impl Into<String>) -> Self {
873 Self::TextString(value.into())
874 }
875
876 /// Create a CBOR date/time string value (tag 0).
877 ///
878 /// Accepts `&str`, `String`, and [`SystemTime`] via the
879 /// [`DateTime`] helper.
880 ///
881 /// The date must be within
882 /// `0000-01-01T00:00:00Z` to `9999-12-31T23:59:59Z`.
883 ///
884 /// # Panics
885 ///
886 /// Panics if the input is not a valid RFC 3339 (ISO 8601 profile)
887 /// UTC timestamp or is out of range.
888 ///
889 /// ```
890 /// use cbor_core::{DataType, Value};
891 ///
892 /// let v = Value::date_time("2000-01-01T00:00:00.000+01:00");
893 /// assert!(v.data_type().is_date_time());
894 /// assert_eq!(v.as_str(), Ok("2000-01-01T00:00:00.000+01:00"));
895 ///
896 /// use std::time::SystemTime;
897 /// let v = Value::date_time(SystemTime::UNIX_EPOCH);
898 /// assert!(v.data_type().is_date_time());
899 /// assert_eq!(v.as_str(), Ok("1970-01-01T00:00:00Z"));
900 /// ```
901 #[must_use]
902 pub fn date_time(value: impl TryInto<DateTime>) -> Self {
903 match value.try_into() {
904 Ok(dt) => dt.into(),
905 Err(_) => panic!("Invalid date/time"),
906 }
907 }
908
909 /// Create a CBOR epoch time value (tag 1).
910 ///
911 /// Accepts integers, floats, and [`SystemTime`] via the
912 /// [`EpochTime`] helper. The value must be in the range 0 to
913 /// 253402300799.
914 ///
915 /// # Panics
916 ///
917 /// Panics if the value is out of range or negative.
918 ///
919 /// ```
920 /// use std::time::{Duration, UNIX_EPOCH};
921 /// use cbor_core::Value;
922 ///
923 /// let v = Value::epoch_time(1_000_000);
924 /// assert_eq!(v.to_system_time(), Ok(UNIX_EPOCH + Duration::from_secs(1_000_000)));
925 /// ```
926 #[must_use]
927 pub fn epoch_time(value: impl TryInto<EpochTime>) -> Self {
928 match value.try_into() {
929 Ok(et) => et.into(),
930 Err(_) => panic!("Invalid epoch time"),
931 }
932 }
933
934 /// Create a CBOR float.
935 ///
936 /// Via the [`Float`] type floats can be created out of integers and booleans too.
937 ///
938 /// ```
939 /// use cbor_core::Value;
940 ///
941 /// let f1 = Value::float(1.0);
942 /// assert!(f1.to_f64() == Ok(1.0));
943 ///
944 /// let f2 = Value::float(2);
945 /// assert!(f2.to_f64() == Ok(2.0));
946 ///
947 /// let f3 = Value::float(true);
948 /// assert!(f3.to_f64() == Ok(1.0));
949 /// ```
950 ///
951 /// The value is stored in the shortest IEEE 754 form (f16, f32,
952 /// or f64) that preserves it exactly.
953 #[must_use]
954 pub fn float(value: impl Into<Float>) -> Self {
955 Self::Float(value.into())
956 }
957
958 /// Create a CBOR array.
959 ///
960 /// Accepts any type that converts into [`Array`], including
961 /// `Vec<T>`, `[T; N]`, `&[T]`, and `Box<[T]>` where `T: Into<Value>`.
962 ///
963 /// See [`Array`] for the full list of accepted types.
964 ///
965 /// ```
966 /// # use cbor_core::Value;
967 /// let a = Value::array([1, 2, 3]);
968 /// assert_eq!(a.len(), Some(3));
969 /// ```
970 #[must_use]
971 pub fn array(array: impl Into<Array>) -> Self {
972 Self::Array(array.into().0)
973 }
974
975 /// Create a CBOR map. Keys are stored in canonical order.
976 ///
977 /// Accepts any type that converts into [`Map`], including
978 /// `BTreeMap`, `&HashMap`, `Vec<(K, V)>`, `[(K, V); N]`, and
979 /// `&[(K, V)]`.
980 ///
981 /// See [`Map`] for the full list of accepted types.
982 ///
983 /// ```
984 /// # use cbor_core::Value;
985 /// let m = Value::map([("x", 1), ("y", 2)]);
986 /// assert_eq!(m.len(), Some(2));
987 /// ```
988 #[must_use]
989 pub fn map(map: impl Into<Map>) -> Self {
990 Self::Map(map.into().0)
991 }
992
993 /// Wrap a value with a CBOR tag.
994 ///
995 /// ```
996 /// use cbor_core::Value;
997 /// let uri = Value::tag(32, "https://example.com");
998 /// assert_eq!(uri.tag_number().unwrap(), 32);
999 /// ```
1000 #[must_use]
1001 pub fn tag(number: u64, content: impl Into<Value>) -> Self {
1002 Self::Tag(number, Box::new(content.into()))
1003 }
1004}
1005
1006/// Decoding and reading
1007impl Value {
1008 /// Decode a CBOR data item from binary bytes.
1009 ///
1010 /// Accepts any byte source (`&[u8]`, `&str`, `String`, `Vec<u8>`,
1011 /// etc.). The input must contain **exactly one** CBOR item; any
1012 /// trailing bytes cause [`Error::InvalidFormat`](crate::Error::InvalidFormat).
1013 /// Use [`DecodeOptions::sequence_decoder`](crate::DecodeOptions::sequence_decoder) for
1014 /// CBOR sequences.
1015 ///
1016 /// Returns `Err` if the encoding is not canonical.
1017 ///
1018 /// ```
1019 /// use cbor_core::Value;
1020 /// let v = Value::decode([0x18, 42]).unwrap();
1021 /// assert_eq!(v.to_u32().unwrap(), 42);
1022 /// ```
1023 pub fn decode(bytes: impl AsRef<[u8]>) -> crate::Result<Self> {
1024 crate::DecodeOptions::new().decode(bytes)
1025 }
1026
1027 /// Decode a CBOR data item from hex-encoded bytes.
1028 ///
1029 /// Accepts any byte source (`&[u8]`, `&str`, `String`, `Vec<u8>`,
1030 /// etc.). Both uppercase and lowercase hex digits are accepted. The
1031 /// input must contain **exactly one** CBOR item; any trailing hex
1032 /// digits cause [`Error::InvalidFormat`](crate::Error::InvalidFormat).
1033 ///
1034 /// Returns `Err` if the encoding is not canonical.
1035 ///
1036 /// ```
1037 /// use cbor_core::Value;
1038 /// let v = Value::decode_hex("182a").unwrap();
1039 /// assert_eq!(v.to_u32().unwrap(), 42);
1040 /// ```
1041 pub fn decode_hex(hex: impl AsRef<[u8]>) -> Result<Self> {
1042 crate::DecodeOptions::new().format(crate::Format::Hex).decode(hex)
1043 }
1044
1045 /// Read a single CBOR data item from a binary stream.
1046 ///
1047 /// The reader is advanced only to the end of the item; any further
1048 /// bytes remain in the stream, so repeated calls pull successive
1049 /// items of a CBOR sequence.
1050 ///
1051 /// ```
1052 /// use cbor_core::Value;
1053 /// let mut bytes: &[u8] = &[0x18, 42];
1054 /// let v = Value::read_from(&mut bytes).unwrap();
1055 /// assert_eq!(v.to_u32().unwrap(), 42);
1056 /// ```
1057 pub fn read_from(reader: impl std::io::Read) -> crate::IoResult<Self> {
1058 crate::DecodeOptions::new().read_from(reader)
1059 }
1060
1061 /// Read a single CBOR data item from a hex-encoded stream.
1062 ///
1063 /// Each byte of CBOR is expected as two hex digits (uppercase or
1064 /// lowercase). The reader is advanced only to the end of the item;
1065 /// any further hex digits remain in the stream, so repeated calls
1066 /// pull successive items of a CBOR sequence.
1067 ///
1068 /// ```
1069 /// use cbor_core::Value;
1070 /// let mut hex = "182a".as_bytes();
1071 /// let v = Value::read_hex_from(&mut hex).unwrap();
1072 /// assert_eq!(v.to_u32().unwrap(), 42);
1073 /// ```
1074 pub fn read_hex_from(reader: impl std::io::Read) -> crate::IoResult<Self> {
1075 crate::DecodeOptions::new().format(crate::Format::Hex).read_from(reader)
1076 }
1077}
1078
1079/// Encoding and writing
1080impl Value {
1081 /// Encode this value to binary CBOR bytes.
1082 ///
1083 /// This is a convenience wrapper around [`write_to`](Self::write_to).
1084 ///
1085 /// ```
1086 /// use cbor_core::Value;
1087 /// let bytes = Value::from(42).encode();
1088 /// assert_eq!(bytes, [0x18, 42]);
1089 /// ```
1090 #[must_use]
1091 pub fn encode(&self) -> Vec<u8> {
1092 let len = self.encoded_len();
1093 let mut bytes = Vec::with_capacity(len);
1094 self.write_to(&mut bytes).unwrap();
1095 debug_assert_eq!(bytes.len(), len);
1096 bytes
1097 }
1098
1099 /// Encode this value to a hex-encoded CBOR string.
1100 ///
1101 /// This is a convenience wrapper around [`write_hex_to`](Self::write_hex_to).
1102 ///
1103 /// ```
1104 /// use cbor_core::Value;
1105 /// let hex = Value::from(42).encode_hex();
1106 /// assert_eq!(hex, "182a");
1107 /// ```
1108 #[must_use]
1109 pub fn encode_hex(&self) -> String {
1110 let len2 = self.encoded_len() * 2;
1111 let mut hex = Vec::with_capacity(len2);
1112 self.write_hex_to(&mut hex).unwrap();
1113 debug_assert_eq!(hex.len(), len2);
1114 String::from_utf8(hex).unwrap()
1115 }
1116
1117 /// Write this value as binary CBOR to a stream.
1118 ///
1119 /// ```
1120 /// use cbor_core::Value;
1121 /// let mut buf = Vec::new();
1122 /// Value::from(42).write_to(&mut buf).unwrap();
1123 /// assert_eq!(buf, [0x18, 42]);
1124 /// ```
1125 pub fn write_to(&self, mut writer: impl std::io::Write) -> std::io::Result<()> {
1126 self.do_write(&mut writer)
1127 }
1128
1129 /// Write this value as hex-encoded CBOR to a stream.
1130 ///
1131 /// Each binary byte is written as two lowercase hex digits. The
1132 /// adapter encodes on the fly without buffering the full output.
1133 ///
1134 /// ```
1135 /// use cbor_core::Value;
1136 /// let mut buf = Vec::new();
1137 /// Value::from(42).write_hex_to(&mut buf).unwrap();
1138 /// assert_eq!(buf, b"182a");
1139 /// ```
1140 pub fn write_hex_to(&self, writer: impl std::io::Write) -> std::io::Result<()> {
1141 struct HexWriter<W>(W);
1142
1143 impl<W: std::io::Write> std::io::Write for HexWriter<W> {
1144 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
1145 for &byte in buf {
1146 write!(self.0, "{byte:02x}")?;
1147 }
1148 Ok(buf.len())
1149 }
1150 fn flush(&mut self) -> std::io::Result<()> {
1151 Ok(())
1152 }
1153 }
1154
1155 self.do_write(&mut HexWriter(writer))
1156 }
1157
1158 fn do_write(&self, writer: &mut impl std::io::Write) -> std::io::Result<()> {
1159 self.head().write_to(writer)?;
1160
1161 match self {
1162 Value::ByteString(bytes) => writer.write_all(bytes)?,
1163 Value::TextString(string) => writer.write_all(string.as_bytes())?,
1164
1165 Value::Tag(_number, content) => content.do_write(writer)?,
1166
1167 Value::Array(values) => {
1168 for value in values {
1169 value.do_write(writer)?;
1170 }
1171 }
1172
1173 Value::Map(map) => {
1174 for (key, value) in map {
1175 key.do_write(writer)?;
1176 value.do_write(writer)?;
1177 }
1178 }
1179
1180 _ => (),
1181 }
1182
1183 Ok(())
1184 }
1185
1186 pub(crate) fn encoded_len(&self) -> usize {
1187 self.head().encoded_len() + self.payload().encoded_len()
1188 }
1189}
1190
1191impl ValueView for Value {
1192 fn head(&self) -> Head {
1193 match self {
1194 Value::SimpleValue(sv) => Head::from_u64(Major::SimpleOrFloat, sv.0.into()),
1195 Value::Unsigned(n) => Head::from_u64(Major::Unsigned, *n),
1196 Value::Negative(n) => Head::from_u64(Major::Negative, *n),
1197 Value::Float(float) => float.head(),
1198 Value::ByteString(bytes) => Head::from_usize(Major::ByteString, bytes.len()),
1199 Value::TextString(text) => Head::from_usize(Major::TextString, text.len()),
1200 Value::Array(vec) => Head::from_usize(Major::Array, vec.len()),
1201 Value::Map(map) => Head::from_usize(Major::Map, map.len()),
1202 Value::Tag(number, _content) => Head::from_u64(Major::Tag, *number),
1203 }
1204 }
1205
1206 fn payload(&self) -> Payload<'_> {
1207 match self {
1208 Value::SimpleValue(_) | Value::Unsigned(_) | Value::Negative(_) | Value::Float(_) => Payload::None,
1209 Value::ByteString(bytes) => Payload::Bytes(bytes),
1210 Value::TextString(text) => Payload::Text(text),
1211 Value::Array(arr) => Payload::Array(arr),
1212 Value::Map(map) => Payload::Map(map),
1213 Value::Tag(_, content) => Payload::TagContent(content),
1214 }
1215 }
1216}
1217
1218/// Misc
1219impl Value {
1220 /// Return the [`DataType`] of this value for type-level dispatch.
1221 #[must_use]
1222 pub const fn data_type(&self) -> DataType {
1223 match self {
1224 Self::SimpleValue(sv) => sv.data_type(),
1225
1226 Self::Unsigned(_) | Self::Negative(_) => DataType::Int,
1227
1228 Self::Float(float) => float.data_type(),
1229
1230 Self::TextString(_) => DataType::Text,
1231 Self::ByteString(_) => DataType::Bytes,
1232
1233 Self::Array(_) => DataType::Array,
1234 Self::Map(_) => DataType::Map,
1235
1236 Self::Tag(tag::DATE_TIME, content) if content.data_type().is_text() => DataType::DateTime,
1237 Self::Tag(tag::EPOCH_TIME, content) if content.data_type().is_numeric() => DataType::EpochTime,
1238
1239 Self::Tag(tag::POS_BIG_INT | tag::NEG_BIG_INT, content) if content.data_type().is_bytes() => {
1240 DataType::BigInt
1241 }
1242
1243 Self::Tag(_, _) => DataType::Tag,
1244 }
1245 }
1246
1247 // Internal shortcut helper
1248 const fn is_bytes(&self) -> bool {
1249 self.data_type().is_bytes()
1250 }
1251
1252 /// Take the value out, leaving `null` in its place.
1253 ///
1254 /// ```
1255 /// use cbor_core::Value;
1256 ///
1257 /// let mut v = Value::from(42);
1258 /// let taken = v.take();
1259 /// assert_eq!(taken.to_u32().unwrap(), 42);
1260 /// assert!(v.data_type().is_null());
1261 /// ```
1262 pub fn take(&mut self) -> Self {
1263 std::mem::take(self)
1264 }
1265
1266 /// Replace the value, returning the old one.
1267 ///
1268 /// ```
1269 /// use cbor_core::Value;
1270 ///
1271 /// let mut v = Value::from("hello");
1272 /// let old = v.replace(Value::from("world"));
1273 /// assert_eq!(old.as_str().unwrap(), "hello");
1274 /// assert_eq!(v.as_str().unwrap(), "world");
1275 /// ```
1276 pub fn replace(&mut self, value: Self) -> Self {
1277 std::mem::replace(self, value)
1278 }
1279}
1280
1281/// Scalar accessors
1282impl Value {
1283 /// Extract a boolean. Returns `Err` for non-boolean values.
1284 pub const fn to_bool(&self) -> Result<bool> {
1285 match self {
1286 Self::SimpleValue(sv) => sv.to_bool(),
1287 Self::Tag(_number, content) => content.untagged().to_bool(),
1288 _ => Err(Error::IncompatibleType(self.data_type())),
1289 }
1290 }
1291
1292 /// Extract the raw simple value number (0-255, excluding 24-31).
1293 pub const fn to_simple_value(&self) -> Result<u8> {
1294 match self {
1295 Self::SimpleValue(sv) => Ok(sv.0),
1296 Self::Tag(_number, content) => content.untagged().to_simple_value(),
1297 _ => Err(Error::IncompatibleType(self.data_type())),
1298 }
1299 }
1300
1301 fn to_uint<T>(&self) -> Result<T>
1302 where
1303 T: TryFrom<u64> + TryFrom<u128>,
1304 {
1305 match self {
1306 Self::Unsigned(x) => T::try_from(*x).or(Err(Error::Overflow)),
1307 Self::Negative(_) => Err(Error::NegativeUnsigned),
1308
1309 Self::Tag(tag::POS_BIG_INT, content) if content.is_bytes() => {
1310 T::try_from(u128_from_slice(self.as_bytes()?)?).or(Err(Error::Overflow))
1311 }
1312
1313 Self::Tag(tag::NEG_BIG_INT, content) if content.is_bytes() => Err(Error::NegativeUnsigned),
1314 Self::Tag(_other_number, content) => content.peeled().to_uint(),
1315 _ => Err(Error::IncompatibleType(self.data_type())),
1316 }
1317 }
1318
1319 /// Narrow to `u8`. Returns `Err(Overflow)` or `Err(NegativeUnsigned)` on mismatch.
1320 pub fn to_u8(&self) -> Result<u8> {
1321 self.to_uint()
1322 }
1323
1324 /// Narrow to `u16`.
1325 pub fn to_u16(&self) -> Result<u16> {
1326 self.to_uint()
1327 }
1328
1329 /// Narrow to `u32`.
1330 pub fn to_u32(&self) -> Result<u32> {
1331 self.to_uint()
1332 }
1333
1334 /// Narrow to `u64`.
1335 pub fn to_u64(&self) -> Result<u64> {
1336 self.to_uint()
1337 }
1338
1339 /// Narrow to `u128`. Handles big integers (tag 2) transparently.
1340 pub fn to_u128(&self) -> Result<u128> {
1341 self.to_uint()
1342 }
1343
1344 /// Narrow to `usize`.
1345 pub fn to_usize(&self) -> Result<usize> {
1346 self.to_uint()
1347 }
1348
1349 #[allow(dead_code)]
1350 pub(crate) fn as_integer_bytes(&self) -> Result<IntegerBytes<'_>> {
1351 match self {
1352 Self::Unsigned(x) => Ok(IntegerBytes::UnsignedOwned(x.to_be_bytes())),
1353 Self::Negative(x) => Ok(IntegerBytes::NegativeOwned(x.to_be_bytes())),
1354
1355 Self::Tag(tag::POS_BIG_INT, content) if content.is_bytes() => {
1356 Ok(IntegerBytes::UnsignedBorrowed(content.as_bytes()?))
1357 }
1358
1359 Self::Tag(tag::NEG_BIG_INT, content) if content.is_bytes() => {
1360 Ok(IntegerBytes::NegativeBorrowed(content.as_bytes()?))
1361 }
1362
1363 Self::Tag(_other_number, content) => content.peeled().as_integer_bytes(),
1364 _ => Err(Error::IncompatibleType(self.data_type())),
1365 }
1366 }
1367
1368 fn to_sint<T>(&self) -> Result<T>
1369 where
1370 T: TryFrom<u64> + TryFrom<u128> + std::ops::Not<Output = T>,
1371 {
1372 match self {
1373 Self::Unsigned(x) => T::try_from(*x).or(Err(Error::Overflow)),
1374 Self::Negative(x) => T::try_from(*x).map(T::not).or(Err(Error::Overflow)),
1375
1376 Self::Tag(tag::POS_BIG_INT, content) if content.is_bytes() => {
1377 T::try_from(u128_from_slice(self.as_bytes()?)?).or(Err(Error::Overflow))
1378 }
1379
1380 Self::Tag(tag::NEG_BIG_INT, content) if content.is_bytes() => {
1381 T::try_from(u128_from_slice(self.as_bytes()?)?)
1382 .map(T::not)
1383 .or(Err(Error::Overflow))
1384 }
1385
1386 Self::Tag(_other_number, content) => content.peeled().to_sint(),
1387 _ => Err(Error::IncompatibleType(self.data_type())),
1388 }
1389 }
1390
1391 /// Narrow to `i8`.
1392 pub fn to_i8(&self) -> Result<i8> {
1393 self.to_sint()
1394 }
1395
1396 /// Narrow to `i16`.
1397 pub fn to_i16(&self) -> Result<i16> {
1398 self.to_sint()
1399 }
1400
1401 /// Narrow to `i32`.
1402 pub fn to_i32(&self) -> Result<i32> {
1403 self.to_sint()
1404 }
1405
1406 /// Narrow to `i64`.
1407 pub fn to_i64(&self) -> Result<i64> {
1408 self.to_sint()
1409 }
1410
1411 /// Narrow to `i128`. Handles big integers (tags 2 and 3) transparently.
1412 pub fn to_i128(&self) -> Result<i128> {
1413 self.to_sint()
1414 }
1415
1416 /// Narrow to `isize`.
1417 pub fn to_isize(&self) -> Result<isize> {
1418 self.to_sint()
1419 }
1420
1421 /// Convert to `f32`.
1422 ///
1423 /// Returns `Err(Precision)` for f64-width values.
1424 pub fn to_f32(&self) -> Result<f32> {
1425 match self {
1426 Self::Float(float) => float.to_f32(),
1427 Self::Tag(_number, content) => content.untagged().to_f32(),
1428 _ => Err(Error::IncompatibleType(self.data_type())),
1429 }
1430 }
1431
1432 /// Convert to `f64`.
1433 ///
1434 /// Always succeeds for float values.
1435 pub fn to_f64(&self) -> Result<f64> {
1436 match self {
1437 Self::Float(float) => Ok(float.to_f64()),
1438 Self::Tag(_number, content) => content.untagged().to_f64(),
1439 _ => Err(Error::IncompatibleType(self.data_type())),
1440 }
1441 }
1442
1443 /// Convert a time value to [`SystemTime`].
1444 ///
1445 /// Accepts date/time strings (tag 0), epoch time values (tag 1),
1446 /// and untagged integers or floats. Numeric values must be
1447 /// non-negative and in the range 0 to 253402300799. Date/time
1448 /// strings may include a timezone offset, which is converted to
1449 /// UTC.
1450 ///
1451 /// Returns [`Err(IncompatibleType)`](Error::IncompatibleType) for
1452 /// values that are neither numeric nor text, [`Err(InvalidValue)`](Error::InvalidValue)
1453 /// if a numeric value is out of range, and [`Err(InvalidFormat)`](Error::InvalidFormat)
1454 /// if a text string is not a valid RFC 3339 timestamp. Leap seconds (`:60`) are rejected
1455 /// because [`SystemTime`] cannot represent them.
1456 ///
1457 /// ```
1458 /// use std::time::{Duration, UNIX_EPOCH};
1459 /// use cbor_core::Value;
1460 ///
1461 /// let v = Value::tag(1, 1_000_000);
1462 /// let t = v.to_system_time().unwrap();
1463 /// assert_eq!(t, UNIX_EPOCH + Duration::from_secs(1_000_000));
1464 /// ```
1465 pub fn to_system_time(&self) -> Result<SystemTime> {
1466 if let Ok(s) = self.as_str() {
1467 Ok(s.parse::<crate::iso3339::Timestamp>()?.try_into()?)
1468 } else if let Ok(f) = self.to_f64() {
1469 if f.is_finite() && (0.0..=253402300799.0).contains(&f) {
1470 Ok(SystemTime::UNIX_EPOCH + Duration::from_secs_f64(f))
1471 } else {
1472 Err(Error::InvalidValue)
1473 }
1474 } else {
1475 match self.to_u64() {
1476 Ok(secs) if secs <= 253402300799 => Ok(SystemTime::UNIX_EPOCH + Duration::from_secs(secs)),
1477 Ok(_) | Err(Error::NegativeUnsigned) => Err(Error::InvalidValue),
1478 Err(error) => Err(error),
1479 }
1480 }
1481 }
1482}
1483
1484/// Bytes and text strings
1485impl Value {
1486 /// Borrow the byte string as a slice.
1487 pub fn as_bytes(&self) -> Result<&[u8]> {
1488 match self {
1489 Self::ByteString(vec) => Ok(vec.as_slice()),
1490 Self::Tag(_number, content) => content.untagged().as_bytes(),
1491 _ => Err(Error::IncompatibleType(self.data_type())),
1492 }
1493 }
1494
1495 /// Borrow the byte string as a mutable `Vec`.
1496 pub const fn as_bytes_mut(&mut self) -> Result<&mut Vec<u8>> {
1497 match self {
1498 Self::ByteString(vec) => Ok(vec),
1499 Self::Tag(_number, content) => content.untagged_mut().as_bytes_mut(),
1500 _ => Err(Error::IncompatibleType(self.data_type())),
1501 }
1502 }
1503
1504 /// Take ownership of the byte string.
1505 pub fn into_bytes(self) -> Result<Vec<u8>> {
1506 match self {
1507 Self::ByteString(vec) => Ok(vec),
1508 Self::Tag(_number, content) => content.into_untagged().into_bytes(),
1509 _ => Err(Error::IncompatibleType(self.data_type())),
1510 }
1511 }
1512
1513 /// Borrow the text string as a `&str`.
1514 pub fn as_str(&self) -> Result<&str> {
1515 match self {
1516 Self::TextString(s) => Ok(s.as_str()),
1517 Self::Tag(_number, content) => content.untagged().as_str(),
1518 _ => Err(Error::IncompatibleType(self.data_type())),
1519 }
1520 }
1521
1522 /// Borrow the text string as a mutable `String`.
1523 pub const fn as_string_mut(&mut self) -> Result<&mut String> {
1524 match self {
1525 Self::TextString(s) => Ok(s),
1526 Self::Tag(_number, content) => content.untagged_mut().as_string_mut(),
1527 _ => Err(Error::IncompatibleType(self.data_type())),
1528 }
1529 }
1530
1531 /// Take ownership of the text string.
1532 pub fn into_string(self) -> Result<String> {
1533 match self {
1534 Self::TextString(s) => Ok(s),
1535 Self::Tag(_number, content) => content.into_untagged().into_string(),
1536 _ => Err(Error::IncompatibleType(self.data_type())),
1537 }
1538 }
1539}
1540
1541/// Arrays and maps
1542impl Value {
1543 /// Borrow the array elements as a slice.
1544 pub fn as_array(&self) -> Result<&[Value]> {
1545 match self {
1546 Self::Array(v) => Ok(v.as_slice()),
1547 Self::Tag(_number, content) => content.untagged().as_array(),
1548 _ => Err(Error::IncompatibleType(self.data_type())),
1549 }
1550 }
1551
1552 /// Borrow the array as a mutable `Vec`.
1553 pub const fn as_array_mut(&mut self) -> Result<&mut Vec<Value>> {
1554 match self {
1555 Self::Array(v) => Ok(v),
1556 Self::Tag(_number, content) => content.untagged_mut().as_array_mut(),
1557 _ => Err(Error::IncompatibleType(self.data_type())),
1558 }
1559 }
1560
1561 /// Take ownership of the array.
1562 pub fn into_array(self) -> Result<Vec<Value>> {
1563 match self {
1564 Self::Array(v) => Ok(v),
1565 Self::Tag(_number, content) => content.into_untagged().into_array(),
1566 _ => Err(Error::IncompatibleType(self.data_type())),
1567 }
1568 }
1569
1570 /// Borrow the map.
1571 pub const fn as_map(&self) -> Result<&BTreeMap<Value, Value>> {
1572 match self {
1573 Self::Map(m) => Ok(m),
1574 Self::Tag(_number, content) => content.untagged().as_map(),
1575 _ => Err(Error::IncompatibleType(self.data_type())),
1576 }
1577 }
1578
1579 /// Borrow the map mutably.
1580 pub const fn as_map_mut(&mut self) -> Result<&mut BTreeMap<Value, Value>> {
1581 match self {
1582 Self::Map(m) => Ok(m),
1583 Self::Tag(_number, content) => content.untagged_mut().as_map_mut(),
1584 _ => Err(Error::IncompatibleType(self.data_type())),
1585 }
1586 }
1587
1588 /// Take ownership of the map.
1589 pub fn into_map(self) -> Result<BTreeMap<Value, Value>> {
1590 match self {
1591 Self::Map(m) => Ok(m),
1592 Self::Tag(_number, content) => content.into_untagged().into_map(),
1593 _ => Err(Error::IncompatibleType(self.data_type())),
1594 }
1595 }
1596}
1597
1598/// Array and map helpers
1599impl Value {
1600 /// Look up an element by index (arrays) or key (maps).
1601 ///
1602 /// Accepts anything convertible into [`ValueKey`](crate::ValueKey):
1603 /// integers for array indices, and `&str`, `&[u8]`, integers, `&Value`,
1604 /// etc. for map keys. Transparent through tags.
1605 ///
1606 /// Returns `None` if the value is not an array or map, the index is
1607 /// out of bounds, the key is missing, or the key type does not match
1608 /// the collection (e.g. a string index into an array).
1609 ///
1610 /// ```
1611 /// use cbor_core::{Value, array, map};
1612 ///
1613 /// let a = array![10, 20, 30];
1614 /// assert_eq!(a.get(1).unwrap().to_u32().unwrap(), 20);
1615 /// assert!(a.get(5).is_none());
1616 ///
1617 /// let m = map! { "x" => 10 };
1618 /// assert_eq!(m.get("x").unwrap().to_u32().unwrap(), 10);
1619 /// assert!(m.get("missing").is_none());
1620 /// ```
1621 pub fn get<'a>(&self, index: impl Into<crate::ValueKey<'a>>) -> Option<&Value> {
1622 let key = index.into();
1623 match self.untagged() {
1624 Value::Array(arr) => key.to_usize().and_then(|idx| arr.get(idx)),
1625 Value::Map(map) => map.get(&key as &dyn ValueView),
1626 _ => None,
1627 }
1628 }
1629
1630 /// Mutable version of [`get`](Self::get).
1631 ///
1632 /// ```
1633 /// use cbor_core::{Value, array};
1634 ///
1635 /// let mut a = array![10, 20, 30];
1636 /// *a.get_mut(1).unwrap() = Value::from(99);
1637 /// assert_eq!(a[1].to_u32().unwrap(), 99);
1638 /// ```
1639 pub fn get_mut<'a>(&mut self, index: impl Into<crate::ValueKey<'a>>) -> Option<&mut Value> {
1640 let key = index.into();
1641 match self.untagged_mut() {
1642 Value::Array(arr) => key.to_usize().and_then(|idx| arr.get_mut(idx)),
1643 Value::Map(map) => map.get_mut(&key as &dyn ValueView),
1644 _ => None,
1645 }
1646 }
1647
1648 /// Remove and return an element by index (arrays) or key (maps).
1649 ///
1650 /// For **arrays**, shifts subsequent elements down like
1651 /// [`Vec::remove`] (O(n)) and returns the removed element. The key
1652 /// must be a valid `usize` index in range `0..len`; otherwise this
1653 /// method **panics**, matching [`Vec::remove`] and the indexing
1654 /// operator `v[i]`.
1655 ///
1656 /// For **maps**, removes and returns the entry for the given key,
1657 /// or `None` if the key is missing — matching [`BTreeMap::remove`].
1658 ///
1659 /// Transparent through tags, matching [`get`](Self::get).
1660 ///
1661 /// # Panics
1662 ///
1663 /// - If the value is not an array or map.
1664 /// - If the value is an array and the key is not a valid `usize`
1665 /// index in range `0..len`.
1666 ///
1667 /// ```
1668 /// use cbor_core::{array, map};
1669 ///
1670 /// let mut a = array![10, 20, 30];
1671 /// assert_eq!(a.remove(1).unwrap().to_u32().unwrap(), 20);
1672 /// assert_eq!(a.len().unwrap(), 2);
1673 ///
1674 /// let mut m = map! { "x" => 10, "y" => 20 };
1675 /// assert_eq!(m.remove("x").unwrap().to_u32().unwrap(), 10);
1676 /// assert!(m.remove("missing").is_none());
1677 /// ```
1678 ///
1679 /// [`BTreeMap::remove`]: std::collections::BTreeMap::remove
1680 pub fn remove<'a>(&mut self, index: impl Into<crate::ValueKey<'a>>) -> Option<Value> {
1681 let key = index.into();
1682 match self.untagged_mut() {
1683 Value::Array(arr) => {
1684 let idx = key.to_usize().expect("array index must be a non-negative integer");
1685 assert!(idx < arr.len(), "array index {idx} out of bounds (len {})", arr.len());
1686 Some(arr.remove(idx))
1687 }
1688 Value::Map(map) => map.remove(&key as &dyn ValueView),
1689 other => panic!("remove called on {:?}, expected array or map", other.data_type()),
1690 }
1691 }
1692
1693 /// Insert an element into a map or array.
1694 ///
1695 /// For **maps**, behaves like [`BTreeMap::insert`]: inserts the
1696 /// key/value pair and returns the previous value if the key was
1697 /// already present, otherwise `None`.
1698 ///
1699 /// For **arrays**, the key is a `usize` index in range `0..=len`.
1700 /// The value is inserted at that position, shifting subsequent
1701 /// elements right like [`Vec::insert`] (O(n)). Insertion into an
1702 /// array **always returns `None`**.
1703 ///
1704 /// Transparent through tags.
1705 ///
1706 /// # Panics
1707 ///
1708 /// - If the value is not an array or map.
1709 /// - If the value is an array and the key is not a valid `usize`
1710 /// index in range `0..=len`.
1711 ///
1712 /// ```
1713 /// use cbor_core::{array, map};
1714 ///
1715 /// let mut m = map! { "x" => 10 };
1716 /// assert_eq!(m.insert("y", 20), None);
1717 /// assert_eq!(m.insert("x", 99).unwrap().to_u32().unwrap(), 10);
1718 /// assert_eq!(m["x"].to_u32().unwrap(), 99);
1719 ///
1720 /// let mut a = array![10, 30];
1721 /// assert_eq!(a.insert(1, 20), None); // always None for arrays
1722 /// assert_eq!(a[1].to_u32().unwrap(), 20);
1723 /// assert_eq!(a.len().unwrap(), 3);
1724 /// ```
1725 ///
1726 /// [`BTreeMap::insert`]: std::collections::BTreeMap::insert
1727 pub fn insert(&mut self, key: impl Into<Value>, value: impl Into<Value>) -> Option<Value> {
1728 let key = key.into();
1729 let value = value.into();
1730 match self.untagged_mut() {
1731 Value::Array(arr) => {
1732 let idx = key.to_usize().expect("array index must be a non-negative integer");
1733 assert!(idx <= arr.len(), "array index {idx} out of bounds (len {})", arr.len());
1734 arr.insert(idx, value);
1735 None
1736 }
1737 Value::Map(map) => map.insert(key, value),
1738 other => panic!("insert called on {:?}, expected array or map", other.data_type()),
1739 }
1740 }
1741
1742 /// Append a value to the end of an array (O(1)), like [`Vec::push`].
1743 ///
1744 /// Transparent through tags.
1745 ///
1746 /// # Panics
1747 ///
1748 /// If the value is not an array.
1749 ///
1750 /// ```
1751 /// use cbor_core::array;
1752 ///
1753 /// let mut a = array![1, 2];
1754 /// a.append(3);
1755 /// a.append(4);
1756 /// assert_eq!(a.len().unwrap(), 4);
1757 /// assert_eq!(a[3].to_u32().unwrap(), 4);
1758 /// ```
1759 pub fn append(&mut self, value: impl Into<Value>) {
1760 match self.untagged_mut() {
1761 Value::Array(arr) => arr.push(value.into()),
1762 other => panic!("append called on {:?}, expected array", other.data_type()),
1763 }
1764 }
1765
1766 /// Test whether an array contains an index or a map contains a key.
1767 ///
1768 /// For **arrays**, returns `true` if the key converts to a `usize`
1769 /// in range `0..len`. For **maps**, returns `true` if the key is
1770 /// present. All other types return `false`. Transparent through tags.
1771 ///
1772 /// ```
1773 /// use cbor_core::{Value, array, map};
1774 ///
1775 /// let a = array![10, 20, 30];
1776 /// assert!(a.contains(1));
1777 /// assert!(!a.contains(5));
1778 ///
1779 /// let m = map! { "x" => 10 };
1780 /// assert!(m.contains("x"));
1781 /// assert!(!m.contains("missing"));
1782 ///
1783 /// assert!(!Value::from(42).contains(0));
1784 /// ```
1785 pub fn contains<'a>(&self, key: impl Into<crate::ValueKey<'a>>) -> bool {
1786 let key = key.into();
1787 match self.untagged() {
1788 Value::Array(arr) => key.to_usize().is_some_and(|idx| idx < arr.len()),
1789 Value::Map(map) => map.contains_key(&key as &dyn ValueView),
1790 _ => false,
1791 }
1792 }
1793
1794 /// Number of elements in an array or map, or `None` for any other type.
1795 ///
1796 /// Transparent through tags. For text and byte strings, use
1797 /// [`as_str`](Self::as_str) or [`as_bytes`](Self::as_bytes) and call
1798 /// `len()` on the slice.
1799 ///
1800 /// ```
1801 /// use cbor_core::{Value, array, map};
1802 ///
1803 /// assert_eq!(array![1, 2, 3].len(), Some(3));
1804 /// assert_eq!(map! { "x" => 1, "y" => 2 }.len(), Some(2));
1805 /// assert_eq!(Value::from("hello").len(), None);
1806 /// assert_eq!(Value::from(42).len(), None);
1807 /// ```
1808 #[allow(clippy::len_without_is_empty)]
1809 pub fn len(&self) -> Option<usize> {
1810 match self.untagged() {
1811 Value::Array(arr) => Some(arr.len()),
1812 Value::Map(map) => Some(map.len()),
1813 _ => None,
1814 }
1815 }
1816}
1817
1818/// Tags
1819impl Value {
1820 /// Return the tag number.
1821 pub const fn tag_number(&self) -> Result<u64> {
1822 match self {
1823 Self::Tag(number, _content) => Ok(*number),
1824 _ => Err(Error::IncompatibleType(self.data_type())),
1825 }
1826 }
1827
1828 /// Borrow the tag content.
1829 pub const fn tag_content(&self) -> Result<&Self> {
1830 match self {
1831 Self::Tag(_tag, content) => Ok(content),
1832 _ => Err(Error::IncompatibleType(self.data_type())),
1833 }
1834 }
1835
1836 /// Mutably borrow the tag content.
1837 pub const fn tag_content_mut(&mut self) -> Result<&mut Self> {
1838 match self {
1839 Self::Tag(_, value) => Ok(value),
1840 _ => Err(Error::IncompatibleType(self.data_type())),
1841 }
1842 }
1843
1844 /// Borrow tag number and content together.
1845 pub fn as_tag(&self) -> Result<(u64, &Value)> {
1846 match self {
1847 Self::Tag(number, content) => Ok((*number, content)),
1848 _ => Err(Error::IncompatibleType(self.data_type())),
1849 }
1850 }
1851
1852 /// Borrow tag number and mutable content together.
1853 pub fn as_tag_mut(&mut self) -> Result<(u64, &mut Value)> {
1854 match self {
1855 Self::Tag(number, content) => Ok((*number, content)),
1856 _ => Err(Error::IncompatibleType(self.data_type())),
1857 }
1858 }
1859
1860 /// Consume self and return tag number and content.
1861 pub fn into_tag(self) -> Result<(u64, Value)> {
1862 match self {
1863 Self::Tag(number, content) => Ok((number, *content)),
1864 _ => Err(Error::IncompatibleType(self.data_type())),
1865 }
1866 }
1867
1868 /// Remove the outermost tag, returning its number. Returns `None` if
1869 /// the value is not tagged.
1870 pub fn remove_tag(&mut self) -> Option<u64> {
1871 let mut result = None;
1872 if let Self::Tag(number, content) = self {
1873 result = Some(*number);
1874 *self = std::mem::take(content);
1875 }
1876 result
1877 }
1878
1879 /// Remove all nested tags, returning their numbers from outermost to
1880 /// innermost.
1881 pub fn remove_all_tags(&mut self) -> Vec<u64> {
1882 let mut tags = Vec::new();
1883 while let Self::Tag(number, content) = self {
1884 tags.push(*number);
1885 *self = std::mem::take(content);
1886 }
1887 tags
1888 }
1889
1890 /// Skip all tag wrappers except the innermost one.
1891 /// Returns `self` unchanged if not tagged or only single-tagged.
1892 #[must_use]
1893 pub(crate) const fn peeled(&self) -> &Self {
1894 let mut result = self;
1895 while let Self::Tag(_, content) = result
1896 && content.data_type().is_tag()
1897 {
1898 result = content;
1899 }
1900 result
1901 }
1902
1903 /// Borrow the innermost non-tag value, skipping all tag wrappers.
1904 #[must_use]
1905 pub const fn untagged(&self) -> &Self {
1906 let mut result = self;
1907 while let Self::Tag(_, content) = result {
1908 result = content;
1909 }
1910 result
1911 }
1912
1913 /// Mutable version of [`untagged`](Self::untagged).
1914 pub const fn untagged_mut(&mut self) -> &mut Self {
1915 let mut result = self;
1916 while let Self::Tag(_, content) = result {
1917 result = content;
1918 }
1919 result
1920 }
1921
1922 /// Consuming version of [`untagged`](Self::untagged).
1923 #[must_use]
1924 pub fn into_untagged(mut self) -> Self {
1925 while let Self::Tag(_number, content) = self {
1926 self = *content;
1927 }
1928 self
1929 }
1930}