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, 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, 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, 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, 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, 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, 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, map: &BTreeMap) { 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, 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) { 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 { let mut bytes: Vec = 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 } }