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