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 the keys and variants will be serialized as variable sized 70 //! integers. The first 24 entries in any struct consume only a single byte! 71 //! To serialize a document in this format use `Serializer::new(writer).packed_format()` or 72 //! the shorthand `ser::to_vec_packed`. The deserialization works without any changes. 73 //! 74 //! # Self describing documents 75 //! In some contexts different formats are used but there is no way to declare the format used 76 //! out of band. For this reason CBOR has a magic number that may be added before any document. 77 //! Self describing documents are created with `serializer.self_describe()`. 78 //! 79 //! # Examples 80 //! Read a CBOR value that is known to be a map of string keys to string values and print it. 81 //! 82 //! ```rust 83 //! use std::collections::BTreeMap; 84 //! use serde_cbor::from_slice; 85 //! 86 //! let slice = b"\xa5aaaAabaBacaCadaDaeaE"; 87 //! let value: BTreeMap<String, String> = from_slice(slice).unwrap(); 88 //! println!("{:?}", value); // {"e": "E", "d": "D", "a": "A", "c": "C", "b": "B"} 89 //! ``` 90 //! 91 //! Read a general CBOR value with an unknown content. 92 //! 93 //! ```rust 94 //! use serde_cbor::from_slice; 95 //! use serde_cbor::value::Value; 96 //! 97 //! let slice = b"\x82\x01\xa1aaab"; 98 //! let value: Value = from_slice(slice).unwrap(); 99 //! println!("{:?}", value); // Array([U64(1), Object({String("a"): String("b")})]) 100 //! ``` 101 //! 102 //! Serialize an object. 103 //! 104 //! ```rust 105 //! use std::collections::BTreeMap; 106 //! use serde_cbor::to_vec; 107 //! 108 //! let mut programming_languages = BTreeMap::new(); 109 //! programming_languages.insert("rust", vec!["safe", "concurrent", "fast"]); 110 //! programming_languages.insert("python", vec!["powerful", "friendly", "open"]); 111 //! programming_languages.insert("js", vec!["lightweight", "interpreted", "object-oriented"]); 112 //! let encoded = to_vec(&programming_languages); 113 //! assert_eq!(encoded.unwrap().len(), 103); 114 //! ``` 115 //! 116 //! Deserializing data in the middle of a slice 117 //! ``` 118 //! # extern crate serde_cbor; 119 //! use serde_cbor::Deserializer; 120 //! 121 //! # fn main() { 122 //! let data: Vec<u8> = vec![ 123 //! 0x66, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72, 0x66, 0x66, 0x6f, 0x6f, 0x62, 124 //! 0x61, 0x72, 125 //! ]; 126 //! let mut deserializer = Deserializer::from_slice(&data); 127 //! let value: &str = serde::de::Deserialize::deserialize(&mut deserializer) 128 //! .unwrap(); 129 //! let rest = &data[deserializer.byte_offset()..]; 130 //! assert_eq!(value, "foobar"); 131 //! assert_eq!(rest, &[0x66, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72]); 132 //! # } 133 //! ``` 134 //! 135 //! # `no-std` support 136 //! 137 //! Serde CBOR supports building in a `no_std` context, use the following lines 138 //! in your `Cargo.toml` dependencies: 139 //! ``` toml 140 //! [dependencies] 141 //! serde = { version = "1.0", default-features = false } 142 //! serde_cbor = { version = "0.10", default-features = false } 143 //! ``` 144 //! 145 //! Without the `std` feature the functions [from_reader], [from_slice], [to_vec], and [to_writer] 146 //! are not exported. To export [from_slice] and [to_vec] enable the `alloc` feature. The `alloc` 147 //! feature uses the [`alloc` library][alloc-lib] and requires at least version 1.36.0 of Rust. 148 //! 149 //! [alloc-lib]: https://doc.rust-lang.org/alloc/ 150 //! 151 //! *Note*: to use derive macros in serde you will need to declare `serde` 152 //! dependency like so: 153 //! ``` toml 154 //! serde = { version = "1.0", default-features = false, features = ["derive"] } 155 //! ``` 156 //! 157 //! Serialize an object with `no_std` and without `alloc`. 158 //! ``` rust 159 //! # #[macro_use] extern crate serde_derive; 160 //! # fn main() -> Result<(), serde_cbor::Error> { 161 //! use serde::Serialize; 162 //! use serde_cbor::Serializer; 163 //! use serde_cbor::ser::SliceWrite; 164 //! 165 //! #[derive(Serialize)] 166 //! struct User { 167 //! user_id: u32, 168 //! password_hash: [u8; 4], 169 //! } 170 //! 171 //! let mut buf = [0u8; 100]; 172 //! let writer = SliceWrite::new(&mut buf[..]); 173 //! let mut ser = Serializer::new(writer); 174 //! let user = User { 175 //! user_id: 42, 176 //! password_hash: [1, 2, 3, 4], 177 //! }; 178 //! user.serialize(&mut ser)?; 179 //! let writer = ser.into_inner(); 180 //! let size = writer.bytes_written(); 181 //! let expected = [ 182 //! 0xa2, 0x67, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x2a, 0x6d, 183 //! 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x68, 0x61, 0x73, 184 //! 0x68, 0x84, 0x1, 0x2, 0x3, 0x4 185 //! ]; 186 //! assert_eq!(&buf[..size], expected); 187 //! # Ok(()) 188 //! # } 189 //! ``` 190 //! 191 //! Deserialize an object. 192 //! ``` rust 193 //! # #[macro_use] extern crate serde_derive; 194 //! # fn main() -> Result<(), serde_cbor::Error> { 195 //! #[derive(Debug, PartialEq, Deserialize)] 196 //! struct User { 197 //! user_id: u32, 198 //! password_hash: [u8; 4], 199 //! } 200 //! 201 //! let value = [ 202 //! 0xa2, 0x67, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x2a, 0x6d, 203 //! 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x68, 0x61, 0x73, 204 //! 0x68, 0x84, 0x1, 0x2, 0x3, 0x4 205 //! ]; 206 //! 207 //! // from_slice_with_scratch will not alter input data, use it whenever you 208 //! // borrow from somewhere else. 209 //! // You will have to size your scratch according to the input data you 210 //! // expect. 211 //! use serde_cbor::de::from_slice_with_scratch; 212 //! let mut scratch = [0u8; 32]; 213 //! let user: User = from_slice_with_scratch(&value[..], &mut scratch)?; 214 //! assert_eq!(user, User { 215 //! user_id: 42, 216 //! password_hash: [1, 2, 3, 4], 217 //! }); 218 //! 219 //! let mut value = [ 220 //! 0xa2, 0x67, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x2a, 0x6d, 221 //! 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x68, 0x61, 0x73, 222 //! 0x68, 0x84, 0x1, 0x2, 0x3, 0x4 223 //! ]; 224 //! 225 //! // from_mut_slice will move data around the input slice, you may only use it 226 //! // on data you may own or can modify. 227 //! use serde_cbor::de::from_mut_slice; 228 //! let user: User = from_mut_slice(&mut value[..])?; 229 //! assert_eq!(user, User { 230 //! user_id: 42, 231 //! password_hash: [1, 2, 3, 4], 232 //! }); 233 //! # Ok(()) 234 //! # } 235 //! ``` 236 //! 237 //! # Limitations 238 //! 239 //! While Serde CBOR strives to support all features of Serde and CBOR 240 //! there are a few limitations. 241 //! 242 //! * [Tags] are ignored during deserialization and can't be emitted during 243 //! serialization. This is because Serde has no concept of tagged 244 //! values. See: [#3] 245 //! * Unknown [simple values] cause an `UnassignedCode` error. 246 //! The simple values *False* and *True* are recognized and parsed as bool. 247 //! *Null* and *Undefined* are both deserialized as *unit*. 248 //! The *unit* type is serialized as *Null*. See: [#86] 249 //! * [128-bit integers] can't be directly encoded in CBOR. If you need them 250 //! store them as a byte string. See: [#77] 251 //! 252 //! [Tags]: https://tools.ietf.org/html/rfc7049#section-2.4.4 253 //! [#3]: https://github.com/pyfisch/cbor/issues/3 254 //! [simple values]: https://tools.ietf.org/html/rfc7049#section-3.5 255 //! [#86]: https://github.com/pyfisch/cbor/issues/86 256 //! [128-bit integers]: https://doc.rust-lang.org/std/primitive.u128.html 257 //! [#77]: https://github.com/pyfisch/cbor/issues/77 258 259 #![deny(missing_docs)] 260 #![cfg_attr(not(feature = "std"), no_std)] 261 262 // When we are running tests in no_std mode we need to explicitly link std, because `cargo test` 263 // will not work without it. 264 #[cfg(all(not(feature = "std"), test))] 265 extern crate std; 266 267 #[cfg(feature = "alloc")] 268 extern crate alloc; 269 270 pub mod de; 271 pub mod error; 272 mod read; 273 pub mod ser; 274 pub mod tags; 275 mod write; 276 277 #[cfg(feature = "std")] 278 pub mod value; 279 280 // Re-export the [items recommended by serde](https://serde.rs/conventions.html). 281 #[doc(inline)] 282 pub use crate::de::{Deserializer, StreamDeserializer}; 283 284 #[doc(inline)] 285 pub use crate::error::{Error, Result}; 286 287 #[doc(inline)] 288 pub use crate::ser::Serializer; 289 290 // Convenience functions for serialization and deserialization. 291 // These functions are only available in `std` mode. 292 #[cfg(feature = "std")] 293 #[doc(inline)] 294 pub use crate::de::from_reader; 295 296 #[cfg(any(feature = "std", feature = "alloc"))] 297 #[doc(inline)] 298 pub use crate::de::from_slice; 299 300 #[cfg(any(feature = "std", feature = "alloc"))] 301 #[doc(inline)] 302 pub use crate::ser::to_vec; 303 304 #[cfg(feature = "std")] 305 #[doc(inline)] 306 pub use crate::ser::to_writer; 307 308 // Re-export the value type like serde_json 309 #[cfg(feature = "std")] 310 #[doc(inline)] 311 pub use crate::value::Value; 312