1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
//! # cboritem: A serialized CBOR item
//!
//! A [`CborItem<'a>`](CborItem) is a newtype around [`&'a [u8]`](u8) that upholds the invariant of
//! containing a single serialized CBOR item. A [`ThinCborItem<'a>`](ThinCborItem) is its start
//! pointer; when accessing it, users rely on that property to stop reading at the end of the item.
//!
//! In a sense, the types are similar to [`&str`](str) and [`CStr`](core::ffi::CStr), respectively,
//! once the latter follows the [plan] of eventually becoming a thin pointer.
//!
//! ## Library use
//!
//! Their use is for efficiently storing pre-verified slices of CBOR items, eg. when implementing
//! [packed CBOR]. They can also serve as an interface point between CBOR libraries (easing error
//! handling because end-of-stream and bytes-after-the-data errors are panic-worthy invariants;
//! other parsing errors may still occur if there is any well-formed data the parser can not
//! process, or that violates basic validity requirements), and as a marker type by which CBOR
//! parsers can be instructed to process any item into a slice for later detailed inspection.
//!
//! This crate is not a CBOR library, thus it contains no functions to safely create any of its
//! types (as that requires a CBOR parser). Instead, its intention is to be produced by CBOR
//! parsers after they have verified that the invariant upholds.
//!
//! ## Invariant definition
//!
//! The invariant upheld in this crate's types is that their bytes are exactly one well-formed CBOR
//! item as defined in [RFC8949]; in particular, that means they contain at least one byte.
//!
//! The invariants in this crates are **soundness invariants**: Receivers of a CBOR item may not
//! just panic when they find invalid CBOR, but they may invoke undefined behavior (eg. by calling
//! [`unreachable_unchecked`](core::hint::unreachable_unchecked). Consequently, creating a CBOR
//! item requires use of the `unsafe` keyword, with the invariants being checked by the parser that
//! creates the item.
//!
//! This is a necessary consequence of providing thin pointers: The invariants are relied on by
//! users who read through a raw pointer, which on inaccurate data would result in reads beyond the
//! original allocated object, which is undefined behavior.
//!
//! ## Examples
//!
//! ```
//! use cboritem::{CborItem, ThinCborItem};
//! let onehundred = [0x24, 0x64];
//! assert_eq!(onehundred[0], 0x24);
//! let onehundred = unsafe { CborItem::new(&onehundred) };
//! let onehundred: ThinCborItem<'_> = onehundred.as_thin();
//! assert_eq!(core::mem::size_of_val(&onehundred), core::mem::size_of::<&u8>());
//! // One byte can always be read, so we don't need a CBOR parser to tell us it is safe
//! if onehundred.first() == 0x24 {
//! assert_eq!(unsafe { onehundred.offset(1).read() }, 100);
//! } else {
//! panic!("Unexpected type or integer size");
//! }
//! ```
//!
//! ## Future development
//!
//! Later versions may add types or variants of the current types (by means of associated types
//! with a default), eg. to descibe additional constraints such as
//!
//! * Embedded strings are UTF-8
//! * No duplicate keys are present
//! * Adhers to the Common Deterministic Encoding
//! * Contains no indefinite-length items
//! * The CBOR item conforms to some particular CDDL structure
//!
//! If any extensions are made that change CBOR's validity rules (eg. i=28 is defined for 128-bit
//! integer arguments), this crate would go through a major release to support them.
//!
//! [plan]: https://internals.rust-lang.org/t/pre-rfc-make-cstr-a-thin-pointer/6258
//! [packed CBOR]: https://datatracker.ietf.org/doc/draft-ietf-cbor-packed/
//! [RFC8949]: https://datatracker.ietf.org/doc/html/rfc8949
/// A transparent newtype around a `&[u8]` with the invariant that the slice contains one encoded CBOR item
///
/// Its main use is through dereferencing it into as a slice.
///
/// # Invariants
///
/// The slice contains exactly one well-formed CBOR item.
;
// FIXME: This should be Target = [u8]. (The &self takes care not to
// produce slices that outlive self, and the produced type should also have the right variance, and
// this may even fix the missing `.as_ref()` in AsRef).
/// A thin reference to self-delimited memory that contians a single encoded CBOR item
///
/// # Invariants
///
/// The pointer is readable for the lifetime of the type. There is a single CBOR item behind the
/// pointer, which may be read through it. The position after the CBOR item can be calculated, but
/// reading it may not be allowed.