Coverage Report

Created: 2025-02-25 06:39

/rust/registry/src/index.crates.io-6f17d22bba15001f/ciborium-ll-0.2.2/src/lib.rs
Line
Count
Source (jump to first uncovered line)
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")]
132
extern crate alloc;
133
134
mod dec;
135
mod enc;
136
mod hdr;
137
mod seg;
138
139
pub use dec::*;
140
pub use enc::*;
141
pub use hdr::*;
142
pub use seg::{Segment, Segments};
143
144
/// Simple value constants
145
pub 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
155
pub mod tag {
156
    #![allow(missing_docs)]
157
158
    pub const BIGPOS: u64 = 2;
159
    pub const BIGNEG: u64 = 3;
160
}
161
162
#[derive(Debug)]
163
struct InvalidError(());
164
165
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
166
enum 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)]
178
enum Minor {
179
    This(u8),
180
    Next1([u8; 1]),
181
    Next2([u8; 2]),
182
    Next4([u8; 4]),
183
    Next8([u8; 8]),
184
    More,
185
}
186
187
impl AsRef<[u8]> for Minor {
188
    #[inline]
189
0
    fn as_ref(&self) -> &[u8] {
190
0
        match self {
191
0
            Self::More => &[],
192
0
            Self::This(..) => &[],
193
0
            Self::Next1(x) => x.as_ref(),
194
0
            Self::Next2(x) => x.as_ref(),
195
0
            Self::Next4(x) => x.as_ref(),
196
0
            Self::Next8(x) => x.as_ref(),
197
        }
198
0
    }
Unexecuted instantiation: <ciborium_ll::Minor as core::convert::AsRef<[u8]>>::as_ref
Unexecuted instantiation: <ciborium_ll::Minor as core::convert::AsRef<[u8]>>::as_ref
Unexecuted instantiation: <ciborium_ll::Minor as core::convert::AsRef<[u8]>>::as_ref
199
}
200
201
impl AsMut<[u8]> for Minor {
202
    #[inline]
203
0
    fn as_mut(&mut self) -> &mut [u8] {
204
0
        match self {
205
0
            Self::More => &mut [],
206
0
            Self::This(..) => &mut [],
207
0
            Self::Next1(x) => x.as_mut(),
208
0
            Self::Next2(x) => x.as_mut(),
209
0
            Self::Next4(x) => x.as_mut(),
210
0
            Self::Next8(x) => x.as_mut(),
211
        }
212
0
    }
Unexecuted instantiation: <ciborium_ll::Minor as core::convert::AsMut<[u8]>>::as_mut
Unexecuted instantiation: <ciborium_ll::Minor as core::convert::AsMut<[u8]>>::as_mut
213
}
214
215
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
216
struct Title(pub Major, pub Minor);
217
218
#[cfg(test)]
219
mod 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
}