Skip to main content

cbor2/
value.rs

1//! A dynamic CBOR value.
2
3use alloc::borrow::Cow;
4use alloc::boxed::Box;
5use alloc::collections::BTreeMap;
6use alloc::format;
7use alloc::string::{String, ToString};
8use alloc::vec::Vec;
9#[cfg(feature = "std")]
10use std::collections::HashMap;
11
12mod canonical;
13mod de;
14mod integer;
15mod ser;
16
17pub use canonical::KeyOrder;
18pub use integer::Integer;
19
20/// An error when serializing to or deserializing from a [`Value`].
21#[derive(Clone, Debug)]
22pub enum Error {
23    /// A custom error message produced by serde.
24    Custom(String),
25}
26
27impl core::fmt::Display for Error {
28    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
29        match self {
30            Error::Custom(msg) => write!(f, "{msg}"),
31        }
32    }
33}
34
35// `serde::ser::StdError` is `std::error::Error` whenever it is available,
36// and an identical substitute otherwise.
37impl serde::ser::StdError for Error {}
38
39impl serde::de::Error for Error {
40    #[inline]
41    fn custom<T: core::fmt::Display>(msg: T) -> Self {
42        Self::Custom(msg.to_string())
43    }
44}
45
46impl serde::ser::Error for Error {
47    #[inline]
48    fn custom<T: core::fmt::Display>(msg: T) -> Self {
49        Self::Custom(msg.to_string())
50    }
51}
52
53/// A representation of any CBOR item that can be inspected and manipulated
54/// dynamically.
55///
56/// Maps are represented as `Vec<(Value, Value)>` rather than as an ordered
57/// or hashed map type. This preserves the order of the pairs on the wire and
58/// makes no assumptions about key uniqueness; convert with `TryFrom` —
59/// `HashMap` and `BTreeMap` are supported directly — if you need a map type.
60///
61/// `Value` intentionally models the serde-visible CBOR data model, not every
62/// byte-level spelling. For example, indefinite-length strings are decoded
63/// into the same variants as definite-length strings, while unknown tags
64/// remain as [`Value::Tag`] and oversized bignums stay as tagged byte
65/// strings.
66#[non_exhaustive]
67#[derive(Clone, PartialEq, PartialOrd)]
68pub enum Value {
69    /// An integer (major type 0 or 1).
70    Integer(Integer),
71
72    /// A byte string (major type 2).
73    Bytes(Vec<u8>),
74
75    /// A floating-point value (major type 7).
76    Float(f64),
77
78    /// A text string (major type 3).
79    Text(String),
80
81    /// A boolean (major type 7).
82    Bool(bool),
83
84    /// Null (major type 7).
85    Null,
86
87    /// A tagged value (major type 6).
88    Tag(u64, Box<Value>),
89
90    /// An array (major type 4).
91    Array(Vec<Value>),
92
93    /// A map (major type 5).
94    Map(Vec<(Value, Value)>),
95}
96
97/// Formats the value as indented CBOR diagnostic notation (RFC 8949 §8).
98///
99/// This is the multi-line counterpart of the [`Display`](Self#impl-Display-for-Value)
100/// implementation: arrays and maps spread one element per line, nested
101/// levels are indented by two spaces, and scalars render exactly as in
102/// the compact form.
103///
104/// ```
105/// use cbor2::cbor;
106///
107/// let value = cbor!({ "a": [1, 2] }).unwrap();
108/// assert_eq!(
109///     format!("{value:?}"),
110///     "{\n  \"a\": [\n    1,\n    2\n  ]\n}"
111/// );
112/// ```
113impl core::fmt::Debug for Value {
114    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
115        let mut out = String::new();
116        crate::diag::write_value_pretty(&mut out, self, 0);
117        f.write_str(&out)
118    }
119}
120
121macro_rules! accessors {
122    ($(#[doc = $doc:literal] $is:ident $as:ident $into:ident($variant:ident) -> $t:ty;)+) => {
123        $(
124            #[doc = concat!("Returns true if the value is ", $doc, ".")]
125            #[inline]
126            pub fn $is(&self) -> bool {
127                matches!(self, Value::$variant(..))
128            }
129
130            #[doc = concat!("If the value is ", $doc, ", returns a reference to it. Returns `None` otherwise.")]
131            #[inline]
132            pub fn $as(&self) -> Option<&$t> {
133                match self {
134                    Value::$variant(x) => Some(x),
135                    _ => None,
136                }
137            }
138
139            #[doc = concat!("If the value is ", $doc, ", returns it as `Ok`. Returns `Err(self)` otherwise.")]
140            #[inline]
141            pub fn $into(self) -> Result<$t, Self> {
142                match self {
143                    Value::$variant(x) => Ok(x),
144                    other => Err(other),
145                }
146            }
147        )+
148    };
149}
150
151impl Value {
152    accessors! {
153        #[doc = "a byte string"]
154        is_bytes as_bytes into_bytes(Bytes) -> Vec<u8>;
155
156        #[doc = "an array"]
157        is_array as_array into_array(Array) -> Vec<Value>;
158
159        #[doc = "a map"]
160        is_map as_map into_map(Map) -> Vec<(Value, Value)>;
161    }
162
163    /// Returns true if the value is an integer.
164    #[inline]
165    pub fn is_integer(&self) -> bool {
166        matches!(self, Value::Integer(..))
167    }
168
169    /// If the value is an integer, returns it. Returns `None` otherwise.
170    #[inline]
171    pub fn as_integer(&self) -> Option<Integer> {
172        match self {
173            Value::Integer(x) => Some(*x),
174            _ => None,
175        }
176    }
177
178    /// If the value is an integer, returns it as `Ok`. Returns `Err(self)`
179    /// otherwise.
180    #[inline]
181    pub fn into_integer(self) -> Result<Integer, Self> {
182        match self {
183            Value::Integer(x) => Ok(x),
184            other => Err(other),
185        }
186    }
187
188    /// Returns true if the value is a float.
189    #[inline]
190    pub fn is_float(&self) -> bool {
191        matches!(self, Value::Float(..))
192    }
193
194    /// If the value is a float, returns it. Returns `None` otherwise.
195    #[inline]
196    pub fn as_float(&self) -> Option<f64> {
197        match self {
198            Value::Float(x) => Some(*x),
199            _ => None,
200        }
201    }
202
203    /// If the value is a float, returns it as `Ok`. Returns `Err(self)`
204    /// otherwise.
205    #[inline]
206    pub fn into_float(self) -> Result<f64, Self> {
207        match self {
208            Value::Float(x) => Ok(x),
209            other => Err(other),
210        }
211    }
212
213    /// Returns true if the value is a text string.
214    #[inline]
215    pub fn is_text(&self) -> bool {
216        matches!(self, Value::Text(..))
217    }
218
219    /// If the value is a text string, returns a reference to it. Returns
220    /// `None` otherwise.
221    #[inline]
222    pub fn as_text(&self) -> Option<&str> {
223        match self {
224            Value::Text(x) => Some(x),
225            _ => None,
226        }
227    }
228
229    /// If the value is a text string, returns it as `Ok`. Returns
230    /// `Err(self)` otherwise.
231    #[inline]
232    pub fn into_text(self) -> Result<String, Self> {
233        match self {
234            Value::Text(x) => Ok(x),
235            other => Err(other),
236        }
237    }
238
239    /// Returns true if the value is a boolean.
240    #[inline]
241    pub fn is_bool(&self) -> bool {
242        matches!(self, Value::Bool(..))
243    }
244
245    /// If the value is a boolean, returns it. Returns `None` otherwise.
246    #[inline]
247    pub fn as_bool(&self) -> Option<bool> {
248        match self {
249            Value::Bool(x) => Some(*x),
250            _ => None,
251        }
252    }
253
254    /// If the value is a boolean, returns it as `Ok`. Returns `Err(self)`
255    /// otherwise.
256    #[inline]
257    pub fn into_bool(self) -> Result<bool, Self> {
258        match self {
259            Value::Bool(x) => Ok(x),
260            other => Err(other),
261        }
262    }
263
264    /// Returns true if the value is null.
265    #[inline]
266    pub fn is_null(&self) -> bool {
267        matches!(self, Value::Null)
268    }
269
270    /// Returns true if the value is a tag.
271    #[inline]
272    pub fn is_tag(&self) -> bool {
273        matches!(self, Value::Tag(..))
274    }
275
276    /// If the value is a tag, returns the tag number and a reference to the
277    /// inner value. Returns `None` otherwise.
278    #[inline]
279    pub fn as_tag(&self) -> Option<(u64, &Value)> {
280        match self {
281            Value::Tag(tag, data) => Some((*tag, data)),
282            _ => None,
283        }
284    }
285
286    /// If the value is a tag, returns the pair of the tag number and the
287    /// inner value as `Ok`. Returns `Err(self)` otherwise.
288    #[inline]
289    pub fn into_tag(self) -> Result<(u64, Box<Value>), Self> {
290        match self {
291            Value::Tag(tag, data) => Ok((tag, data)),
292            other => Err(other),
293        }
294    }
295
296    /// If the value is a byte string, returns a mutable reference to it.
297    /// Returns `None` otherwise.
298    #[inline]
299    pub fn as_bytes_mut(&mut self) -> Option<&mut Vec<u8>> {
300        match self {
301            Value::Bytes(x) => Some(x),
302            _ => None,
303        }
304    }
305
306    /// If the value is a text string, returns a mutable reference to it.
307    /// Returns `None` otherwise.
308    #[inline]
309    pub fn as_text_mut(&mut self) -> Option<&mut String> {
310        match self {
311            Value::Text(x) => Some(x),
312            _ => None,
313        }
314    }
315
316    /// If the value is an array, returns a mutable reference to it. Returns
317    /// `None` otherwise.
318    #[inline]
319    pub fn as_array_mut(&mut self) -> Option<&mut Vec<Value>> {
320        match self {
321            Value::Array(x) => Some(x),
322            _ => None,
323        }
324    }
325
326    /// If the value is a map, returns a mutable reference to it. Returns
327    /// `None` otherwise.
328    #[inline]
329    pub fn as_map_mut(&mut self) -> Option<&mut Vec<(Value, Value)>> {
330        match self {
331            Value::Map(x) => Some(x),
332            _ => None,
333        }
334    }
335
336    /// If the value is a tag, returns mutable references to the tag number
337    /// and the inner value. Returns `None` otherwise.
338    #[inline]
339    pub fn as_tag_mut(&mut self) -> Option<(&mut u64, &mut Value)> {
340        match self {
341            Value::Tag(tag, data) => Some((tag, data.as_mut())),
342            _ => None,
343        }
344    }
345}
346
347/// Formats the value in CBOR diagnostic notation (RFC 8949 §8).
348///
349/// Byte strings appear as `h'..'`, text is escaped to pure ASCII in the
350/// style of RFC 8949 Appendix A, floats always carry a decimal point or
351/// exponent and bignum tags (2 and 3) are written as plain integers.
352///
353/// ```
354/// use cbor2::{cbor, Value};
355///
356/// let value = cbor!({ "k": [1, -2.5, null] }).unwrap();
357/// assert_eq!(value.to_string(), r#"{"k": [1, -2.5, null]}"#);
358/// ```
359impl core::fmt::Display for Value {
360    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
361        let mut out = String::new();
362        crate::diag::write_value(&mut out, self);
363        f.write_str(&out)
364    }
365}
366
367macro_rules! implfrom {
368    ($($variant:ident($t:ty)),+ $(,)?) => {
369        $(
370            impl From<$t> for Value {
371                #[inline]
372                fn from(value: $t) -> Self {
373                    Self::$variant(value.into())
374                }
375            }
376        )+
377    };
378}
379
380implfrom! {
381    Integer(Integer),
382    Integer(u64),
383    Integer(i64),
384    Integer(u32),
385    Integer(i32),
386    Integer(u16),
387    Integer(i16),
388    Integer(u8),
389    Integer(i8),
390
391    Bytes(Vec<u8>),
392    Bytes(&[u8]),
393
394    Float(f64),
395    Float(f32),
396
397    Text(String),
398    Text(&str),
399
400    Bool(bool),
401
402    Array(&[Value]),
403    Array(Vec<Value>),
404
405    Map(&[(Value, Value)]),
406    Map(Vec<(Value, Value)>),
407}
408
409impl From<u128> for Value {
410    #[inline]
411    fn from(value: u128) -> Self {
412        if let Ok(x) = Integer::try_from(value) {
413            return Value::Integer(x);
414        }
415
416        let mut bytes = &value.to_be_bytes()[..];
417        while let Some(0) = bytes.first() {
418            bytes = &bytes[1..];
419        }
420
421        Value::Tag(crate::core::tag::BIGPOS, Value::Bytes(bytes.into()).into())
422    }
423}
424
425impl From<i128> for Value {
426    #[inline]
427    fn from(value: i128) -> Self {
428        if let Ok(x) = Integer::try_from(value) {
429            return Value::Integer(x);
430        }
431
432        let (tag, raw) = match value.is_negative() {
433            true => (crate::core::tag::BIGNEG, value as u128 ^ !0),
434            false => (crate::core::tag::BIGPOS, value as u128),
435        };
436
437        let mut bytes = &raw.to_be_bytes()[..];
438        while let Some(0) = bytes.first() {
439            bytes = &bytes[1..];
440        }
441
442        Value::Tag(tag, Value::Bytes(bytes.into()).into())
443    }
444}
445
446impl From<char> for Value {
447    #[inline]
448    fn from(value: char) -> Self {
449        let mut v = String::with_capacity(value.len_utf8());
450        v.push(value);
451        Value::Text(v)
452    }
453}
454
455impl From<Cow<'_, str>> for Value {
456    #[inline]
457    fn from(value: Cow<'_, str>) -> Self {
458        Value::Text(value.into_owned())
459    }
460}
461
462impl<const N: usize> From<[u8; N]> for Value {
463    #[inline]
464    fn from(value: [u8; N]) -> Self {
465        Value::Bytes(value.into())
466    }
467}
468
469impl<const N: usize> From<&[u8; N]> for Value {
470    #[inline]
471    fn from(value: &[u8; N]) -> Self {
472        Value::Bytes(value.into())
473    }
474}
475
476#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
477impl From<usize> for Value {
478    #[inline]
479    fn from(value: usize) -> Self {
480        Value::Integer(value.into())
481    }
482}
483
484#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
485impl From<isize> for Value {
486    #[inline]
487    fn from(value: isize) -> Self {
488        Value::Integer(value.into())
489    }
490}
491
492/// Converts `Some` to the inner value and `None` to [`Value::Null`].
493impl<T: Into<Value>> From<Option<T>> for Value {
494    #[inline]
495    fn from(value: Option<T>) -> Self {
496        match value {
497            Some(value) => value.into(),
498            None => Value::Null,
499        }
500    }
501}
502
503/// Converts to [`Value::Map`], keeping the map's iteration order — which
504/// a `HashMap` randomizes. Encode with the `to_canonical_*` functions (or
505/// [`canonicalize`](Value::canonicalize) first) when a deterministic
506/// order matters.
507///
508/// ```
509/// use std::collections::HashMap;
510/// use cbor2::Value;
511///
512/// let map: HashMap<&str, u64> = [("a", 1)].into();
513/// assert_eq!(Value::from(map), cbor2::cbor!({ "a": 1 }).unwrap());
514/// ```
515#[cfg(feature = "std")]
516impl<K: Into<Value>, V: Into<Value>> From<HashMap<K, V>> for Value {
517    fn from(value: HashMap<K, V>) -> Self {
518        Value::Map(
519            value
520                .into_iter()
521                .map(|(k, v)| (k.into(), v.into()))
522                .collect(),
523        )
524    }
525}
526
527/// Converts to [`Value::Map`] in the map's order: ascending by key.
528impl<K: Into<Value>, V: Into<Value>> From<BTreeMap<K, V>> for Value {
529    fn from(value: BTreeMap<K, V>) -> Self {
530        Value::Map(
531            value
532                .into_iter()
533                .map(|(k, v)| (k.into(), v.into()))
534                .collect(),
535        )
536    }
537}
538
539/// Collects an iterator of values into [`Value::Array`].
540///
541/// ```
542/// use cbor2::Value;
543///
544/// let value: Value = (1..=3).collect();
545/// assert_eq!(value, cbor2::cbor!([1, 2, 3]).unwrap());
546/// ```
547impl<T: Into<Value>> FromIterator<T> for Value {
548    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
549        Value::Array(iter.into_iter().map(Into::into).collect())
550    }
551}
552
553// A serde-style "invalid type" error for a failed conversion.
554fn invalid_type(value: &Value, expected: &'static str) -> Error {
555    serde::de::Error::invalid_type(value.into(), &expected)
556}
557
558macro_rules! tryfrom_value {
559    ($($t:ty: $variant:ident => $expected:literal,)+) => {$(
560        #[doc = concat!("Converts from [`Value::", stringify!($variant), "`]; any other variant is an `\"invalid type\"` error.")]
561        ///
562        /// The [`Value::into_*`](Value::into_bytes) accessors are the
563        /// non-consuming-on-failure alternative: they hand the original
564        /// value back instead of an error message.
565        impl TryFrom<Value> for $t {
566            type Error = Error;
567
568            #[inline]
569            fn try_from(value: Value) -> Result<Self, Error> {
570                match value {
571                    Value::$variant(x) => Ok(x),
572                    other => Err(invalid_type(&other, $expected)),
573                }
574            }
575        }
576    )+};
577}
578
579tryfrom_value! {
580    Integer: Integer => "integer",
581    Vec<u8>: Bytes => "bytes",
582    f64: Float => "float",
583    String: Text => "text",
584    bool: Bool => "bool",
585    Vec<Value>: Array => "array",
586    Vec<(Value, Value)>: Map => "map",
587}
588
589/// Converts from a single-character [`Value::Text`].
590impl TryFrom<Value> for char {
591    type Error = Error;
592
593    fn try_from(value: Value) -> Result<Self, Error> {
594        if let Value::Text(text) = &value {
595            let mut chars = text.chars();
596            if let (Some(c), None) = (chars.next(), chars.next()) {
597                return Ok(c);
598            }
599        }
600
601        Err(invalid_type(&value, "a single-character text"))
602    }
603}
604
605macro_rules! tryfrom_int {
606    ($($(#[$($attr:meta)+])? $t:ident)+) => {$(
607        $(#[$($attr)+])?
608        #[doc = concat!("Converts from a [`Value::Integer`] in `", stringify!($t), "` range.")]
609        impl TryFrom<Value> for $t {
610            type Error = Error;
611
612            #[inline]
613            fn try_from(value: Value) -> Result<Self, Error> {
614                match value {
615                    Value::Integer(x) => $t::try_from(x).map_err(|_| {
616                        Error::Custom(format!(
617                            concat!(
618                                "invalid value: integer `{}`, expected ",
619                                stringify!($t),
620                            ),
621                            i128::from(x),
622                        ))
623                    }),
624                    other => Err(invalid_type(&other, "integer")),
625                }
626            }
627        }
628    )+};
629}
630
631tryfrom_int! {
632    u8 u16 u32 u64
633    i8 i16 i32 i64
634
635    #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
636    usize
637
638    #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
639    isize
640}
641
642/// Converts from any integer representation that fits, including the
643/// bignum form (tag 2 or 3) that [`From<u128>`](Value#impl-From%3Cu128%3E-for-Value)
644/// produces for values beyond 64 bits.
645impl TryFrom<Value> for u128 {
646    type Error = Error;
647
648    #[inline]
649    fn try_from(value: Value) -> Result<Self, Error> {
650        value.deserialized()
651    }
652}
653
654/// Converts from any integer representation that fits, including the
655/// bignum form (tag 2 or 3) that [`From<i128>`](Value#impl-From%3Ci128%3E-for-Value)
656/// produces for values beyond 64 bits.
657impl TryFrom<Value> for i128 {
658    type Error = Error;
659
660    #[inline]
661    fn try_from(value: Value) -> Result<Self, Error> {
662        value.deserialized()
663    }
664}
665
666// Converts the entries of a map, reporting the first failure.
667fn map_entries<K, V, M>(pairs: Vec<(Value, Value)>) -> Result<M, Error>
668where
669    K: TryFrom<Value>,
670    K::Error: core::fmt::Display,
671    V: TryFrom<Value>,
672    V::Error: core::fmt::Display,
673    M: FromIterator<(K, V)>,
674{
675    pairs
676        .into_iter()
677        .map(|(k, v)| {
678            Ok((
679                K::try_from(k).map_err(|err| Error::Custom(format!("invalid map key: {err}")))?,
680                V::try_from(v).map_err(|err| Error::Custom(format!("invalid map value: {err}")))?,
681            ))
682        })
683        .collect()
684}
685
686/// Converts from [`Value::Map`], converting every key and value in turn;
687/// later duplicate keys overwrite earlier ones. For deep, typed
688/// extraction with detailed errors prefer
689/// [`Value::deserialized`](Value::deserialized).
690///
691/// ```
692/// use std::collections::HashMap;
693/// use cbor2::Value;
694///
695/// let value = cbor2::cbor!({ "a": 1, "b": 2 }).unwrap();
696/// let map: HashMap<String, u64> = value.try_into().unwrap();
697/// assert_eq!(map["a"], 1);
698/// ```
699#[cfg(feature = "std")]
700impl<K, V> TryFrom<Value> for HashMap<K, V>
701where
702    K: TryFrom<Value> + Eq + core::hash::Hash,
703    K::Error: core::fmt::Display,
704    V: TryFrom<Value>,
705    V::Error: core::fmt::Display,
706{
707    type Error = Error;
708
709    fn try_from(value: Value) -> Result<Self, Error> {
710        match value {
711            Value::Map(pairs) => map_entries(pairs),
712            other => Err(invalid_type(&other, "map")),
713        }
714    }
715}
716
717/// Converts from [`Value::Map`], converting every key and value in turn;
718/// later duplicate keys overwrite earlier ones.
719impl<K, V> TryFrom<Value> for BTreeMap<K, V>
720where
721    K: TryFrom<Value> + Ord,
722    K::Error: core::fmt::Display,
723    V: TryFrom<Value>,
724    V::Error: core::fmt::Display,
725{
726    type Error = Error;
727
728    fn try_from(value: Value) -> Result<Self, Error> {
729        match value {
730            Value::Map(pairs) => map_entries(pairs),
731            other => Err(invalid_type(&other, "map")),
732        }
733    }
734}