ciborium/value/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! A dynamic CBOR value
4
5mod canonical;
6mod integer;
7
8mod de;
9mod error;
10mod ser;
11
12pub use canonical::CanonicalValue;
13pub use error::Error;
14pub use integer::Integer;
15
16use alloc::{boxed::Box, string::String, vec::Vec};
17
18/// A representation of a dynamic CBOR value that can handled dynamically
19#[non_exhaustive]
20#[derive(Clone, Debug, PartialEq, PartialOrd)]
21pub enum Value {
22    /// An integer
23    Integer(Integer),
24
25    /// Bytes
26    Bytes(Vec<u8>),
27
28    /// A float
29    Float(f64),
30
31    /// A string
32    Text(String),
33
34    /// A boolean
35    Bool(bool),
36
37    /// Null
38    Null,
39
40    /// Tag
41    Tag(u64, Box<Value>),
42
43    /// An array
44    Array(Vec<Value>),
45
46    /// A map
47    Map(Vec<(Value, Value)>),
48}
49
50impl Value {
51    /// Returns true if the `Value` is an `Integer`. Returns false otherwise.
52    ///
53    /// ```
54    /// # use ciborium::Value;
55    /// #
56    /// let value = Value::Integer(17.into());
57    ///
58    /// assert!(value.is_integer());
59    /// ```
60    pub fn is_integer(&self) -> bool {
61        self.as_integer().is_some()
62    }
63
64    /// If the `Value` is a `Integer`, returns a reference to the associated `Integer` data.
65    /// Returns None otherwise.
66    ///
67    /// ```
68    /// # use ciborium::Value;
69    /// #
70    /// let value = Value::Integer(17.into());
71    ///
72    /// // We can read the number
73    /// assert_eq!(17, value.as_integer().unwrap().try_into().unwrap());
74    /// ```
75    pub fn as_integer(&self) -> Option<Integer> {
76        match self {
77            Value::Integer(int) => Some(*int),
78            _ => None,
79        }
80    }
81
82    /// If the `Value` is a `Integer`, returns a the associated `Integer` data as `Ok`.
83    /// Returns `Err(Self)` otherwise.
84    ///
85    /// ```
86    /// # use ciborium::{Value, value::Integer};
87    /// #
88    /// let value = Value::Integer(17.into());
89    /// assert_eq!(value.into_integer(), Ok(Integer::from(17)));
90    ///
91    /// let value = Value::Bool(true);
92    /// assert_eq!(value.into_integer(), Err(Value::Bool(true)));
93    /// ```
94    pub fn into_integer(self) -> Result<Integer, Self> {
95        match self {
96            Value::Integer(int) => Ok(int),
97            other => Err(other),
98        }
99    }
100
101    /// Returns true if the `Value` is a `Bytes`. Returns false otherwise.
102    ///
103    /// ```
104    /// # use ciborium::Value;
105    /// #
106    /// let value = Value::Bytes(vec![104, 101, 108, 108, 111]);
107    ///
108    /// assert!(value.is_bytes());
109    /// ```
110    pub fn is_bytes(&self) -> bool {
111        self.as_bytes().is_some()
112    }
113
114    /// If the `Value` is a `Bytes`, returns a reference to the associated bytes vector.
115    /// Returns None otherwise.
116    ///
117    /// ```
118    /// # use ciborium::Value;
119    /// #
120    /// let value = Value::Bytes(vec![104, 101, 108, 108, 111]);
121    ///
122    /// assert_eq!(std::str::from_utf8(value.as_bytes().unwrap()).unwrap(), "hello");
123    /// ```
124    pub fn as_bytes(&self) -> Option<&Vec<u8>> {
125        match *self {
126            Value::Bytes(ref bytes) => Some(bytes),
127            _ => None,
128        }
129    }
130
131    /// If the `Value` is a `Bytes`, returns a mutable reference to the associated bytes vector.
132    /// Returns None otherwise.
133    ///
134    /// ```
135    /// # use ciborium::Value;
136    /// #
137    /// let mut value = Value::Bytes(vec![104, 101, 108, 108, 111]);
138    /// value.as_bytes_mut().unwrap().clear();
139    ///
140    /// assert_eq!(value, Value::Bytes(vec![]));
141    /// ```
142    pub fn as_bytes_mut(&mut self) -> Option<&mut Vec<u8>> {
143        match *self {
144            Value::Bytes(ref mut bytes) => Some(bytes),
145            _ => None,
146        }
147    }
148
149    /// If the `Value` is a `Bytes`, returns a the associated `Vec<u8>` data as `Ok`.
150    /// Returns `Err(Self)` otherwise.
151    ///
152    /// ```
153    /// # use ciborium::Value;
154    /// #
155    /// let value = Value::Bytes(vec![104, 101, 108, 108, 111]);
156    /// assert_eq!(value.into_bytes(), Ok(vec![104, 101, 108, 108, 111]));
157    ///
158    /// let value = Value::Bool(true);
159    /// assert_eq!(value.into_bytes(), Err(Value::Bool(true)));
160    /// ```
161    pub fn into_bytes(self) -> Result<Vec<u8>, Self> {
162        match self {
163            Value::Bytes(vec) => Ok(vec),
164            other => Err(other),
165        }
166    }
167
168    /// Returns true if the `Value` is a `Float`. Returns false otherwise.
169    ///
170    /// ```
171    /// # use ciborium::Value;
172    /// #
173    /// let value = Value::Float(17.0.into());
174    ///
175    /// assert!(value.is_float());
176    /// ```
177    pub fn is_float(&self) -> bool {
178        self.as_float().is_some()
179    }
180
181    /// If the `Value` is a `Float`, returns a reference to the associated float data.
182    /// Returns None otherwise.
183    ///
184    /// ```
185    /// # use ciborium::Value;
186    /// #
187    /// let value = Value::Float(17.0.into());
188    ///
189    /// // We can read the float number
190    /// assert_eq!(value.as_float().unwrap(), 17.0_f64);
191    /// ```
192    pub fn as_float(&self) -> Option<f64> {
193        match *self {
194            Value::Float(f) => Some(f),
195            _ => None,
196        }
197    }
198
199    /// If the `Value` is a `Float`, returns a the associated `f64` data as `Ok`.
200    /// Returns `Err(Self)` otherwise.
201    ///
202    /// ```
203    /// # use ciborium::Value;
204    /// #
205    /// let value = Value::Float(17.);
206    /// assert_eq!(value.into_float(), Ok(17.));
207    ///
208    /// let value = Value::Bool(true);
209    /// assert_eq!(value.into_float(), Err(Value::Bool(true)));
210    /// ```
211    pub fn into_float(self) -> Result<f64, Self> {
212        match self {
213            Value::Float(f) => Ok(f),
214            other => Err(other),
215        }
216    }
217
218    /// Returns true if the `Value` is a `Text`. Returns false otherwise.
219    ///
220    /// ```
221    /// # use ciborium::Value;
222    /// #
223    /// let value = Value::Text(String::from("hello"));
224    ///
225    /// assert!(value.is_text());
226    /// ```
227    pub fn is_text(&self) -> bool {
228        self.as_text().is_some()
229    }
230
231    /// If the `Value` is a `Text`, returns a reference to the associated `String` data.
232    /// Returns None otherwise.
233    ///
234    /// ```
235    /// # use ciborium::Value;
236    /// #
237    /// let value = Value::Text(String::from("hello"));
238    ///
239    /// // We can read the String
240    /// assert_eq!(value.as_text().unwrap(), "hello");
241    /// ```
242    pub fn as_text(&self) -> Option<&str> {
243        match *self {
244            Value::Text(ref s) => Some(s),
245            _ => None,
246        }
247    }
248
249    /// If the `Value` is a `Text`, returns a mutable reference to the associated `String` data.
250    /// Returns None otherwise.
251    ///
252    /// ```
253    /// # use ciborium::Value;
254    /// #
255    /// let mut value = Value::Text(String::from("hello"));
256    /// value.as_text_mut().unwrap().clear();
257    ///
258    /// assert_eq!(value.as_text().unwrap(), &String::from(""));
259    /// ```
260    pub fn as_text_mut(&mut self) -> Option<&mut String> {
261        match *self {
262            Value::Text(ref mut s) => Some(s),
263            _ => None,
264        }
265    }
266
267    /// If the `Value` is a `String`, returns a the associated `String` data as `Ok`.
268    /// Returns `Err(Self)` otherwise.
269    ///
270    /// ```
271    /// # use ciborium::Value;
272    /// #
273    /// let value = Value::Text(String::from("hello"));
274    /// assert_eq!(value.into_text().as_deref(), Ok("hello"));
275    ///
276    /// let value = Value::Bool(true);
277    /// assert_eq!(value.into_text(), Err(Value::Bool(true)));
278    /// ```
279    pub fn into_text(self) -> Result<String, Self> {
280        match self {
281            Value::Text(s) => Ok(s),
282            other => Err(other),
283        }
284    }
285
286    /// Returns true if the `Value` is a `Bool`. Returns false otherwise.
287    ///
288    /// ```
289    /// # use ciborium::Value;
290    /// #
291    /// let value = Value::Bool(false);
292    ///
293    /// assert!(value.is_bool());
294    /// ```
295    pub fn is_bool(&self) -> bool {
296        self.as_bool().is_some()
297    }
298
299    /// If the `Value` is a `Bool`, returns a copy of the associated boolean value. Returns None
300    /// otherwise.
301    ///
302    /// ```
303    /// # use ciborium::Value;
304    /// #
305    /// let value = Value::Bool(false);
306    ///
307    /// assert_eq!(value.as_bool().unwrap(), false);
308    /// ```
309    pub fn as_bool(&self) -> Option<bool> {
310        match *self {
311            Value::Bool(b) => Some(b),
312            _ => None,
313        }
314    }
315
316    /// If the `Value` is a `Bool`, returns a the associated `bool` data as `Ok`.
317    /// Returns `Err(Self)` otherwise.
318    ///
319    /// ```
320    /// # use ciborium::Value;
321    /// #
322    /// let value = Value::Bool(false);
323    /// assert_eq!(value.into_bool(), Ok(false));
324    ///
325    /// let value = Value::Float(17.);
326    /// assert_eq!(value.into_bool(), Err(Value::Float(17.)));
327    /// ```
328    pub fn into_bool(self) -> Result<bool, Self> {
329        match self {
330            Value::Bool(b) => Ok(b),
331            other => Err(other),
332        }
333    }
334
335    /// Returns true if the `Value` is a `Null`. Returns false otherwise.
336    ///
337    /// ```
338    /// # use ciborium::Value;
339    /// #
340    /// let value = Value::Null;
341    ///
342    /// assert!(value.is_null());
343    /// ```
344    pub fn is_null(&self) -> bool {
345        matches!(self, Value::Null)
346    }
347
348    /// Returns true if the `Value` is a `Tag`. Returns false otherwise.
349    ///
350    /// ```
351    /// # use ciborium::Value;
352    /// #
353    /// let value = Value::Tag(61, Box::from(Value::Null));
354    ///
355    /// assert!(value.is_tag());
356    /// ```
357    pub fn is_tag(&self) -> bool {
358        self.as_tag().is_some()
359    }
360
361    /// If the `Value` is a `Tag`, returns the associated tag value and a reference to the tag `Value`.
362    /// Returns None otherwise.
363    ///
364    /// ```
365    /// # use ciborium::Value;
366    /// #
367    /// let value = Value::Tag(61, Box::from(Value::Bytes(vec![104, 101, 108, 108, 111])));
368    ///
369    /// let (tag, data) = value.as_tag().unwrap();
370    /// assert_eq!(tag, 61);
371    /// assert_eq!(data, &Value::Bytes(vec![104, 101, 108, 108, 111]));
372    /// ```
373    pub fn as_tag(&self) -> Option<(u64, &Value)> {
374        match self {
375            Value::Tag(tag, data) => Some((*tag, data)),
376            _ => None,
377        }
378    }
379
380    /// If the `Value` is a `Tag`, returns the associated tag value and a mutable reference
381    /// to the tag `Value`. Returns None otherwise.
382    ///
383    /// ```
384    /// # use ciborium::Value;
385    /// #
386    /// let mut value = Value::Tag(61, Box::from(Value::Bytes(vec![104, 101, 108, 108, 111])));
387    ///
388    /// let (tag, mut data) = value.as_tag_mut().unwrap();
389    /// data.as_bytes_mut().unwrap().clear();
390    /// assert_eq!(tag, &61);
391    /// assert_eq!(data, &Value::Bytes(vec![]));
392    /// ```
393    pub fn as_tag_mut(&mut self) -> Option<(&mut u64, &mut Value)> {
394        match self {
395            Value::Tag(tag, data) => Some((tag, data.as_mut())),
396            _ => None,
397        }
398    }
399
400    /// If the `Value` is a `Tag`, returns a the associated pair of `u64` and `Box<value>` data as `Ok`.
401    /// Returns `Err(Self)` otherwise.
402    ///
403    /// ```
404    /// # use ciborium::Value;
405    /// #
406    /// let value = Value::Tag(7, Box::new(Value::Float(12.)));
407    /// assert_eq!(value.into_tag(), Ok((7, Box::new(Value::Float(12.)))));
408    ///
409    /// let value = Value::Bool(true);
410    /// assert_eq!(value.into_tag(), Err(Value::Bool(true)));
411    /// ```
412    pub fn into_tag(self) -> Result<(u64, Box<Value>), Self> {
413        match self {
414            Value::Tag(tag, value) => Ok((tag, value)),
415            other => Err(other),
416        }
417    }
418
419    /// Returns true if the `Value` is an Array. Returns false otherwise.
420    ///
421    /// ```
422    /// # use ciborium::Value;
423    /// #
424    /// let value = Value::Array(
425    ///     vec![
426    ///         Value::Text(String::from("foo")),
427    ///         Value::Text(String::from("bar"))
428    ///     ]
429    /// );
430    ///
431    /// assert!(value.is_array());
432    /// ```
433    pub fn is_array(&self) -> bool {
434        self.as_array().is_some()
435    }
436
437    /// If the `Value` is an Array, returns a reference to the associated vector. Returns None
438    /// otherwise.
439    ///
440    /// ```
441    /// # use ciborium::Value;
442    /// #
443    /// let value = Value::Array(
444    ///     vec![
445    ///         Value::Text(String::from("foo")),
446    ///         Value::Text(String::from("bar"))
447    ///     ]
448    /// );
449    ///
450    /// // The length of `value` is 2 elements.
451    /// assert_eq!(value.as_array().unwrap().len(), 2);
452    /// ```
453    pub fn as_array(&self) -> Option<&Vec<Value>> {
454        match *self {
455            Value::Array(ref array) => Some(array),
456            _ => None,
457        }
458    }
459
460    /// If the `Value` is an Array, returns a mutable reference to the associated vector.
461    /// Returns None otherwise.
462    ///
463    /// ```
464    /// # use ciborium::Value;
465    /// #
466    /// let mut value = Value::Array(
467    ///     vec![
468    ///         Value::Text(String::from("foo")),
469    ///         Value::Text(String::from("bar"))
470    ///     ]
471    /// );
472    ///
473    /// value.as_array_mut().unwrap().clear();
474    /// assert_eq!(value, Value::Array(vec![]));
475    /// ```
476    pub fn as_array_mut(&mut self) -> Option<&mut Vec<Value>> {
477        match *self {
478            Value::Array(ref mut list) => Some(list),
479            _ => None,
480        }
481    }
482
483    /// If the `Value` is a `Array`, returns a the associated `Vec<Value>` data as `Ok`.
484    /// Returns `Err(Self)` otherwise.
485    ///
486    /// ```
487    /// # use ciborium::{Value, value::Integer};
488    /// #
489    /// let mut value = Value::Array(
490    ///     vec![
491    ///         Value::Integer(17.into()),
492    ///         Value::Float(18.),
493    ///     ]
494    /// );
495    /// assert_eq!(value.into_array(), Ok(vec![Value::Integer(17.into()), Value::Float(18.)]));
496    ///
497    /// let value = Value::Bool(true);
498    /// assert_eq!(value.into_array(), Err(Value::Bool(true)));
499    /// ```
500    pub fn into_array(self) -> Result<Vec<Value>, Self> {
501        match self {
502            Value::Array(vec) => Ok(vec),
503            other => Err(other),
504        }
505    }
506
507    /// Returns true if the `Value` is a Map. Returns false otherwise.
508    ///
509    /// ```
510    /// # use ciborium::Value;
511    /// #
512    /// let value = Value::Map(
513    ///     vec![
514    ///         (Value::Text(String::from("foo")), Value::Text(String::from("bar")))
515    ///     ]
516    /// );
517    ///
518    /// assert!(value.is_map());
519    /// ```
520    pub fn is_map(&self) -> bool {
521        self.as_map().is_some()
522    }
523
524    /// If the `Value` is a Map, returns a reference to the associated Map data. Returns None
525    /// otherwise.
526    ///
527    /// ```
528    /// # use ciborium::Value;
529    /// #
530    /// let value = Value::Map(
531    ///     vec![
532    ///         (Value::Text(String::from("foo")), Value::Text(String::from("bar")))
533    ///     ]
534    /// );
535    ///
536    /// // The length of data is 1 entry (1 key/value pair).
537    /// assert_eq!(value.as_map().unwrap().len(), 1);
538    ///
539    /// // The content of the first element is what we expect
540    /// assert_eq!(
541    ///     value.as_map().unwrap().get(0).unwrap(),
542    ///     &(Value::Text(String::from("foo")), Value::Text(String::from("bar")))
543    /// );
544    /// ```
545    pub fn as_map(&self) -> Option<&Vec<(Value, Value)>> {
546        match *self {
547            Value::Map(ref map) => Some(map),
548            _ => None,
549        }
550    }
551
552    /// If the `Value` is a Map, returns a mutable reference to the associated Map Data.
553    /// Returns None otherwise.
554    ///
555    /// ```
556    /// # use ciborium::Value;
557    /// #
558    /// let mut value = Value::Map(
559    ///     vec![
560    ///         (Value::Text(String::from("foo")), Value::Text(String::from("bar")))
561    ///     ]
562    /// );
563    ///
564    /// value.as_map_mut().unwrap().clear();
565    /// assert_eq!(value, Value::Map(vec![]));
566    /// assert_eq!(value.as_map().unwrap().len(), 0);
567    /// ```
568    pub fn as_map_mut(&mut self) -> Option<&mut Vec<(Value, Value)>> {
569        match *self {
570            Value::Map(ref mut map) => Some(map),
571            _ => None,
572        }
573    }
574
575    /// If the `Value` is a `Map`, returns a the associated `Vec<(Value, Value)>` data as `Ok`.
576    /// Returns `Err(Self)` otherwise.
577    ///
578    /// ```
579    /// # use ciborium::Value;
580    /// #
581    /// let mut value = Value::Map(
582    ///     vec![
583    ///         (Value::Text(String::from("key")), Value::Float(18.)),
584    ///     ]
585    /// );
586    /// assert_eq!(value.into_map(), Ok(vec![(Value::Text(String::from("key")), Value::Float(18.))]));
587    ///
588    /// let value = Value::Bool(true);
589    /// assert_eq!(value.into_map(), Err(Value::Bool(true)));
590    /// ```
591    pub fn into_map(self) -> Result<Vec<(Value, Value)>, Self> {
592        match self {
593            Value::Map(map) => Ok(map),
594            other => Err(other),
595        }
596    }
597}
598
599macro_rules! implfrom {
600    ($($v:ident($t:ty)),+ $(,)?) => {
601        $(
602            impl From<$t> for Value {
603                #[inline]
604                fn from(value: $t) -> Self {
605                    Self::$v(value.into())
606                }
607            }
608        )+
609    };
610}
611
612implfrom! {
613    Integer(Integer),
614    Integer(u64),
615    Integer(i64),
616    Integer(u32),
617    Integer(i32),
618    Integer(u16),
619    Integer(i16),
620    Integer(u8),
621    Integer(i8),
622
623    Bytes(Vec<u8>),
624    Bytes(&[u8]),
625
626    Float(f64),
627    Float(f32),
628
629    Text(String),
630    Text(&str),
631
632    Bool(bool),
633
634    Array(&[Value]),
635    Array(Vec<Value>),
636
637    Map(&[(Value, Value)]),
638    Map(Vec<(Value, Value)>),
639}
640
641impl From<u128> for Value {
642    #[inline]
643    fn from(value: u128) -> Self {
644        if let Ok(x) = Integer::try_from(value) {
645            return Value::Integer(x);
646        }
647
648        let mut bytes = &value.to_be_bytes()[..];
649        while let Some(0) = bytes.first() {
650            bytes = &bytes[1..];
651        }
652
653        Value::Tag(ciborium_ll::tag::BIGPOS, Value::Bytes(bytes.into()).into())
654    }
655}
656
657impl From<i128> for Value {
658    #[inline]
659    fn from(value: i128) -> Self {
660        if let Ok(x) = Integer::try_from(value) {
661            return Value::Integer(x);
662        }
663
664        let (tag, raw) = match value.is_negative() {
665            true => (ciborium_ll::tag::BIGNEG, value as u128 ^ !0),
666            false => (ciborium_ll::tag::BIGPOS, value as u128),
667        };
668
669        let mut bytes = &raw.to_be_bytes()[..];
670        while let Some(0) = bytes.first() {
671            bytes = &bytes[1..];
672        }
673
674        Value::Tag(tag, Value::Bytes(bytes.into()).into())
675    }
676}
677
678impl From<char> for Value {
679    #[inline]
680    fn from(value: char) -> Self {
681        let mut v = String::with_capacity(1);
682        v.push(value);
683        Value::Text(v)
684    }
685}