1// SPDX-License-Identifier: Apache-2.0
2
3//! Low level CBOR parsing tools
4//!
5//! This crate contains low-level types for encoding and decoding items in
6//! CBOR. This crate is usable in both `no_std` and `no_alloc` environments.
7//! To understand how this crate works, first we will look at the structure
8//! of a CBOR item on the wire.
9//!
10//! # Anatomy of a CBOR Item
11//!
12//! This is a brief anatomy of a CBOR item on the wire.
13//!
14//! ```text
15//! +------------+-----------+
16//! | | |
17//! | Major | Minor |
18//! | (3bits) | (5bits) |
19//! | | |
20//! +------------+-----------+
21//! ^ ^
22//! | |
23//! +-----+ +-----+
24//! | |
25//! | |
26//! +----------------------------+--------------+
27//! | | | |
28//! | Prefix | Affix | Suffix |
29//! | (1 byte) | (0-8 bytes) | (0+ bytes) |
30//! | | | |
31//! +------------+---------------+--------------+
32//!
33//! | | |
34//! +------------+---------------+--------------+
35//! | |
36//! v v
37//!
38//! Header Body
39//! ```
40//!
41//! The `ciborium` crate works by providing the `Decoder` and `Encoder` types
42//! which provide input and output for a CBOR header (see: `Header`). From
43//! there, you can either handle the body yourself or use the provided utility
44//! functions.
45//!
46//! For more information on the CBOR format, see
47//! [RFC 7049](https://tools.ietf.org/html/rfc7049).
48//!
49//! # Decoding
50//!
51//! In order to decode CBOR, you will create a `Decoder` from a reader. The
52//! decoder instance will allow you to `Decoder::pull()` `Header` instances
53//! from the input.
54//!
55//! Most CBOR items are fully contained in their headers and therefore have no
56//! body. These items can be evaluated directly from the `Header` instance.
57//!
58//! Bytes and text items have a body but do not contain child items. Since
59//! both bytes and text values may be segmented, parsing them can be a bit
60//! tricky. Therefore, we provide helper functions to parse these types. See
61//! `Decoder::bytes()` and `Decoder::text()` for more details.
62//!
63//! Array and map items have a body which contains child items. These can be
64//! parsed by simply doing `Decoder::pull()` to parse the child items.
65//!
66//! ## Example
67//!
68//! ```rust
69//! use ciborium_ll::{Decoder, Header};
70//! use ciborium_io::Read as _;
71//!
72//! let input = b"\x6dHello, World!";
73//! let mut decoder = Decoder::from(&input[..]);
74//! let mut chunks = 0;
75//!
76//! match decoder.pull().unwrap() {
77//! Header::Text(len) => {
78//! let mut segments = decoder.text(len);
79//! while let Some(mut segment) = segments.pull().unwrap() {
80//! let mut buffer = [0u8; 7];
81//! while let Some(chunk) = segment.pull(&mut buffer[..]).unwrap() {
82//! match chunk {
83//! "Hello, " if chunks == 0 => chunks = 1,
84//! "World!" if chunks == 1 => chunks = 2,
85//! _ => panic!("received unexpected chunk"),
86//! }
87//! }
88//! }
89//! }
90//!
91//! _ => panic!("received unexpected value"),
92//! }
93//!
94//! assert_eq!(chunks, 2);
95//! ```
96//!
97//! # Encoding
98//!
99//! To encode values to CBOR, create an `Encoder` from a writer. The encoder
100//! instance provides the `Encoder::push()` method to write a `Header` value
101//! to the wire. CBOR item bodies can be written directly.
102//!
103//! For bytes and text, there are the `Encoder::bytes()` and `Encoder::text()`
104//! utility functions, respectively, which will properly segment the output
105//! on the wire for you.
106//!
107//! ## Example
108//!
109//! ```rust
110//! use ciborium_ll::{Encoder, Header};
111//! use ciborium_io::Write as _;
112//!
113//! let mut buffer = [0u8; 19];
114//! let mut encoder = Encoder::from(&mut buffer[..]);
115//!
116//! // Write the structure
117//! encoder.push(Header::Map(Some(1))).unwrap();
118//! encoder.push(Header::Positive(7)).unwrap();
119//! encoder.text("Hello, World!", 7).unwrap();
120//!
121//! // Validate our output
122//! encoder.flush().unwrap();
123//! assert_eq!(b"\xa1\x07\x7f\x67Hello, \x66World!\xff", &buffer[..]);
124//! ```
125
126#![cfg_attr(not(feature = "std"), no_std)]
127#![deny(missing_docs)]
128#![deny(clippy::all)]
129#![deny(clippy::cargo)]
130
131#[cfg(feature = "alloc")]
132extern crate alloc;
133
134mod dec;
135mod enc;
136mod hdr;
137mod seg;
138
139pub use dec::*;
140pub use enc::*;
141pub use hdr::*;
142pub use seg::{Segment, Segments};
143
144/// Simple value constants
145pub mod simple {
146 #![allow(missing_docs)]
147
148 pub const FALSE: u8 = 20;
149 pub const TRUE: u8 = 21;
150 pub const NULL: u8 = 22;
151 pub const UNDEFINED: u8 = 23;
152}
153
154/// Tag constants
155pub mod tag {
156 #![allow(missing_docs)]
157
158 pub const BIGPOS: u64 = 2;
159 pub const BIGNEG: u64 = 3;
160}
161
162#[derive(Debug)]
163struct InvalidError(());
164
165#[derive(Copy, Clone, Debug, PartialEq, Eq)]
166enum Major {
167 Positive,
168 Negative,
169 Bytes,
170 Text,
171 Array,
172 Map,
173 Tag,
174 Other,
175}
176
177#[derive(Copy, Clone, Debug, PartialEq, Eq)]
178enum Minor {
179 This(u8),
180 Next1([u8; 1]),
181 Next2([u8; 2]),
182 Next4([u8; 4]),
183 Next8([u8; 8]),
184 More,
185}
186
187impl AsRef<[u8]> for Minor {
188 #[inline]
189 fn as_ref(&self) -> &[u8] {
190 match self {
191 Self::More => &[],
192 Self::This(..) => &[],
193 Self::Next1(x) => x.as_ref(),
194 Self::Next2(x) => x.as_ref(),
195 Self::Next4(x) => x.as_ref(),
196 Self::Next8(x) => x.as_ref(),
197 }
198 }
199}
200
201impl AsMut<[u8]> for Minor {
202 #[inline]
203 fn as_mut(&mut self) -> &mut [u8] {
204 match self {
205 Self::More => &mut [],
206 Self::This(..) => &mut [],
207 Self::Next1(x) => x.as_mut(),
208 Self::Next2(x) => x.as_mut(),
209 Self::Next4(x) => x.as_mut(),
210 Self::Next8(x) => x.as_mut(),
211 }
212 }
213}
214
215#[derive(Copy, Clone, Debug, PartialEq, Eq)]
216struct Title(pub Major, pub Minor);
217
218#[cfg(test)]
219mod tests {
220 use super::*;
221
222 macro_rules! neg {
223 ($i:expr) => {
224 Header::Negative((($i as i128) ^ !0) as u64)
225 };
226 }
227
228 #[allow(clippy::excessive_precision)]
229 #[test]
230 fn leaf() {
231 use core::f64::{INFINITY, NAN};
232
233 let data = &[
234 (Header::Positive(0), "00", true),
235 (Header::Positive(1), "01", true),
236 (Header::Positive(10), "0a", true),
237 (Header::Positive(23), "17", true),
238 (Header::Positive(24), "1818", true),
239 (Header::Positive(25), "1819", true),
240 (Header::Positive(100), "1864", true),
241 (Header::Positive(1000), "1903e8", true),
242 (Header::Positive(1000000), "1a000f4240", true),
243 (Header::Positive(1000000000000), "1b000000e8d4a51000", true),
244 (
245 Header::Positive(18446744073709551615),
246 "1bffffffffffffffff",
247 true,
248 ),
249 (neg!(-18446744073709551616), "3bffffffffffffffff", true),
250 (neg!(-1), "20", true),
251 (neg!(-10), "29", true),
252 (neg!(-100), "3863", true),
253 (neg!(-1000), "3903e7", true),
254 (Header::Float(0.0), "f90000", true),
255 (Header::Float(-0.0), "f98000", true),
256 (Header::Float(1.0), "f93c00", true),
257 (Header::Float(1.1), "fb3ff199999999999a", true),
258 (Header::Float(1.5), "f93e00", true),
259 (Header::Float(65504.0), "f97bff", true),
260 (Header::Float(100000.0), "fa47c35000", true),
261 (Header::Float(3.4028234663852886e+38), "fa7f7fffff", true),
262 (Header::Float(1.0e+300), "fb7e37e43c8800759c", true),
263 (Header::Float(5.960464477539063e-8), "f90001", true),
264 (Header::Float(0.00006103515625), "f90400", true),
265 (Header::Float(-4.0), "f9c400", true),
266 (Header::Float(-4.1), "fbc010666666666666", true),
267 (Header::Float(INFINITY), "f97c00", true),
268 (Header::Float(NAN), "f97e00", true),
269 (Header::Float(-INFINITY), "f9fc00", true),
270 (Header::Float(INFINITY), "fa7f800000", false),
271 (Header::Float(NAN), "fa7fc00000", false),
272 (Header::Float(-INFINITY), "faff800000", false),
273 (Header::Float(INFINITY), "fb7ff0000000000000", false),
274 (Header::Float(NAN), "fb7ff8000000000000", false),
275 (Header::Float(-INFINITY), "fbfff0000000000000", false),
276 (Header::Simple(simple::FALSE), "f4", true),
277 (Header::Simple(simple::TRUE), "f5", true),
278 (Header::Simple(simple::NULL), "f6", true),
279 (Header::Simple(simple::UNDEFINED), "f7", true),
280 (Header::Simple(16), "f0", true),
281 (Header::Simple(24), "f818", true),
282 (Header::Simple(255), "f8ff", true),
283 (Header::Tag(0), "c0", true),
284 (Header::Tag(1), "c1", true),
285 (Header::Tag(23), "d7", true),
286 (Header::Tag(24), "d818", true),
287 (Header::Tag(32), "d820", true),
288 (Header::Bytes(Some(0)), "40", true),
289 (Header::Bytes(Some(4)), "44", true),
290 (Header::Text(Some(0)), "60", true),
291 (Header::Text(Some(4)), "64", true),
292 ];
293
294 for (header, bytes, encode) in data.iter().cloned() {
295 let bytes = hex::decode(bytes).unwrap();
296
297 let mut decoder = Decoder::from(&bytes[..]);
298 match (header, decoder.pull().unwrap()) {
299 // NaN equality...
300 (Header::Float(l), Header::Float(r)) if l.is_nan() && r.is_nan() => (),
301
302 // Everything else...
303 (l, r) => assert_eq!(l, r),
304 }
305
306 if encode {
307 let mut buffer = [0u8; 1024];
308 let mut writer = &mut buffer[..];
309 let mut encoder = Encoder::from(&mut writer);
310 encoder.push(header).unwrap();
311
312 let len = writer.len();
313 assert_eq!(&bytes[..], &buffer[..1024 - len]);
314 }
315 }
316 }
317
318 #[test]
319 fn node() {
320 let data: &[(&str, &[Header])] = &[
321 ("80", &[Header::Array(Some(0))]),
322 (
323 "83010203",
324 &[
325 Header::Array(Some(3)),
326 Header::Positive(1),
327 Header::Positive(2),
328 Header::Positive(3),
329 ],
330 ),
331 (
332 "98190102030405060708090a0b0c0d0e0f101112131415161718181819",
333 &[
334 Header::Array(Some(25)),
335 Header::Positive(1),
336 Header::Positive(2),
337 Header::Positive(3),
338 Header::Positive(4),
339 Header::Positive(5),
340 Header::Positive(6),
341 Header::Positive(7),
342 Header::Positive(8),
343 Header::Positive(9),
344 Header::Positive(10),
345 Header::Positive(11),
346 Header::Positive(12),
347 Header::Positive(13),
348 Header::Positive(14),
349 Header::Positive(15),
350 Header::Positive(16),
351 Header::Positive(17),
352 Header::Positive(18),
353 Header::Positive(19),
354 Header::Positive(20),
355 Header::Positive(21),
356 Header::Positive(22),
357 Header::Positive(23),
358 Header::Positive(24),
359 Header::Positive(25),
360 ],
361 ),
362 ("a0", &[Header::Map(Some(0))]),
363 (
364 "a201020304",
365 &[
366 Header::Map(Some(2)),
367 Header::Positive(1),
368 Header::Positive(2),
369 Header::Positive(3),
370 Header::Positive(4),
371 ],
372 ),
373 ("9fff", &[Header::Array(None), Header::Break]),
374 (
375 "9f018202039f0405ffff",
376 &[
377 Header::Array(None),
378 Header::Positive(1),
379 Header::Array(Some(2)),
380 Header::Positive(2),
381 Header::Positive(3),
382 Header::Array(None),
383 Header::Positive(4),
384 Header::Positive(5),
385 Header::Break,
386 Header::Break,
387 ],
388 ),
389 (
390 "9f01820203820405ff",
391 &[
392 Header::Array(None),
393 Header::Positive(1),
394 Header::Array(Some(2)),
395 Header::Positive(2),
396 Header::Positive(3),
397 Header::Array(Some(2)),
398 Header::Positive(4),
399 Header::Positive(5),
400 Header::Break,
401 ],
402 ),
403 (
404 "83018202039f0405ff",
405 &[
406 Header::Array(Some(3)),
407 Header::Positive(1),
408 Header::Array(Some(2)),
409 Header::Positive(2),
410 Header::Positive(3),
411 Header::Array(None),
412 Header::Positive(4),
413 Header::Positive(5),
414 Header::Break,
415 ],
416 ),
417 (
418 "83019f0203ff820405",
419 &[
420 Header::Array(Some(3)),
421 Header::Positive(1),
422 Header::Array(None),
423 Header::Positive(2),
424 Header::Positive(3),
425 Header::Break,
426 Header::Array(Some(2)),
427 Header::Positive(4),
428 Header::Positive(5),
429 ],
430 ),
431 (
432 "9f0102030405060708090a0b0c0d0e0f101112131415161718181819ff",
433 &[
434 Header::Array(None),
435 Header::Positive(1),
436 Header::Positive(2),
437 Header::Positive(3),
438 Header::Positive(4),
439 Header::Positive(5),
440 Header::Positive(6),
441 Header::Positive(7),
442 Header::Positive(8),
443 Header::Positive(9),
444 Header::Positive(10),
445 Header::Positive(11),
446 Header::Positive(12),
447 Header::Positive(13),
448 Header::Positive(14),
449 Header::Positive(15),
450 Header::Positive(16),
451 Header::Positive(17),
452 Header::Positive(18),
453 Header::Positive(19),
454 Header::Positive(20),
455 Header::Positive(21),
456 Header::Positive(22),
457 Header::Positive(23),
458 Header::Positive(24),
459 Header::Positive(25),
460 Header::Break,
461 ],
462 ),
463 ];
464
465 for (bytes, headers) in data {
466 let bytes = hex::decode(bytes).unwrap();
467
468 // Test decoding
469 let mut decoder = Decoder::from(&bytes[..]);
470 for header in headers.iter().cloned() {
471 assert_eq!(header, decoder.pull().unwrap());
472 }
473
474 // Test encoding
475 let mut buffer = [0u8; 1024];
476 let mut writer = &mut buffer[..];
477 let mut encoder = Encoder::from(&mut writer);
478
479 for header in headers.iter().cloned() {
480 encoder.push(header).unwrap();
481 }
482
483 let len = writer.len();
484 assert_eq!(&bytes[..], &buffer[..1024 - len]);
485 }
486 }
487}
488