petra/
marker.rs

1use crate::Error;
2
3const POSIMM_CODE: u8 = 0b00000000;
4const POSIMM_MASK: u8 = 0b01111111;
5const POSIMM_LAST: u8 = POSIMM_CODE + POSIMM_MASK;
6
7const NEGIMM_CODE: u8 = 0b11100000;
8const NEGIMM_MASK: u8 = 0b00011111;
9const NEGIMM_LAST: u8 = NEGIMM_CODE + NEGIMM_MASK;
10
11const STRIMM_CODE: u8 = 0b10000000;
12const STRIMM_MASK: u8 = 0b00011111;
13const STRIMM_LAST: u8 = STRIMM_CODE + STRIMM_MASK;
14
15const ARRIMM_CODE: u8 = 0b10100000;
16const ARRIMM_MASK: u8 = 0b00001111;
17const ARRIMM_LAST: u8 = ARRIMM_CODE + ARRIMM_MASK;
18
19const MAPIMM_CODE: u8 = 0b10110000;
20const MAPIMM_MASK: u8 = 0b00001111;
21const MAPIMM_LAST: u8 = MAPIMM_CODE + MAPIMM_MASK;
22
23const BITS_8: u8 = 0b00;
24const BITS_16: u8 = 0b01;
25const BITS_32: u8 = 0b10;
26const BITS_64: u8 = 0b11;
27
28const FLEX: u8 = 0b11;
29
30const ARRAY_CODE: u8 = 0b11000000;
31const ARRAY_CODE_U8: u8 = ARRAY_CODE + BITS_8;
32const ARRAY_CODE_U16: u8 = ARRAY_CODE + BITS_16;
33const ARRAY_CODE_U32: u8 = ARRAY_CODE + BITS_32;
34const ARRAY_CODE_FLEX: u8 = ARRAY_CODE + FLEX;
35
36const MAP_CODE: u8 = 0b11000100;
37const MAP_CODE_U8: u8 = MAP_CODE + BITS_8;
38const MAP_CODE_U16: u8 = MAP_CODE + BITS_16;
39const MAP_CODE_U32: u8 = MAP_CODE + BITS_32;
40const MAP_CODE_FLEX: u8 = MAP_CODE + FLEX;
41
42const UNSIGNED_CODE: u8 = 0b11001000;
43const UNSIGNED_CODE_U8: u8 = UNSIGNED_CODE + BITS_8;
44const UNSIGNED_CODE_U16: u8 = UNSIGNED_CODE + BITS_16;
45const UNSIGNED_CODE_U32: u8 = UNSIGNED_CODE + BITS_32;
46const UNSIGNED_CODE_U64: u8 = UNSIGNED_CODE + BITS_64;
47
48const SIGNED_CODE: u8 = 0b11001100;
49const SIGNED_CODE_U8: u8 = SIGNED_CODE + BITS_8;
50const SIGNED_CODE_U16: u8 = SIGNED_CODE + BITS_16;
51const SIGNED_CODE_U32: u8 = SIGNED_CODE + BITS_32;
52const SIGNED_CODE_U64: u8 = SIGNED_CODE + BITS_64;
53
54const STR_CODE: u8 = 0b11010000;
55const STR_CODE_U8: u8 = STR_CODE + BITS_8;
56const STR_CODE_U16: u8 = STR_CODE + BITS_16;
57const STR_CODE_U32: u8 = STR_CODE + BITS_32;
58
59const BIN_CODE: u8 = 0b11010100;
60const BIN_CODE_U8: u8 = BIN_CODE + BITS_8;
61const BIN_CODE_U16: u8 = BIN_CODE + BITS_16;
62const BIN_CODE_U32: u8 = BIN_CODE + BITS_32;
63
64const FLOAT_CODE_32: u8 = 0b11011010;
65const FLOAT_CODE_64: u8 = FLOAT_CODE_32 + 1;
66
67const BOOL_CODE_0: u8 = 0b11011100;
68const BOOL_CODE_1: u8 = BOOL_CODE_0 + 1;
69
70const NULL_CODE: u8 = 0b11011110;
71const TERM_CODE: u8 = 0b11011111;
72
73const BOOL_MASK: u8 = 0b00000001;
74
75/// Data marker for the encoded data.
76///
77/// The marker identifies the data type of the encoded data immediately following the marker.
78/// The marker itself is encoded as a numerical 8-bit value and can be followed by at most 9 bytes of additional data.
79/// Some marker values support immediate data, i.e. the data represented by the marker is encoded into the marker itself.
80/// Other marker values encode immediate length values.
81///
82/// For more information on each marker variant, see their individual documentation.
83pub enum Marker {
84    /// Immediate positive value in the range [0, 128).
85    ImmPos {
86        /// The encoded positive value.
87        value: u8,
88    },
89
90    /// Immediate negative value in the range [-32, 0).
91    ImmNeg {
92        /// The encoded negative value.
93        value: i8,
94    },
95
96    /// Immediate string length, in the range [0, 32).
97    ImmStr {
98        /// The encoded string length.
99        len: u8,
100    },
101
102    /// Immediate array length, in the range [0, 16).
103    ImmArr {
104        /// The encoded array length.
105        len: u8,
106    },
107
108    /// Immediate map length, in the range [0, 16).
109    ImmMap {
110        /// The encoded map length.
111        len: u8,
112    },
113
114    /// The next 8 bits after the marker encode the length of an array, and the array data follows.
115    A8,
116
117    /// The next 16 bits after the marker encode the length of an array, and the array data follows.
118    A16,
119
120    /// The next 32 bits after the marker encode the length of an array, and the array data follows.
121    A32,
122
123    /// Immediately following the marker, a flexible array is encoded.
124    /// The flexible array must be terminated by encoding a [`Term`](Marker::Term) marker after the last element of the array.
125    AFlex,
126
127    /// The next 8 bits after the marker encode the length of a map, and the map data follows.
128    M8,
129
130    /// The next 16 bits after the marker encode the length of a map, and the map data follows.
131    M16,
132
133    /// The next 32 bits after the marker encode the length of a map, and the map data follows.
134    M32,
135
136    /// Immediately following the marker, a flexible map is encoded.
137    /// The flexible map must be terminated by encoding a [`Term`](Marker::Term) marker after the last element of the map.
138    MFlex,
139
140    /// The next 8 bits after the marker encode a `u8` value.
141    U8,
142
143    /// The next 16 bits after the marker encode a `u16` value.
144    U16,
145
146    /// The next 32 bits after the marker encode a `u32` value.
147    U32,
148
149    /// The next 64 bits after the marker encode a `u64` value.
150    U64,
151
152    /// The next 8 bits after the marker encode a `i8` value.
153    I8,
154
155    /// The next 16 bits after the marker encode a `i16` value.
156    I16,
157
158    /// The next 32 bits after the marker encode a `i32` value.
159    I32,
160
161    /// The next 64 bits after the marker encode a `i64` value.
162    I64,
163
164    /// The next 8 bits after the marker encode the length of a string, and the string data follows.
165    S8,
166
167    /// The next 16 bits after the marker encode the length of a string, and the string data follows.
168    S16,
169
170    /// The next 32 bits after the marker encode the length of a string, and the string data follows.
171    S32,
172
173    /// The next 8 bits after the marker encode the length of a byte array, and the binary data follows.
174    B8,
175
176    /// The next 16 bits after the marker encode the length of a byte array, and the binary data follows.
177    B16,
178
179    /// The next 32 bits after the marker encode the length of a byte array, and the binary data follows.
180    B32,
181
182    /// The next 32 bits after the marker encode a `f32` value.
183    F32,
184
185    /// The next 64 bits after the marker encode a `f64` value.
186    F64,
187
188    /// The marker encodes a boolean value.
189    Bool {
190        /// The encoded boolean value.
191        value: bool,
192    },
193
194    /// The marker encodes a null or unit value, i.e. `()`.
195    Null,
196
197    /// The marker encodes a flexible container terminator.
198    Term,
199
200    /// Reserved, do not use.
201    Reserved,
202}
203
204impl Marker {
205    fn code(&self) -> u8 {
206        match self {
207            Marker::ImmPos { .. } => POSIMM_CODE,
208            Marker::ImmNeg { .. } => NEGIMM_CODE,
209            Marker::ImmStr { .. } => STRIMM_CODE,
210            Marker::ImmArr { .. } => ARRIMM_CODE,
211            Marker::ImmMap { .. } => MAPIMM_CODE,
212
213            Marker::A8 => ARRAY_CODE_U8,
214            Marker::A16 => ARRAY_CODE_U16,
215            Marker::A32 => ARRAY_CODE_U32,
216            Marker::AFlex => ARRAY_CODE_FLEX,
217
218            Marker::M8 => MAP_CODE_U8,
219            Marker::M16 => MAP_CODE_U16,
220            Marker::M32 => MAP_CODE_U32,
221            Marker::MFlex => MAP_CODE_FLEX,
222
223            Marker::U8 => UNSIGNED_CODE_U8,
224            Marker::U16 => UNSIGNED_CODE_U16,
225            Marker::U32 => UNSIGNED_CODE_U32,
226            Marker::U64 => UNSIGNED_CODE_U64,
227
228            Marker::I8 => SIGNED_CODE_U8,
229            Marker::I16 => SIGNED_CODE_U16,
230            Marker::I32 => SIGNED_CODE_U32,
231            Marker::I64 => SIGNED_CODE_U64,
232
233            Marker::S8 => STR_CODE_U8,
234            Marker::S16 => STR_CODE_U16,
235            Marker::S32 => STR_CODE_U32,
236
237            Marker::B8 => BIN_CODE_U8,
238            Marker::B16 => BIN_CODE_U16,
239            Marker::B32 => BIN_CODE_U32,
240
241            Marker::F32 => FLOAT_CODE_32,
242            Marker::F64 => FLOAT_CODE_64,
243
244            Marker::Bool { .. } => BOOL_CODE_0,
245
246            Marker::Null => NULL_CODE,
247            Marker::Term => TERM_CODE,
248
249            Marker::Reserved => panic!(),
250        }
251    }
252
253    fn mask(&self) -> u8 {
254        match self {
255            Marker::ImmPos { .. } => POSIMM_MASK,
256            Marker::ImmNeg { .. } => NEGIMM_MASK,
257            Marker::ImmStr { .. } => STRIMM_MASK,
258            Marker::ImmArr { .. } => ARRIMM_MASK,
259            Marker::ImmMap { .. } => MAPIMM_MASK,
260
261            Marker::Bool { .. } => BOOL_MASK,
262
263            Marker::Reserved => panic!(),
264
265            _ => 0,
266        }
267    }
268
269    /// Given a marker, return the numerical encoding.
270    pub fn encoding(&self) -> u8 {
271        let code = self.code();
272        let mask = self.mask();
273
274        let imm = match self {
275            Marker::ImmPos { value } => *value,
276            Marker::ImmNeg { value } => *value as u8,
277            Marker::ImmStr { len } | Marker::ImmArr { len } | Marker::ImmMap { len } => *len,
278            Marker::Bool { value } => *value as u8,
279
280            _ => 0,
281        };
282
283        code | (imm & mask)
284    }
285
286    /// Return the number of additional bytes following the marker for a complete read.
287    ///
288    /// This method only returns the number of bytes required by the marker.
289    /// It does not count the data bytes following the marker, for example in the case of length markers.
290    pub fn argument_bytes(&self) -> usize {
291        match self {
292            Marker::A8 | Marker::M8 | Marker::U8 | Marker::I8 | Marker::S8 | Marker::B8 => 1,
293            Marker::A16 | Marker::M16 | Marker::U16 | Marker::I16 | Marker::S16 | Marker::B16 => 2,
294
295            Marker::A32
296            | Marker::M32
297            | Marker::U32
298            | Marker::I32
299            | Marker::S32
300            | Marker::B32
301            | Marker::F32 => 4,
302
303            Marker::U64 | Marker::I64 | Marker::F64 => 8,
304
305            Marker::Reserved => panic!(),
306
307            _ => 0,
308        }
309    }
310
311    /// Try to decode a numerical value into a valid marker.
312    ///
313    /// # Errors
314    /// This method returns [`BadMarker`](Error::BadMarker) if an attempt is made to decode reserved marker values.
315    pub fn decode(value: u8) -> Result<Self, Error> {
316        let marker = match value {
317            POSIMM_CODE..=POSIMM_LAST => Marker::ImmPos { value },
318            NEGIMM_CODE..=NEGIMM_LAST => Marker::ImmNeg { value: value as i8 },
319            STRIMM_CODE..=STRIMM_LAST => Marker::ImmStr {
320                len: value & STRIMM_MASK,
321            },
322            ARRIMM_CODE..=ARRIMM_LAST => Marker::ImmArr {
323                len: value & ARRIMM_MASK,
324            },
325            MAPIMM_CODE..=MAPIMM_LAST => Marker::ImmMap {
326                len: value & MAPIMM_MASK,
327            },
328
329            ARRAY_CODE_U8 => Marker::A8,
330            ARRAY_CODE_U16 => Marker::A16,
331            ARRAY_CODE_U32 => Marker::A32,
332            ARRAY_CODE_FLEX => Marker::AFlex,
333
334            MAP_CODE_U8 => Marker::M8,
335            MAP_CODE_U16 => Marker::M16,
336            MAP_CODE_U32 => Marker::M32,
337            MAP_CODE_FLEX => Marker::MFlex,
338
339            UNSIGNED_CODE_U8 => Marker::U8,
340            UNSIGNED_CODE_U16 => Marker::U16,
341            UNSIGNED_CODE_U32 => Marker::U32,
342            UNSIGNED_CODE_U64 => Marker::U64,
343
344            SIGNED_CODE_U8 => Marker::I8,
345            SIGNED_CODE_U16 => Marker::I16,
346            SIGNED_CODE_U32 => Marker::I32,
347            SIGNED_CODE_U64 => Marker::I64,
348
349            STR_CODE_U8 => Marker::S8,
350            STR_CODE_U16 => Marker::S16,
351            STR_CODE_U32 => Marker::S32,
352
353            BIN_CODE_U8 => Marker::B8,
354            BIN_CODE_U16 => Marker::B16,
355            BIN_CODE_U32 => Marker::B32,
356
357            FLOAT_CODE_32 => Marker::F32,
358            FLOAT_CODE_64 => Marker::F64,
359
360            BOOL_CODE_0 => Marker::Bool { value: false },
361            BOOL_CODE_1 => Marker::Bool { value: true },
362
363            NULL_CODE => Marker::Null,
364            TERM_CODE => Marker::Term,
365
366            _ => return Err(Error::BadMarker),
367        };
368
369        Ok(marker)
370    }
371
372    /// Return `true` if the marker represents a string data type.
373    pub fn is_str(&self) -> bool {
374        match self {
375            Marker::ImmStr { .. } | Marker::S8 | Marker::S16 | Marker::S32 => true,
376            _ => false,
377        }
378    }
379
380    /// Return `true` if the marker represents a map data type, including flexible maps.
381    pub fn is_map(&self) -> bool {
382        match self {
383            Marker::ImmMap { .. } | Marker::M8 | Marker::M16 | Marker::M32 | Marker::MFlex => true,
384            _ => false,
385        }
386    }
387
388    /// Return `true` if the marker represents an array data type, including flexible arrays.
389    pub fn is_array(&self) -> bool {
390        match self {
391            Marker::ImmArr { .. } | Marker::A8 | Marker::A16 | Marker::A32 | Marker::AFlex => true,
392            _ => false,
393        }
394    }
395}