• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: Apache-2.0
2 
3 //! A dynamic CBOR value
4 
5 mod integer;
6 
7 mod de;
8 mod error;
9 mod ser;
10 
11 pub use error::Error;
12 pub use integer::Integer;
13 
14 use alloc::{boxed::Box, string::String, vec::Vec};
15 
16 /// A representation of a dynamic CBOR value that can handled dynamically
17 #[non_exhaustive]
18 #[derive(Clone, Debug, PartialEq, PartialOrd)]
19 pub enum Value {
20     /// An integer
21     Integer(Integer),
22 
23     /// Bytes
24     Bytes(Vec<u8>),
25 
26     /// A float
27     Float(f64),
28 
29     /// A string
30     Text(String),
31 
32     /// A boolean
33     Bool(bool),
34 
35     /// Null
36     Null,
37 
38     /// Tag
39     Tag(u64, Box<Value>),
40 
41     /// An array
42     Array(Vec<Value>),
43 
44     /// A map
45     Map(Vec<(Value, Value)>),
46 }
47 
48 impl Value {
49     /// Returns true if the `Value` is an `Integer`. Returns false otherwise.
50     ///
51     /// ```
52     /// # use ciborium::value::Value;
53     /// #
54     /// let value = Value::Integer(17.into());
55     ///
56     /// assert!(value.is_integer());
57     /// ```
is_integer(&self) -> bool58     pub fn is_integer(&self) -> bool {
59         self.as_integer().is_some()
60     }
61 
62     /// If the `Value` is a `Integer`, returns a reference to the associated `Integer` data.
63     /// Returns None otherwise.
64     ///
65     /// ```
66     /// # use ciborium::value::Value;
67     /// #
68     /// let value = Value::Integer(17.into());
69     ///
70     /// // We can read the number
71     /// assert_eq!(17, value.as_integer().unwrap().try_into().unwrap());
72     /// ```
as_integer(&self) -> Option<Integer>73     pub fn as_integer(&self) -> Option<Integer> {
74         match self {
75             Value::Integer(int) => Some(*int),
76             _ => None,
77         }
78     }
79 
80     /// Returns true if the `Value` is a `Bytes`. Returns false otherwise.
81     ///
82     /// ```
83     /// # use ciborium::value::Value;
84     /// #
85     /// let value = Value::Bytes(vec![104, 101, 108, 108, 111]);
86     ///
87     /// assert!(value.is_bytes());
88     /// ```
is_bytes(&self) -> bool89     pub fn is_bytes(&self) -> bool {
90         self.as_bytes().is_some()
91     }
92 
93     /// If the `Value` is a `Bytes`, returns a reference to the associated bytes vector.
94     /// Returns None otherwise.
95     ///
96     /// ```
97     /// # use ciborium::value::Value;
98     /// #
99     /// let value = Value::Bytes(vec![104, 101, 108, 108, 111]);
100     ///
101     /// assert_eq!(std::str::from_utf8(value.as_bytes().unwrap()).unwrap(), "hello");
102     /// ```
as_bytes(&self) -> Option<&Vec<u8>>103     pub fn as_bytes(&self) -> Option<&Vec<u8>> {
104         match *self {
105             Value::Bytes(ref bytes) => Some(bytes),
106             _ => None,
107         }
108     }
109 
110     /// If the `Value` is a `Bytes`, returns a mutable reference to the associated bytes vector.
111     /// Returns None otherwise.
112     ///
113     /// ```
114     /// # use ciborium::value::Value;
115     /// #
116     /// let mut value = Value::Bytes(vec![104, 101, 108, 108, 111]);
117     /// value.as_bytes_mut().unwrap().clear();
118     ///
119     /// assert_eq!(value, Value::Bytes(vec![]));
120     /// ```
as_bytes_mut(&mut self) -> Option<&mut Vec<u8>>121     pub fn as_bytes_mut(&mut self) -> Option<&mut Vec<u8>> {
122         match *self {
123             Value::Bytes(ref mut bytes) => Some(bytes),
124             _ => None,
125         }
126     }
127 
128     /// Returns true if the `Value` is a `Float`. Returns false otherwise.
129     ///
130     /// ```
131     /// # use ciborium::value::Value;
132     /// #
133     /// let value = Value::Float(17.0.into());
134     ///
135     /// assert!(value.is_float());
136     /// ```
is_float(&self) -> bool137     pub fn is_float(&self) -> bool {
138         self.as_float().is_some()
139     }
140 
141     /// If the `Value` is a `Float`, returns a reference to the associated float data.
142     /// Returns None otherwise.
143     ///
144     /// ```
145     /// # use ciborium::value::Value;
146     /// #
147     /// let value = Value::Float(17.0.into());
148     ///
149     /// // We can read the float number
150     /// assert_eq!(value.as_float().unwrap(), 17.0_f64);
151     /// ```
as_float(&self) -> Option<f64>152     pub fn as_float(&self) -> Option<f64> {
153         match *self {
154             Value::Float(f) => Some(f),
155             _ => None,
156         }
157     }
158 
159     /// Returns true if the `Value` is a `Text`. Returns false otherwise.
160     ///
161     /// ```
162     /// # use ciborium::value::Value;
163     /// #
164     /// let value = Value::Text(String::from("hello"));
165     ///
166     /// assert!(value.is_text());
167     /// ```
is_text(&self) -> bool168     pub fn is_text(&self) -> bool {
169         self.as_text().is_some()
170     }
171 
172     /// If the `Value` is a `Text`, returns a reference to the associated `String` data.
173     /// Returns None otherwise.
174     ///
175     /// ```
176     /// # use ciborium::value::Value;
177     /// #
178     /// let value = Value::Text(String::from("hello"));
179     ///
180     /// // We can read the String
181     /// assert_eq!(value.as_text().unwrap(), "hello");
182     /// ```
as_text(&self) -> Option<&str>183     pub fn as_text(&self) -> Option<&str> {
184         match *self {
185             Value::Text(ref s) => Some(s),
186             _ => None,
187         }
188     }
189 
190     /// If the `Value` is a `Text`, returns a mutable reference to the associated `String` data.
191     /// Returns None otherwise.
192     ///
193     /// ```
194     /// # use ciborium::value::Value;
195     /// #
196     /// let mut value = Value::Text(String::from("hello"));
197     /// value.as_text_mut().unwrap().clear();
198     ///
199     /// assert_eq!(value.as_text().unwrap(), &String::from(""));
200     /// ```
as_text_mut(&mut self) -> Option<&mut String>201     pub fn as_text_mut(&mut self) -> Option<&mut String> {
202         match *self {
203             Value::Text(ref mut s) => Some(s),
204             _ => None,
205         }
206     }
207 
208     /// Returns true if the `Value` is a `Bool`. Returns false otherwise.
209     ///
210     /// ```
211     /// # use ciborium::value::Value;
212     /// #
213     /// let value = Value::Bool(false);
214     ///
215     /// assert!(value.is_bool());
216     /// ```
is_bool(&self) -> bool217     pub fn is_bool(&self) -> bool {
218         self.as_bool().is_some()
219     }
220 
221     /// If the `Value` is a `Bool`, returns a copy of the associated boolean value. Returns None
222     /// otherwise.
223     ///
224     /// ```
225     /// # use ciborium::value::Value;
226     /// #
227     /// let value = Value::Bool(false);
228     ///
229     /// assert_eq!(value.as_bool().unwrap(), false);
230     /// ```
as_bool(&self) -> Option<bool>231     pub fn as_bool(&self) -> Option<bool> {
232         match *self {
233             Value::Bool(b) => Some(b),
234             _ => None,
235         }
236     }
237 
238     /// Returns true if the `Value` is a `Null`. Returns false otherwise.
239     ///
240     /// ```
241     /// # use ciborium::value::Value;
242     /// #
243     /// let value = Value::Null;
244     ///
245     /// assert!(value.is_null());
246     /// ```
is_null(&self) -> bool247     pub fn is_null(&self) -> bool {
248         matches!(self, Value::Null)
249     }
250 
251     /// Returns true if the `Value` is a `Tag`. Returns false otherwise.
252     ///
253     /// ```
254     /// # use ciborium::value::Value;
255     /// #
256     /// let value = Value::Tag(61, Box::from(Value::Null));
257     ///
258     /// assert!(value.is_tag());
259     /// ```
is_tag(&self) -> bool260     pub fn is_tag(&self) -> bool {
261         self.as_tag().is_some()
262     }
263 
264     /// If the `Value` is a `Tag`, returns the associated tag value and a reference to the tag `Value`.
265     /// Returns None otherwise.
266     ///
267     /// ```
268     /// # use ciborium::value::Value;
269     /// #
270     /// let value = Value::Tag(61, Box::from(Value::Bytes(vec![104, 101, 108, 108, 111])));
271     ///
272     /// let (tag, data) = value.as_tag().unwrap();
273     /// assert_eq!(tag, 61);
274     /// assert_eq!(data, &Value::Bytes(vec![104, 101, 108, 108, 111]));
275     /// ```
as_tag(&self) -> Option<(u64, &Value)>276     pub fn as_tag(&self) -> Option<(u64, &Value)> {
277         match self {
278             Value::Tag(tag, data) => Some((*tag, data)),
279             _ => None,
280         }
281     }
282 
283     /// If the `Value` is a `Tag`, returns the associated tag value and a mutable reference
284     /// to the tag `Value`. Returns None otherwise.
285     ///
286     /// ```
287     /// # use ciborium::value::Value;
288     /// #
289     /// let mut value = Value::Tag(61, Box::from(Value::Bytes(vec![104, 101, 108, 108, 111])));
290     ///
291     /// let (tag, mut data) = value.as_tag_mut().unwrap();
292     /// data.as_bytes_mut().unwrap().clear();
293     /// assert_eq!(tag, &61);
294     /// assert_eq!(data, &Value::Bytes(vec![]));
295     /// ```
as_tag_mut(&mut self) -> Option<(&mut u64, &mut Value)>296     pub fn as_tag_mut(&mut self) -> Option<(&mut u64, &mut Value)> {
297         match self {
298             Value::Tag(tag, data) => Some((tag, data.as_mut())),
299             _ => None,
300         }
301     }
302 
303     /// Returns true if the `Value` is an Array. Returns false otherwise.
304     ///
305     /// ```
306     /// # use ciborium::value::Value;
307     /// #
308     /// let value = Value::Array(
309     ///     vec![
310     ///         Value::Text(String::from("foo")),
311     ///         Value::Text(String::from("bar"))
312     ///     ]
313     /// );
314     ///
315     /// assert!(value.is_array());
316     /// ```
is_array(&self) -> bool317     pub fn is_array(&self) -> bool {
318         self.as_array().is_some()
319     }
320 
321     /// If the `Value` is an Array, returns a reference to the associated vector. Returns None
322     /// otherwise.
323     ///
324     /// ```
325     /// # use ciborium::value::Value;
326     /// #
327     /// let value = Value::Array(
328     ///     vec![
329     ///         Value::Text(String::from("foo")),
330     ///         Value::Text(String::from("bar"))
331     ///     ]
332     /// );
333     ///
334     /// // The length of `value` is 2 elements.
335     /// assert_eq!(value.as_array().unwrap().len(), 2);
336     /// ```
as_array(&self) -> Option<&Vec<Value>>337     pub fn as_array(&self) -> Option<&Vec<Value>> {
338         match *self {
339             Value::Array(ref array) => Some(&*array),
340             _ => None,
341         }
342     }
343 
344     /// If the `Value` is an Array, returns a mutable reference to the associated vector.
345     /// Returns None otherwise.
346     ///
347     /// ```
348     /// # use ciborium::value::Value;
349     /// #
350     /// let mut value = Value::Array(
351     ///     vec![
352     ///         Value::Text(String::from("foo")),
353     ///         Value::Text(String::from("bar"))
354     ///     ]
355     /// );
356     ///
357     /// value.as_array_mut().unwrap().clear();
358     /// assert_eq!(value, Value::Array(vec![]));
359     /// ```
as_array_mut(&mut self) -> Option<&mut Vec<Value>>360     pub fn as_array_mut(&mut self) -> Option<&mut Vec<Value>> {
361         match *self {
362             Value::Array(ref mut list) => Some(list),
363             _ => None,
364         }
365     }
366 
367     /// Returns true if the `Value` is a Map. Returns false otherwise.
368     ///
369     /// ```
370     /// # use ciborium::value::Value;
371     /// #
372     /// let value = Value::Map(
373     ///     vec![
374     ///         (Value::Text(String::from("foo")), Value::Text(String::from("bar")))
375     ///     ]
376     /// );
377     ///
378     /// assert!(value.is_map());
379     /// ```
is_map(&self) -> bool380     pub fn is_map(&self) -> bool {
381         self.as_map().is_some()
382     }
383 
384     /// If the `Value` is a Map, returns a reference to the associated Map data. Returns None
385     /// otherwise.
386     ///
387     /// ```
388     /// # use ciborium::value::Value;
389     /// #
390     /// let value = Value::Map(
391     ///     vec![
392     ///         (Value::Text(String::from("foo")), Value::Text(String::from("bar")))
393     ///     ]
394     /// );
395     ///
396     /// // The length of data is 1 entry (1 key/value pair).
397     /// assert_eq!(value.as_map().unwrap().len(), 1);
398     ///
399     /// // The content of the first element is what we expect
400     /// assert_eq!(
401     ///     value.as_map().unwrap().get(0).unwrap(),
402     ///     &(Value::Text(String::from("foo")), Value::Text(String::from("bar")))
403     /// );
404     /// ```
as_map(&self) -> Option<&Vec<(Value, Value)>>405     pub fn as_map(&self) -> Option<&Vec<(Value, Value)>> {
406         match *self {
407             Value::Map(ref map) => Some(map),
408             _ => None,
409         }
410     }
411 
412     /// If the `Value` is a Map, returns a mutable reference to the associated Map Data.
413     /// Returns None otherwise.
414     ///
415     /// ```
416     /// # use ciborium::value::Value;
417     /// #
418     /// let mut value = Value::Map(
419     ///     vec![
420     ///         (Value::Text(String::from("foo")), Value::Text(String::from("bar")))
421     ///     ]
422     /// );
423     ///
424     /// value.as_map_mut().unwrap().clear();
425     /// assert_eq!(value, Value::Map(vec![]));
426     /// assert_eq!(value.as_map().unwrap().len(), 0);
427     /// ```
as_map_mut(&mut self) -> Option<&mut Vec<(Value, Value)>>428     pub fn as_map_mut(&mut self) -> Option<&mut Vec<(Value, Value)>> {
429         match *self {
430             Value::Map(ref mut map) => Some(map),
431             _ => None,
432         }
433     }
434 }
435 
436 macro_rules! implfrom {
437     ($($v:ident($t:ty)),+ $(,)?) => {
438         $(
439             impl From<$t> for Value {
440                 #[inline]
441                 fn from(value: $t) -> Self {
442                     Self::$v(value.into())
443                 }
444             }
445         )+
446     };
447 }
448 
449 implfrom! {
450     Integer(Integer),
451     Integer(u64),
452     Integer(i64),
453     Integer(u32),
454     Integer(i32),
455     Integer(u16),
456     Integer(i16),
457     Integer(u8),
458     Integer(i8),
459 
460     Bytes(Vec<u8>),
461     Bytes(&[u8]),
462 
463     Float(f64),
464     Float(f32),
465 
466     Text(String),
467     Text(&str),
468 
469     Bool(bool),
470 
471     Array(&[Value]),
472     Array(Vec<Value>),
473 
474     Map(&[(Value, Value)]),
475     Map(Vec<(Value, Value)>),
476 }
477 
478 impl From<u128> for Value {
479     #[inline]
from(value: u128) -> Self480     fn from(value: u128) -> Self {
481         if let Ok(x) = Integer::try_from(value) {
482             return Value::Integer(x);
483         }
484 
485         let mut bytes = &value.to_be_bytes()[..];
486         while let Some(0) = bytes.get(0) {
487             bytes = &bytes[1..];
488         }
489 
490         Value::Tag(ciborium_ll::tag::BIGPOS, Value::Bytes(bytes.into()).into())
491     }
492 }
493 
494 impl From<i128> for Value {
495     #[inline]
from(value: i128) -> Self496     fn from(value: i128) -> Self {
497         if let Ok(x) = Integer::try_from(value) {
498             return Value::Integer(x);
499         }
500 
501         let (tag, raw) = match value.is_negative() {
502             true => (ciborium_ll::tag::BIGNEG, value as u128 ^ !0),
503             false => (ciborium_ll::tag::BIGPOS, value as u128),
504         };
505 
506         let mut bytes = &raw.to_be_bytes()[..];
507         while let Some(0) = bytes.get(0) {
508             bytes = &bytes[1..];
509         }
510 
511         Value::Tag(tag, Value::Bytes(bytes.into()).into())
512     }
513 }
514 
515 impl From<char> for Value {
516     #[inline]
from(value: char) -> Self517     fn from(value: char) -> Self {
518         let mut v = String::with_capacity(1);
519         v.push(value);
520         Value::Text(v)
521     }
522 }
523