README.md
1[](https://github.com/enarx/ciborium/actions?query=workflow%3A%22test%22)
2[](https://isitmaintained.com/project/enarx/ciborium "Average time to resolve an issue")
3[](https://isitmaintained.com/project/enarx/ciborium "Percentage of issues still open")
4
5
6# ciborium-ll
7
8Low level CBOR parsing tools
9
10This crate contains low-level types for encoding and decoding items in
11CBOR. This crate is usable in both `no_std` and `no_alloc` environments.
12To understand how this crate works, first we will look at the structure
13of a CBOR item on the wire.
14
15## Anatomy of a CBOR Item
16
17This is a brief anatomy of a CBOR item on the wire.
18
19```
20+------------+-----------+
21| | |
22| Major | Minor |
23| (3bits) | (5bits) |
24| | |
25+------------+-----------+
26^ ^
27| |
28+-----+ +-----+
29 | |
30 | |
31 +----------------------------+--------------+
32 | | | |
33 | Prefix | Affix | Suffix |
34 | (1 byte) | (0-8 bytes) | (0+ bytes) |
35 | | | |
36 +------------+---------------+--------------+
37
38 | | |
39 +------------+---------------+--------------+
40 | |
41 v v
42
43 Header Body
44```
45
46The `ciborium` crate works by providing the `Decoder` and `Encoder` types
47which provide input and output for a CBOR header (see: `Header`). From
48there, you can either handle the body yourself or use the provided utility
49functions.
50
51For more information on the CBOR format, see
52[RFC 7049](https://tools.ietf.org/html/rfc7049).
53
54## Decoding
55
56In order to decode CBOR, you will create a `Decoder` from a reader. The
57decoder instance will allow you to `Decoder::pull()` `Header` instances
58from the input.
59
60Most CBOR items are fully contained in their headers and therefore have no
61body. These items can be evaluated directly from the `Header` instance.
62
63Bytes and text items have a body but do not contain child items. Since
64both bytes and text values may be segmented, parsing them can be a bit
65tricky. Therefore, we provide helper functions to parse these types. See
66`Decoder::bytes()` and `Decoder::text()` for more details.
67
68Array and map items have a body which contains child items. These can be
69parsed by simply doing `Decoder::pull()` to parse the child items.
70
71### Example
72
73```rust
74use ciborium_ll::{Decoder, Header};
75use ciborium_io::Read as _;
76
77let input = b"\x6dHello, World!";
78let mut decoder = Decoder::from(&input[..]);
79let mut chunks = 0;
80
81match decoder.pull().unwrap() {
82 Header::Text(len) => {
83 let mut segments = decoder.text(len);
84 while let Some(mut segment) = segments.pull().unwrap() {
85 let mut buffer = [0u8; 7];
86 while let Some(chunk) = segment.pull(&mut buffer[..]).unwrap() {
87 match chunk {
88 "Hello, " if chunks == 0 => chunks = 1,
89 "World!" if chunks == 1 => chunks = 2,
90 _ => panic!("received unexpected chunk"),
91 }
92 }
93 }
94 }
95
96 _ => panic!("received unexpected value"),
97}
98
99assert_eq!(chunks, 2);
100```
101
102## Encoding
103
104To encode values to CBOR, create an `Encoder` from a writer. The encoder
105instance provides the `Encoder::push()` method to write a `Header` value
106to the wire. CBOR item bodies can be written directly.
107
108For bytes and text, there are the `Encoder::bytes()` and `Encoder::text()`
109utility functions, respectively, which will properly segment the output
110on the wire for you.
111
112### Example
113
114```rust
115use ciborium_ll::{Encoder, Header};
116use ciborium_io::Write as _;
117
118let mut buffer = [0u8; 19];
119let mut encoder = Encoder::from(&mut buffer[..]);
120
121// Write the structure
122encoder.push(Header::Map(Some(1))).unwrap();
123encoder.push(Header::Positive(7)).unwrap();
124encoder.text("Hello, World!", 7).unwrap();
125
126// Validate our output
127encoder.flush().unwrap();
128assert_eq!(b"\xa1\x07\x7f\x67Hello, \x66World!\xff", &buffer[..]);
129```
130
131License: Apache-2.0
132