oasis_cbor_value/
writer.rs

1// Copyright 2019 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Functionality for serializing CBOR values into bytes.
16
17use alloc::vec::Vec;
18
19use super::values::{Constants, Value};
20
21/// Possible errors from a serialization operation.
22#[derive(Debug, PartialEq)]
23pub enum EncoderError {
24    TooMuchNesting,
25    DuplicateMapKey,
26}
27
28/// Convert a [`Value`] to serialized CBOR data, consuming it along the way and appending to the provided vector.
29/// Maximum level of nesting supported is 127; more deeply nested structures will fail with
30/// [`EncoderError::TooMuchNesting`].
31pub fn write(value: Value, encoded_cbor: &mut Vec<u8>) -> Result<(), EncoderError> {
32    write_nested(value, encoded_cbor, Some(i8::MAX))
33}
34
35/// Convert a [`Value`] to serialized CBOR data, consuming it along the way and appending to the provided vector.  If
36/// `max_nest` is `Some(max)`, then nested structures are only supported up to the given limit (returning
37/// [`DecoderError::TooMuchNesting`] if the limit is hit).
38pub fn write_nested(
39    value: Value,
40    encoded_cbor: &mut Vec<u8>,
41    max_nest: Option<i8>,
42) -> Result<(), EncoderError> {
43    let mut writer = Writer::new(encoded_cbor);
44    writer.encode_cbor(value, max_nest)
45}
46
47struct Writer<'a> {
48    encoded_cbor: &'a mut Vec<u8>,
49}
50
51impl<'a> Writer<'a> {
52    pub fn new(encoded_cbor: &mut Vec<u8>) -> Writer {
53        Writer { encoded_cbor }
54    }
55
56    fn encode_cbor(
57        &mut self,
58        value: Value,
59        remaining_depth: Option<i8>,
60    ) -> Result<(), EncoderError> {
61        if remaining_depth.map_or(false, |d| d < 0) {
62            return Err(EncoderError::TooMuchNesting);
63        }
64        let type_label = value.type_label();
65        match value {
66            Value::Unsigned(unsigned) => self.start_item(type_label, unsigned),
67            Value::Negative(negative) => self.start_item(type_label, -(negative + 1) as u64),
68            Value::ByteString(byte_string) => {
69                self.start_item(type_label, byte_string.len() as u64);
70                self.encoded_cbor.extend(byte_string);
71            }
72            Value::TextString(text_string) => {
73                self.start_item(type_label, text_string.len() as u64);
74                self.encoded_cbor.extend(text_string.into_bytes());
75            }
76            Value::Array(array) => {
77                self.start_item(type_label, array.len() as u64);
78                for el in array {
79                    self.encode_cbor(el, remaining_depth.map(|d| d - 1))?;
80                }
81            }
82            Value::Map(mut map) => {
83                map.sort_by(|a, b| a.0.cmp(&b.0));
84                let map_len = map.len();
85                map.dedup_by(|a, b| a.0.eq(&b.0));
86                if map_len != map.len() {
87                    return Err(EncoderError::DuplicateMapKey);
88                }
89                self.start_item(type_label, map_len as u64);
90                for (k, v) in map {
91                    self.encode_cbor(k, remaining_depth.map(|d| d - 1))?;
92                    self.encode_cbor(v, remaining_depth.map(|d| d - 1))?;
93                }
94            }
95            Value::Tag(tag, inner_value) => {
96                self.start_item(type_label, tag);
97                self.encode_cbor(*inner_value, remaining_depth.map(|d| d - 1))?;
98            }
99            Value::Simple(simple_value) => self.start_item(type_label, simple_value as u64),
100        }
101        Ok(())
102    }
103
104    fn start_item(&mut self, type_label: u8, size: u64) {
105        let (mut first_byte, shift) = match size {
106            0..=23 => (size as u8, 0),
107            24..=0xFF => (Constants::ADDITIONAL_INFORMATION_1_BYTE, 1),
108            0x100..=0xFFFF => (Constants::ADDITIONAL_INFORMATION_2_BYTES, 2),
109            0x10000..=0xFFFF_FFFF => (Constants::ADDITIONAL_INFORMATION_4_BYTES, 4),
110            _ => (Constants::ADDITIONAL_INFORMATION_8_BYTES, 8),
111        };
112        first_byte |= type_label << Constants::MAJOR_TYPE_BIT_SHIFT;
113        self.encoded_cbor.push(first_byte);
114
115        for i in (0..shift).rev() {
116            self.encoded_cbor.push((size >> (i * 8)) as u8);
117        }
118    }
119}
120
121#[cfg(test)]
122mod test {
123    use alloc::vec;
124
125    use super::*;
126    use crate::{
127        cbor_array, cbor_array_vec, cbor_bytes, cbor_false, cbor_int, cbor_map, cbor_null,
128        cbor_tagged, cbor_text, cbor_true, cbor_undefined,
129    };
130
131    fn write_return(value: Value) -> Option<Vec<u8>> {
132        let mut encoded_cbor = Vec::new();
133        if write(value, &mut encoded_cbor).is_ok() {
134            Some(encoded_cbor)
135        } else {
136            None
137        }
138    }
139
140    #[test]
141    fn test_write_unsigned() {
142        let cases = vec![
143            (0, vec![0x00]),
144            (1, vec![0x01]),
145            (10, vec![0x0A]),
146            (23, vec![0x17]),
147            (24, vec![0x18, 0x18]),
148            (25, vec![0x18, 0x19]),
149            (100, vec![0x18, 0x64]),
150            (1000, vec![0x19, 0x03, 0xE8]),
151            (1000000, vec![0x1A, 0x00, 0x0F, 0x42, 0x40]),
152            (0xFFFFFFFF, vec![0x1A, 0xFF, 0xFF, 0xFF, 0xFF]),
153            (
154                0x100000000,
155                vec![0x1B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00],
156            ),
157            (
158                core::i64::MAX,
159                vec![0x1B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
160            ),
161        ];
162        for (unsigned, correct_cbor) in cases {
163            assert_eq!(write_return(cbor_int!(unsigned)), Some(correct_cbor));
164        }
165    }
166
167    #[test]
168    fn test_write_negative() {
169        let cases = vec![
170            (-1, vec![0x20]),
171            (-10, vec![0x29]),
172            (-23, vec![0x36]),
173            (-24, vec![0x37]),
174            (-25, vec![0x38, 0x18]),
175            (-100, vec![0x38, 0x63]),
176            (-1000, vec![0x39, 0x03, 0xE7]),
177            (-4294967296, vec![0x3A, 0xFF, 0xFF, 0xFF, 0xFF]),
178            (
179                -4294967297,
180                vec![0x3B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00],
181            ),
182            (
183                core::i64::MIN,
184                vec![0x3B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
185            ),
186        ];
187        for (negative, correct_cbor) in cases {
188            assert_eq!(write_return(cbor_int!(negative)), Some(correct_cbor));
189        }
190    }
191
192    #[test]
193    fn test_write_byte_string() {
194        let cases = vec![
195            (vec![], vec![0x40]),
196            (
197                vec![0x01, 0x02, 0x03, 0x04],
198                vec![0x44, 0x01, 0x02, 0x03, 0x04],
199            ),
200        ];
201        for (byte_string, correct_cbor) in cases {
202            assert_eq!(write_return(cbor_bytes!(byte_string)), Some(correct_cbor));
203        }
204    }
205
206    #[test]
207    fn test_write_text_string() {
208        let unicode_3byte = vec![0xE6, 0xB0, 0xB4];
209        let cases = vec![
210            ("", vec![0x60]),
211            ("a", vec![0x61, 0x61]),
212            ("IETF", vec![0x64, 0x49, 0x45, 0x54, 0x46]),
213            ("\"\\", vec![0x62, 0x22, 0x5C]),
214            ("ü", vec![0x62, 0xC3, 0xBC]),
215            (
216                core::str::from_utf8(&unicode_3byte).unwrap(),
217                vec![0x63, 0xE6, 0xB0, 0xB4],
218            ),
219            ("𐅑", vec![0x64, 0xF0, 0x90, 0x85, 0x91]),
220        ];
221        for (text_string, correct_cbor) in cases {
222            assert_eq!(write_return(cbor_text!(text_string)), Some(correct_cbor));
223        }
224    }
225
226    #[test]
227    fn test_write_array() {
228        let value_vec: Vec<_> = (1..26).collect();
229        let expected_cbor = vec![
230            0x98, 0x19, // array of 25 elements
231            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
232            0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x18, 0x18, 0x19,
233        ];
234        assert_eq!(
235            write_return(cbor_array_vec!(value_vec)),
236            Some(expected_cbor)
237        );
238    }
239
240    #[test]
241    fn test_write_map() {
242        let value_map = cbor_map! {
243            0 => "a",
244            23 => "b",
245            24 => "c",
246            core::u8::MAX as i64 => "d",
247            256 => "e",
248            core::u16::MAX as i64 => "f",
249            65536 => "g",
250            core::u32::MAX as i64 => "h",
251            4294967296_i64 => "i",
252            core::i64::MAX => "j",
253            -1 => "k",
254            -24 => "l",
255            -25 => "m",
256            -256 => "n",
257            -257 => "o",
258            -65537 => "p",
259            -4294967296_i64 => "q",
260            -4294967297_i64 => "r",
261            core::i64::MIN => "s",
262            b"a" => 2,
263            b"bar" => 3,
264            b"foo" => 4,
265            "" => ".",
266            "e" => "E",
267            "aa" => "AA",
268        };
269        let expected_cbor = vec![
270            0xb8, 0x19, // map of 25 pairs:
271            0x00, // key 0
272            0x61, 0x61, // value "a"
273            0x17, // key 23
274            0x61, 0x62, // value "b"
275            0x18, 0x18, // key 24
276            0x61, 0x63, // value "c"
277            0x18, 0xFF, // key 255
278            0x61, 0x64, // value "d"
279            0x19, 0x01, 0x00, // key 256
280            0x61, 0x65, // value "e"
281            0x19, 0xFF, 0xFF, // key 65535
282            0x61, 0x66, // value "f"
283            0x1A, 0x00, 0x01, 0x00, 0x00, // key 65536
284            0x61, 0x67, // value "g"
285            0x1A, 0xFF, 0xFF, 0xFF, 0xFF, // key 4294967295
286            0x61, 0x68, // value "h"
287            // key 4294967296
288            0x1B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x61, 0x69, //  value "i"
289            // key INT64_MAX
290            0x1b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x61, 0x6a, //  value "j"
291            0x20, // key -1
292            0x61, 0x6b, // value "k"
293            0x37, // key -24
294            0x61, 0x6c, // value "l"
295            0x38, 0x18, // key -25
296            0x61, 0x6d, // value "m"
297            0x38, 0xFF, // key -256
298            0x61, 0x6e, // value "n"
299            0x39, 0x01, 0x00, // key -257
300            0x61, 0x6f, // value "o"
301            0x3A, 0x00, 0x01, 0x00, 0x00, // key -65537
302            0x61, 0x70, // value "p"
303            0x3A, 0xFF, 0xFF, 0xFF, 0xFF, // key -4294967296
304            0x61, 0x71, // value "q"
305            // key -4294967297
306            0x3B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x61, 0x72, //  value "r"
307            // key INT64_MIN
308            0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x61, 0x73, //  value "s"
309            0x41, b'a', // byte string "a"
310            0x02, 0x43, b'b', b'a', b'r', // byte string "bar"
311            0x03, 0x43, b'f', b'o', b'o', // byte string "foo"
312            0x04, 0x60, // key ""
313            0x61, 0x2e, // value "."
314            0x61, 0x65, // key "e"
315            0x61, 0x45, // value "E"
316            0x62, 0x61, 0x61, // key "aa"
317            0x62, 0x41, 0x41, // value "AA"
318        ];
319        assert_eq!(write_return(value_map), Some(expected_cbor));
320    }
321
322    #[test]
323    fn test_write_map_sorted() {
324        let sorted_map = cbor_map! {
325            0 => "a",
326            1 => "b",
327            -1 => "c",
328            -2 => "d",
329            b"a" => "e",
330            b"b" => "f",
331            "" => "g",
332            "c" => "h",
333        };
334        let unsorted_map = cbor_map! {
335            1 => "b",
336            -2 => "d",
337            b"b" => "f",
338            "c" => "h",
339            "" => "g",
340            b"a" => "e",
341            -1 => "c",
342            0 => "a",
343        };
344        assert_eq!(write_return(sorted_map), write_return(unsorted_map));
345    }
346
347    #[test]
348    fn test_write_map_duplicates() {
349        let duplicate0 = cbor_map! {
350            0 => "a",
351            -1 => "c",
352            b"a" => "e",
353            "c" => "g",
354            0 => "b",
355        };
356        assert_eq!(write_return(duplicate0), None);
357        let duplicate1 = cbor_map! {
358            0 => "a",
359            -1 => "c",
360            b"a" => "e",
361            "c" => "g",
362            -1 => "d",
363        };
364        assert_eq!(write_return(duplicate1), None);
365        let duplicate2 = cbor_map! {
366            0 => "a",
367            -1 => "c",
368            b"a" => "e",
369            "c" => "g",
370            b"a" => "f",
371        };
372        assert_eq!(write_return(duplicate2), None);
373        let duplicate3 = cbor_map! {
374            0 => "a",
375            -1 => "c",
376            b"a" => "e",
377            "c" => "g",
378            "c" => "h",
379        };
380        assert_eq!(write_return(duplicate3), None);
381    }
382
383    #[test]
384    fn test_write_map_with_array() {
385        let value_map = cbor_map! {
386            "a" => 1,
387            "b" => cbor_array![2, 3],
388        };
389        let expected_cbor = vec![
390            0xa2, // map of 2 pairs
391            0x61, 0x61, // "a"
392            0x01, 0x61, 0x62, // "b"
393            0x82, // array with 2 elements
394            0x02, 0x03,
395        ];
396        assert_eq!(write_return(value_map), Some(expected_cbor));
397    }
398
399    #[test]
400    fn test_write_nested_map() {
401        let value_map = cbor_map! {
402            "a" => 1,
403            "b" => cbor_map! {
404                "c" => 2,
405                "d" => 3,
406            },
407        };
408        let expected_cbor = vec![
409            0xa2, // map of 2 pairs
410            0x61, 0x61, // "a"
411            0x01, 0x61, 0x62, // "b"
412            0xa2, // map of 2 pairs
413            0x61, 0x63, // "c"
414            0x02, 0x61, 0x64, // "d"
415            0x03,
416        ];
417        assert_eq!(write_return(value_map), Some(expected_cbor));
418    }
419
420    #[test]
421    fn test_write_tagged() {
422        let cases = vec![
423            (cbor_tagged!(6, cbor_int!(0x42)), vec![0xc6, 0x18, 0x42]),
424            (cbor_tagged!(1, cbor_true!()), vec![0xc1, 0xf5]),
425            (
426                cbor_tagged!(
427                    1000,
428                    cbor_map! {
429                        "a" => 1,
430                        "b" => cbor_array![2, 3],
431                    }
432                ),
433                vec![
434                    0xd9, 0x03, 0xe8, 0xa2, // map of 2 pairs
435                    0x61, 0x61, // "a"
436                    0x01, 0x61, 0x62, // "b"
437                    0x82, // array with 2 elements
438                    0x02, 0x03,
439                ],
440            ),
441        ];
442        for (value, correct_cbor) in cases {
443            assert_eq!(write_return(value), Some(correct_cbor));
444        }
445    }
446
447    #[test]
448    fn test_write_simple() {
449        let cases = vec![
450            (cbor_false!(), vec![0xF4]),
451            (cbor_true!(), vec![0xF5]),
452            (cbor_null!(), vec![0xF6]),
453            (cbor_undefined!(), vec![0xF7]),
454        ];
455        for (value, correct_cbor) in cases {
456            assert_eq!(write_return(value), Some(correct_cbor));
457        }
458    }
459
460    #[test]
461    fn test_write_single_levels() {
462        let simple_array: Value = cbor_array![2];
463        let simple_map: Value = cbor_map! {"b" => 3};
464        let positive_cases = vec![
465            (cbor_int!(1), 0),
466            (cbor_bytes!(vec![0x01, 0x02, 0x03, 0x04]), 0),
467            (cbor_text!("a"), 0),
468            (cbor_array![], 0),
469            (cbor_map! {}, 0),
470            (simple_array.clone(), 1),
471            (simple_map.clone(), 1),
472        ];
473        let negative_cases = vec![(simple_array.clone(), 0), (simple_map.clone(), 0)];
474        for (value, level) in positive_cases {
475            let mut buf = Vec::new();
476            let mut writer = Writer::new(&mut buf);
477            assert!(writer.encode_cbor(value, Some(level)).is_ok());
478        }
479        for (value, level) in negative_cases {
480            let mut buf = Vec::new();
481            let mut writer = Writer::new(&mut buf);
482            assert!(!writer.encode_cbor(value, Some(level)).is_ok());
483        }
484    }
485
486    #[test]
487    fn test_write_nested_map_levels() {
488        let cbor_map: Value = cbor_map! {
489            "a" => 1,
490            "b" => cbor_map! {
491                "c" => 2,
492                "d" => 3,
493            },
494        };
495
496        let mut buf = Vec::new();
497        let mut writer = Writer::new(&mut buf);
498        assert!(writer.encode_cbor(cbor_map.clone(), Some(2)).is_ok());
499        assert!(writer.encode_cbor(cbor_map.clone(), None).is_ok());
500        writer = Writer::new(&mut buf);
501        assert!(writer.encode_cbor(cbor_map, Some(1)).is_err());
502    }
503
504    #[test]
505    fn test_write_unbalanced_nested_containers() {
506        let cbor_array: Value = cbor_array![
507            1,
508            2,
509            3,
510            cbor_map! {
511                "a" => 1,
512                "b" => cbor_map! {
513                    "c" => 2,
514                    "d" => 3,
515                },
516            },
517        ];
518
519        let mut buf = Vec::new();
520        let mut writer = Writer::new(&mut buf);
521        assert!(writer.encode_cbor(cbor_array.clone(), Some(3)).is_ok());
522        writer = Writer::new(&mut buf);
523        assert!(writer.encode_cbor(cbor_array, Some(2)).is_err());
524    }
525
526    #[test]
527    fn test_write_overly_nested() {
528        let cbor_map: Value = cbor_map! {
529            "a" => 1,
530            "b" => cbor_map! {
531                "c" => 2,
532                "d" => 3,
533                "h" => cbor_map! {
534                    "e" => 4,
535                    "f" => 5,
536                    "g" => cbor_array![
537                        6,
538                        7,
539                        cbor_array![
540                            8
541                        ]
542                    ],
543                },
544            },
545        };
546
547        let mut buf = Vec::new();
548        let mut writer = Writer::new(&mut buf);
549        assert!(writer.encode_cbor(cbor_map.clone(), Some(5)).is_ok());
550        assert!(writer.encode_cbor(cbor_map.clone(), None).is_ok());
551        writer = Writer::new(&mut buf);
552        assert!(writer.encode_cbor(cbor_map, Some(4)).is_err());
553    }
554}