1 // SPDX-License-Identifier: Apache-2.0
2 
3 //! A dynamic CBOR value
4 
5 mod canonical;
6 mod integer;
7 
8 mod de;
9 mod error;
10 mod ser;
11 
12 pub use canonical::CanonicalValue;
13 pub use error::Error;
14 pub use integer::Integer;
15 
16 use 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)]
21 pub 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 
50 impl 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     /// ```
is_integer(&self) -> bool60     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     /// ```
as_integer(&self) -> Option<Integer>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     /// ```
into_integer(self) -> Result<Integer, Self>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     /// ```
is_bytes(&self) -> bool110     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     /// ```
as_bytes(&self) -> Option<&Vec<u8>>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     /// ```
as_bytes_mut(&mut self) -> Option<&mut Vec<u8>>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     /// ```
into_bytes(self) -> Result<Vec<u8>, Self>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     /// ```
is_float(&self) -> bool177     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     /// ```
as_float(&self) -> Option<f64>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     /// ```
into_float(self) -> Result<f64, Self>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     /// ```
is_text(&self) -> bool227     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     /// ```
as_text(&self) -> Option<&str>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     /// ```
as_text_mut(&mut self) -> Option<&mut String>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     /// ```
into_text(self) -> Result<String, Self>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     /// ```
is_bool(&self) -> bool295     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     /// ```
as_bool(&self) -> Option<bool>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     /// ```
into_bool(self) -> Result<bool, Self>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     /// ```
is_null(&self) -> bool344     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     /// ```
is_tag(&self) -> bool357     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     /// ```
as_tag(&self) -> Option<(u64, &Value)>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     /// ```
as_tag_mut(&mut self) -> Option<(&mut u64, &mut Value)>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     /// ```
into_tag(self) -> Result<(u64, Box<Value>), Self>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     /// ```
is_array(&self) -> bool433     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     /// ```
as_array(&self) -> Option<&Vec<Value>>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     /// ```
as_array_mut(&mut self) -> Option<&mut Vec<Value>>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     /// ```
into_array(self) -> Result<Vec<Value>, Self>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     /// ```
is_map(&self) -> bool520     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     /// ```
as_map(&self) -> Option<&Vec<(Value, Value)>>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     /// ```
as_map_mut(&mut self) -> Option<&mut Vec<(Value, Value)>>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     /// ```
into_map(self) -> Result<Vec<(Value, Value)>, Self>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 
599 macro_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 
612 implfrom! {
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 
641 impl From<u128> for Value {
642     #[inline]
from(value: u128) -> Self643     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 
657 impl From<i128> for Value {
658     #[inline]
from(value: i128) -> Self659     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 
678 impl From<char> for Value {
679     #[inline]
from(value: char) -> Self680     fn from(value: char) -> Self {
681         let mut v = String::with_capacity(1);
682         v.push(value);
683         Value::Text(v)
684     }
685 }
686