diff --git a/ciborium/src/ser/mod.rs b/ciborium/src/ser/mod.rs index 89766e1..27ef0ee 100644 --- a/ciborium/src/ser/mod.rs +++ b/ciborium/src/ser/mod.rs @@ -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 { diff --git a/ciborium/tests/canonical.rs b/ciborium/tests/canonical.rs index ed3786b..50dbdfb 100644 --- a/ciborium/tests/canonical.rs +++ b/ciborium/tests/canonical.rs @@ -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)); @@ -64,6 +64,27 @@ 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. @@ -71,7 +92,7 @@ fn map() { /// [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));