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