1 //! CBOR and serialization. 2 //! 3 //! # Usage 4 //! 5 //! Serde CBOR supports Rust 1.40 and up. Add this to your `Cargo.toml`: 6 //! ```toml 7 //! [dependencies] 8 //! serde_cbor = "0.10" 9 //! ``` 10 //! 11 //! Storing and loading Rust types is easy and requires only 12 //! minimal modifications to the program code. 13 //! 14 //! ```rust 15 //! use serde_derive::{Deserialize, Serialize}; 16 //! use std::error::Error; 17 //! use std::fs::File; 18 //! 19 //! // Types annotated with `Serialize` can be stored as CBOR. 20 //! // To be able to load them again add `Deserialize`. 21 //! #[derive(Debug, Serialize, Deserialize)] 22 //! struct Mascot { 23 //! name: String, 24 //! species: String, 25 //! year_of_birth: u32, 26 //! } 27 //! 28 //! fn main() -> Result<(), Box<dyn Error>> { 29 //! let ferris = Mascot { 30 //! name: "Ferris".to_owned(), 31 //! species: "crab".to_owned(), 32 //! year_of_birth: 2015, 33 //! }; 34 //! 35 //! let ferris_file = File::create("examples/ferris.cbor")?; 36 //! // Write Ferris to the given file. 37 //! // Instead of a file you can use any type that implements `io::Write` 38 //! // like a HTTP body, database connection etc. 39 //! serde_cbor::to_writer(ferris_file, &ferris)?; 40 //! 41 //! let tux_file = File::open("examples/tux.cbor")?; 42 //! // Load Tux from a file. 43 //! // Serde CBOR performs roundtrip serialization meaning that 44 //! // the data will not change in any way. 45 //! let tux: Mascot = serde_cbor::from_reader(tux_file)?; 46 //! 47 //! println!("{:?}", tux); 48 //! // prints: Mascot { name: "Tux", species: "penguin", year_of_birth: 1996 } 49 //! 50 //! Ok(()) 51 //! } 52 //! ``` 53 //! 54 //! There are a lot of options available to customize the format. 55 //! To operate on untyped CBOR values have a look at the `Value` type. 56 //! 57 //! # Type-based Serialization and Deserialization 58 //! Serde provides a mechanism for low boilerplate serialization & deserialization of values to and 59 //! from CBOR via the serialization API. To be able to serialize a piece of data, it must implement 60 //! the `serde::Serialize` trait. To be able to deserialize a piece of data, it must implement the 61 //! `serde::Deserialize` trait. Serde provides an annotation to automatically generate the 62 //! code for these traits: `#[derive(Serialize, Deserialize)]`. 63 //! 64 //! The CBOR API also provides an enum `serde_cbor::Value`. 65 //! 66 //! # Packed Encoding 67 //! When serializing structs or enums in CBOR the keys or enum variant names will be serialized 68 //! as string keys to a map. Especially in embedded environments this can increase the file 69 //! size too much. In packed encoding all struct keys, as well as any enum variant that has no data, 70 //! will be serialized as variable sized integers. The first 24 entries in any struct consume only a 71 //! single byte! Packed encoding uses serde's preferred [externally tagged enum 72 //! format](https://serde.rs/enum-representations.html) and therefore serializes enum variant names 73 //! as string keys when that variant contains data. So, in the packed encoding example, `FirstVariant` 74 //! encodes to a single byte, but encoding `SecondVariant` requires 16 bytes. 75 //! 76 //! To serialize a document in this format use `Serializer::new(writer).packed_format()` or 77 //! the shorthand `ser::to_vec_packed`. The deserialization works without any changes. 78 //! 79 //! If you would like to omit the enum variant encoding for all variants, including ones that 80 //! contain data, you can add `legacy_enums()` in addition to `packed_format()`, as can seen 81 //! in the Serialize using minimal encoding example. 82 //! 83 //! # Self describing documents 84 //! In some contexts different formats are used but there is no way to declare the format used 85 //! out of band. For this reason CBOR has a magic number that may be added before any document. 86 //! Self describing documents are created with `serializer.self_describe()`. 87 //! 88 //! # Examples 89 //! Read a CBOR value that is known to be a map of string keys to string values and print it. 90 //! 91 //! ```rust 92 //! use std::collections::BTreeMap; 93 //! use serde_cbor::from_slice; 94 //! 95 //! let slice = b"\xa5aaaAabaBacaCadaDaeaE"; 96 //! let value: BTreeMap<String, String> = from_slice(slice).unwrap(); 97 //! println!("{:?}", value); // {"e": "E", "d": "D", "a": "A", "c": "C", "b": "B"} 98 //! ``` 99 //! 100 //! Read a general CBOR value with an unknown content. 101 //! 102 //! ```rust 103 //! use serde_cbor::from_slice; 104 //! use serde_cbor::value::Value; 105 //! 106 //! let slice = b"\x82\x01\xa1aaab"; 107 //! let value: Value = from_slice(slice).unwrap(); 108 //! println!("{:?}", value); // Array([U64(1), Object({String("a"): String("b")})]) 109 //! ``` 110 //! 111 //! Serialize an object. 112 //! 113 //! ```rust 114 //! use std::collections::BTreeMap; 115 //! use serde_cbor::to_vec; 116 //! 117 //! let mut programming_languages = BTreeMap::new(); 118 //! programming_languages.insert("rust", vec!["safe", "concurrent", "fast"]); 119 //! programming_languages.insert("python", vec!["powerful", "friendly", "open"]); 120 //! programming_languages.insert("js", vec!["lightweight", "interpreted", "object-oriented"]); 121 //! let encoded = to_vec(&programming_languages); 122 //! assert_eq!(encoded.unwrap().len(), 103); 123 //! ``` 124 //! 125 //! Deserializing data in the middle of a slice 126 //! ``` 127 //! # extern crate serde_cbor; 128 //! use serde_cbor::Deserializer; 129 //! 130 //! # fn main() { 131 //! let data: Vec<u8> = vec![ 132 //! 0x66, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72, 0x66, 0x66, 0x6f, 0x6f, 0x62, 133 //! 0x61, 0x72, 134 //! ]; 135 //! let mut deserializer = Deserializer::from_slice(&data); 136 //! let value: &str = serde::de::Deserialize::deserialize(&mut deserializer) 137 //! .unwrap(); 138 //! let rest = &data[deserializer.byte_offset()..]; 139 //! assert_eq!(value, "foobar"); 140 //! assert_eq!(rest, &[0x66, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72]); 141 //! # } 142 //! ``` 143 //! 144 //! Serialize using packed encoding 145 //! 146 //! ```rust 147 //! use serde_derive::{Deserialize, Serialize}; 148 //! use serde_cbor::ser::to_vec_packed; 149 //! use WithTwoVariants::*; 150 //! 151 //! #[derive(Debug, Serialize, Deserialize)] 152 //! enum WithTwoVariants { 153 //! FirstVariant, 154 //! SecondVariant(u8), 155 //! } 156 //! 157 //! let cbor = to_vec_packed(&FirstVariant).unwrap(); 158 //! assert_eq!(cbor.len(), 1); 159 //! 160 //! let cbor = to_vec_packed(&SecondVariant(0)).unwrap(); 161 //! assert_eq!(cbor.len(), 16); // Includes 13 bytes of "SecondVariant" 162 //! ``` 163 //! 164 //! Serialize using minimal encoding 165 //! 166 //! ```rust 167 //! use serde_derive::{Deserialize, Serialize}; 168 //! use serde_cbor::{Result, Serializer, ser::{self, IoWrite}}; 169 //! use WithTwoVariants::*; 170 //! 171 //! fn to_vec_minimal<T>(value: &T) -> Result<Vec<u8>> 172 //! where 173 //! T: serde::Serialize, 174 //! { 175 //! let mut vec = Vec::new(); 176 //! value.serialize(&mut Serializer::new(&mut IoWrite::new(&mut vec)).packed_format().legacy_enums())?; 177 //! Ok(vec) 178 //! } 179 //! 180 //! #[derive(Debug, Serialize, Deserialize)] 181 //! enum WithTwoVariants { 182 //! FirstVariant, 183 //! SecondVariant(u8), 184 //! } 185 //! 186 //! let cbor = to_vec_minimal(&FirstVariant).unwrap(); 187 //! assert_eq!(cbor.len(), 1); 188 //! 189 //! let cbor = to_vec_minimal(&SecondVariant(0)).unwrap(); 190 //! assert_eq!(cbor.len(), 3); 191 //! ``` 192 //! 193 //! # `no-std` support 194 //! 195 //! Serde CBOR supports building in a `no_std` context, use the following lines 196 //! in your `Cargo.toml` dependencies: 197 //! ``` toml 198 //! [dependencies] 199 //! serde = { version = "1.0", default-features = false } 200 //! serde_cbor = { version = "0.10", default-features = false } 201 //! ``` 202 //! 203 //! Without the `std` feature the functions [from_reader], [from_slice], [to_vec], and [to_writer] 204 //! are not exported. To export [from_slice] and [to_vec] enable the `alloc` feature. The `alloc` 205 //! feature uses the [`alloc` library][alloc-lib] and requires at least version 1.36.0 of Rust. 206 //! 207 //! [alloc-lib]: https://doc.rust-lang.org/alloc/ 208 //! 209 //! *Note*: to use derive macros in serde you will need to declare `serde` 210 //! dependency like so: 211 //! ``` toml 212 //! serde = { version = "1.0", default-features = false, features = ["derive"] } 213 //! ``` 214 //! 215 //! Serialize an object with `no_std` and without `alloc`. 216 //! ``` rust 217 //! # #[macro_use] extern crate serde_derive; 218 //! # fn main() -> Result<(), serde_cbor::Error> { 219 //! use serde::Serialize; 220 //! use serde_cbor::Serializer; 221 //! use serde_cbor::ser::SliceWrite; 222 //! 223 //! #[derive(Serialize)] 224 //! struct User { 225 //! user_id: u32, 226 //! password_hash: [u8; 4], 227 //! } 228 //! 229 //! let mut buf = [0u8; 100]; 230 //! let writer = SliceWrite::new(&mut buf[..]); 231 //! let mut ser = Serializer::new(writer); 232 //! let user = User { 233 //! user_id: 42, 234 //! password_hash: [1, 2, 3, 4], 235 //! }; 236 //! user.serialize(&mut ser)?; 237 //! let writer = ser.into_inner(); 238 //! let size = writer.bytes_written(); 239 //! let expected = [ 240 //! 0xa2, 0x67, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x2a, 0x6d, 241 //! 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x68, 0x61, 0x73, 242 //! 0x68, 0x84, 0x1, 0x2, 0x3, 0x4 243 //! ]; 244 //! assert_eq!(&buf[..size], expected); 245 //! # Ok(()) 246 //! # } 247 //! ``` 248 //! 249 //! Deserialize an object. 250 //! ``` rust 251 //! # #[macro_use] extern crate serde_derive; 252 //! # fn main() -> Result<(), serde_cbor::Error> { 253 //! #[derive(Debug, PartialEq, Deserialize)] 254 //! struct User { 255 //! user_id: u32, 256 //! password_hash: [u8; 4], 257 //! } 258 //! 259 //! let value = [ 260 //! 0xa2, 0x67, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x2a, 0x6d, 261 //! 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x68, 0x61, 0x73, 262 //! 0x68, 0x84, 0x1, 0x2, 0x3, 0x4 263 //! ]; 264 //! 265 //! // from_slice_with_scratch will not alter input data, use it whenever you 266 //! // borrow from somewhere else. 267 //! // You will have to size your scratch according to the input data you 268 //! // expect. 269 //! use serde_cbor::de::from_slice_with_scratch; 270 //! let mut scratch = [0u8; 32]; 271 //! let user: User = from_slice_with_scratch(&value[..], &mut scratch)?; 272 //! assert_eq!(user, User { 273 //! user_id: 42, 274 //! password_hash: [1, 2, 3, 4], 275 //! }); 276 //! 277 //! let mut value = [ 278 //! 0xa2, 0x67, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x2a, 0x6d, 279 //! 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x68, 0x61, 0x73, 280 //! 0x68, 0x84, 0x1, 0x2, 0x3, 0x4 281 //! ]; 282 //! 283 //! // from_mut_slice will move data around the input slice, you may only use it 284 //! // on data you may own or can modify. 285 //! use serde_cbor::de::from_mut_slice; 286 //! let user: User = from_mut_slice(&mut value[..])?; 287 //! assert_eq!(user, User { 288 //! user_id: 42, 289 //! password_hash: [1, 2, 3, 4], 290 //! }); 291 //! # Ok(()) 292 //! # } 293 //! ``` 294 //! 295 //! # Limitations 296 //! 297 //! While Serde CBOR strives to support all features of Serde and CBOR 298 //! there are a few limitations. 299 //! 300 //! * [Tags] are ignored during deserialization and can't be emitted during 301 //! serialization. This is because Serde has no concept of tagged 302 //! values. See: [#3] 303 //! * Unknown [simple values] cause an `UnassignedCode` error. 304 //! The simple values *False* and *True* are recognized and parsed as bool. 305 //! *Null* and *Undefined* are both deserialized as *unit*. 306 //! The *unit* type is serialized as *Null*. See: [#86] 307 //! * [128-bit integers] can't be directly encoded in CBOR. If you need them 308 //! store them as a byte string. See: [#77] 309 //! 310 //! [Tags]: https://tools.ietf.org/html/rfc7049#section-2.4.4 311 //! [#3]: https://github.com/pyfisch/cbor/issues/3 312 //! [simple values]: https://tools.ietf.org/html/rfc7049#section-3.5 313 //! [#86]: https://github.com/pyfisch/cbor/issues/86 314 //! [128-bit integers]: https://doc.rust-lang.org/std/primitive.u128.html 315 //! [#77]: https://github.com/pyfisch/cbor/issues/77 316 317 #![deny(missing_docs)] 318 #![cfg_attr(not(feature = "std"), no_std)] 319 320 // When we are running tests in no_std mode we need to explicitly link std, because `cargo test` 321 // will not work without it. 322 #[cfg(all(not(feature = "std"), test))] 323 extern crate std; 324 325 #[cfg(feature = "alloc")] 326 extern crate alloc; 327 328 pub mod de; 329 pub mod error; 330 mod read; 331 pub mod ser; 332 pub mod tags; 333 mod write; 334 335 #[cfg(feature = "std")] 336 pub mod value; 337 338 // Re-export the [items recommended by serde](https://serde.rs/conventions.html). 339 #[doc(inline)] 340 pub use crate::de::{Deserializer, StreamDeserializer}; 341 342 #[doc(inline)] 343 pub use crate::error::{Error, Result}; 344 345 #[doc(inline)] 346 pub use crate::ser::Serializer; 347 348 // Convenience functions for serialization and deserialization. 349 // These functions are only available in `std` mode. 350 #[cfg(feature = "std")] 351 #[doc(inline)] 352 pub use crate::de::from_reader; 353 354 #[cfg(any(feature = "std", feature = "alloc"))] 355 #[doc(inline)] 356 pub use crate::de::from_slice; 357 358 #[cfg(any(feature = "std", feature = "alloc"))] 359 #[doc(inline)] 360 pub use crate::ser::to_vec; 361 362 #[cfg(feature = "std")] 363 #[doc(inline)] 364 pub use crate::ser::to_writer; 365 366 // Re-export the value type like serde_json 367 #[cfg(feature = "std")] 368 #[doc(inline)] 369 pub use crate::value::Value; 370