Skip to content

Commit

Permalink
Rfc7049 length-first key ordering implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
hoxxep committed Nov 26, 2024
1 parent 83dd4aa commit cd0350e
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 6 deletions.
22 changes: 18 additions & 4 deletions ciborium/src/ser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,11 +400,25 @@ macro_rules! end_map {
self.serializer.encoder.write_all(&key)?;
self.serializer.encoder.write_all(&value)?;
}
}
} else if matches!(self.serializer.canonicalization, CanonicalizationScheme::Rfc7049) {
// keys get sorted in length-first byte order
let keys = self.cache_keys;
let values = self.cache_values;

#[cfg(feature = "std")]
if matches!(self.serializer.canonicalization, CanonicalizationScheme::Rfc7049) {
unimplemented!("rfc7049 canonicalization not yet implemented");
debug_assert_eq!(
keys.len(), values.len(),
"ciborium error: canonicalization failed, different number of keys and values?");

let pairs: std::collections::BTreeMap<_, _> =
keys.iter()
.map(|key| (key.len(), key))
.zip(values.iter())
.collect();

for ((_, key), value) in pairs.iter() {
self.serializer.encoder.write_all(&key)?;
self.serializer.encoder.write_all(&value)?;
}
}

if self.indefinite {
Expand Down
25 changes: 23 additions & 2 deletions ciborium/tests/canonical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ fn rfc8949_example() {
}

#[test]
fn map() {
fn map_old() {
let mut map = BTreeMap::new();
map.insert(cval!(false), val!(2));
map.insert(cval!([-1]), val!(5));
Expand All @@ -64,14 +64,35 @@ fn map() {
);
}

/// Use length-first ordering for keys.
#[test]
fn map_rfc7049() {
let mut map = BTreeMap::new();
map.insert(cval!(false), val!(2));
map.insert(cval!([-1]), val!(5));
map.insert(cval!(-1), val!(1));
map.insert(cval!(10), val!(0));
map.insert(cval!(100), val!(3));
map.insert(cval!([100]), val!(7));
map.insert(cval!("z"), val!(4));
map.insert(cval!("aa"), val!(6));

let bytes1 = ciborium::ser::to_vec_canonical(&map, CanonicalizationScheme::Rfc7049).unwrap();

assert_eq!(
hex::encode(&bytes1),
"a80a002001f402186403617a048120056261610681186407"
);
}

/// Match [RFC 8949] deterministic ordering example.
///
/// The RFC specifies lexicographic byte ordering of serialized keys.
///
/// [RFC 8949]: https://www.rfc-editor.org/rfc/rfc8949.html#name-core-deterministic-encoding
#[test]
#[cfg(feature = "std")]
fn map_canonical() {
fn map_rfc8949() {
let mut map = BTreeMap::new();
map.insert(cval!(false), val!(2));
map.insert(cval!([-1]), val!(5));
Expand Down

0 comments on commit cd0350e

Please sign in to comment.