ciborium/value/mod.rs
1// SPDX-License-Identifier: Apache-2.0
2
3//! A dynamic CBOR value
4
5mod integer;
6
7mod de;
8mod error;
9mod ser;
10
11pub use error::Error;
12pub use integer::Integer;
13
14use 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)]
19pub 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
48impl 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 /// ```
58 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 /// ```
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 /// ```
89 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 /// ```
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 /// ```
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 /// ```
137 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 /// ```
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 /// ```
168 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 /// ```
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 /// ```
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 /// ```
217 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 /// ```
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 /// ```
247 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 /// ```
260 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 /// ```
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 /// ```
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 /// ```
317 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 /// ```
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 /// ```
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 /// ```
380 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 /// ```
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 /// ```
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
436macro_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
449implfrom! {
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
478impl From<u128> for Value {
479 #[inline]
480 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
494impl From<i128> for Value {
495 #[inline]
496 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
515impl From<char> for Value {
516 #[inline]
517 fn from(value: char) -> Self {
518 let mut v = String::with_capacity(1);
519 v.push(value);
520 Value::Text(v)
521 }
522}