summaryrefslogtreecommitdiffstats
path: root/third_party/rust/moz_cbor/src/serializer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/moz_cbor/src/serializer.rs')
-rw-r--r--third_party/rust/moz_cbor/src/serializer.rs124
1 files changed, 124 insertions, 0 deletions
diff --git a/third_party/rust/moz_cbor/src/serializer.rs b/third_party/rust/moz_cbor/src/serializer.rs
new file mode 100644
index 0000000000..b796aaedc7
--- /dev/null
+++ b/third_party/rust/moz_cbor/src/serializer.rs
@@ -0,0 +1,124 @@
+use std::collections::BTreeMap;
+use CborType;
+
+/// Given a vector of bytes to append to, a tag to use, and an unsigned value to encode, uses the
+/// CBOR unsigned integer encoding to represent the given value.
+fn common_encode_unsigned(output: &mut Vec<u8>, tag: u8, value: u64) {
+ assert!(tag < 8);
+ let shifted_tag = tag << 5;
+ match value {
+ 0..=23 => {
+ output.push(shifted_tag | (value as u8));
+ }
+ 24..=255 => {
+ output.push(shifted_tag | 24);
+ output.push(value as u8);
+ }
+ 256..=65_535 => {
+ output.push(shifted_tag | 25);
+ output.push((value >> 8) as u8);
+ output.push((value & 255) as u8);
+ }
+ 65_536..=4_294_967_295 => {
+ output.push(shifted_tag | 26);
+ output.push((value >> 24) as u8);
+ output.push(((value >> 16) & 255) as u8);
+ output.push(((value >> 8) & 255) as u8);
+ output.push((value & 255) as u8);
+ }
+ _ => {
+ output.push(shifted_tag | 27);
+ output.push((value >> 56) as u8);
+ output.push(((value >> 48) & 255) as u8);
+ output.push(((value >> 40) & 255) as u8);
+ output.push(((value >> 32) & 255) as u8);
+ output.push(((value >> 24) & 255) as u8);
+ output.push(((value >> 16) & 255) as u8);
+ output.push(((value >> 8) & 255) as u8);
+ output.push((value & 255) as u8);
+ }
+ };
+}
+
+/// The major type is 0. For values 0 through 23, the 5 bits of additional information is just the
+/// value of the unsigned number. For values representable in one byte, the additional information
+/// has the value 24. If two bytes are necessary, the value is 25. If four bytes are necessary, the
+/// value is 26. If 8 bytes are necessary, the value is 27. The following bytes are the value of the
+/// unsigned number in as many bytes were indicated in network byte order (big endian).
+fn encode_unsigned(output: &mut Vec<u8>, unsigned: u64) {
+ common_encode_unsigned(output, 0, unsigned);
+}
+
+/// The major type is 1. The encoding is the same as for positive (i.e. unsigned) integers, except
+/// the value encoded is -1 minus the value of the negative number.
+fn encode_negative(output: &mut Vec<u8>, negative: i64) {
+ assert!(negative < 0);
+ let value_to_encode: u64 = (-1 - negative) as u64;
+ common_encode_unsigned(output, 1, value_to_encode);
+}
+
+/// The major type is 2. The length of the data is encoded as with positive integers, followed by
+/// the actual data.
+fn encode_bytes(output: &mut Vec<u8>, bstr: &[u8]) {
+ common_encode_unsigned(output, 2, bstr.len() as u64);
+ output.extend_from_slice(bstr);
+}
+
+/// The major type is 3. The length is as with bstr. The UTF-8-encoded bytes of the string follow.
+fn encode_string(output: &mut Vec<u8>, tstr: &str) {
+ let utf8_bytes = tstr.as_bytes();
+ common_encode_unsigned(output, 3, utf8_bytes.len() as u64);
+ output.extend_from_slice(utf8_bytes);
+}
+
+/// The major type is 4. The number of items is encoded as with positive integers. Then follows the
+/// encodings of the items themselves.
+fn encode_array(output: &mut Vec<u8>, array: &[CborType]) {
+ common_encode_unsigned(output, 4, array.len() as u64);
+ for element in array {
+ output.append(&mut element.serialize());
+ }
+}
+
+/// The major type is 5. The number of pairs is encoded as with positive integers. Then follows the
+/// encodings of each key, value pair. In Canonical CBOR, the keys must be sorted lowest value to
+/// highest.
+fn encode_map(output: &mut Vec<u8>, map: &BTreeMap<CborType, CborType>) {
+ common_encode_unsigned(output, 5, map.len() as u64);
+ for (key, value) in map {
+ output.append(&mut key.serialize());
+ output.append(&mut value.serialize());
+ }
+}
+
+fn encode_tag(output: &mut Vec<u8>, tag: &u64, val: &CborType) {
+ common_encode_unsigned(output, 6, *tag);
+ output.append(&mut val.serialize());
+}
+
+/// The major type is 7. The only supported value for this type is 22, which is Null.
+/// This makes the encoded value 246, or 0xf6.
+fn encode_null(output: &mut Vec<u8>) {
+ output.push(0xf6);
+}
+
+impl CborType {
+ /// Serialize a Cbor object. NB: if the object to be serialized consists of too many nested
+ /// Cbor objects (for example, Array(Array(Array(...(Array(0))))), it is possible that calling
+ /// serialize will exhaust the stack. It is considered the caller's responsibility to prevent
+ /// this.
+ pub fn serialize(&self) -> Vec<u8> {
+ let mut bytes: Vec<u8> = Vec::new();
+ match *self {
+ CborType::Integer(ref unsigned) => encode_unsigned(&mut bytes, *unsigned),
+ CborType::SignedInteger(ref negative) => encode_negative(&mut bytes, *negative),
+ CborType::Bytes(ref bstr) => encode_bytes(&mut bytes, bstr),
+ CborType::String(ref tstr) => encode_string(&mut bytes, tstr),
+ CborType::Array(ref arr) => encode_array(&mut bytes, arr),
+ CborType::Map(ref map) => encode_map(&mut bytes, map),
+ CborType::Tag(ref t, ref val) => encode_tag(&mut bytes, t, val),
+ CborType::Null => encode_null(&mut bytes),
+ };
+ bytes
+ }
+}