Revision control
Copy as Markdown
Other Tools
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
}
}