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}
686