Skip to content

Commit cd0350e

Browse files
committed
Rfc7049 length-first key ordering implementation
1 parent 83dd4aa commit cd0350e

File tree

2 files changed

+41
-6
lines changed

2 files changed

+41
-6
lines changed

ciborium/src/ser/mod.rs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -400,11 +400,25 @@ macro_rules! end_map {
400400
self.serializer.encoder.write_all(&key)?;
401401
self.serializer.encoder.write_all(&value)?;
402402
}
403-
}
403+
} else if matches!(self.serializer.canonicalization, CanonicalizationScheme::Rfc7049) {
404+
// keys get sorted in length-first byte order
405+
let keys = self.cache_keys;
406+
let values = self.cache_values;
404407

405-
#[cfg(feature = "std")]
406-
if matches!(self.serializer.canonicalization, CanonicalizationScheme::Rfc7049) {
407-
unimplemented!("rfc7049 canonicalization not yet implemented");
408+
debug_assert_eq!(
409+
keys.len(), values.len(),
410+
"ciborium error: canonicalization failed, different number of keys and values?");
411+
412+
let pairs: std::collections::BTreeMap<_, _> =
413+
keys.iter()
414+
.map(|key| (key.len(), key))
415+
.zip(values.iter())
416+
.collect();
417+
418+
for ((_, key), value) in pairs.iter() {
419+
self.serializer.encoder.write_all(&key)?;
420+
self.serializer.encoder.write_all(&value)?;
421+
}
408422
}
409423

410424
if self.indefinite {

ciborium/tests/canonical.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ fn rfc8949_example() {
4444
}
4545

4646
#[test]
47-
fn map() {
47+
fn map_old() {
4848
let mut map = BTreeMap::new();
4949
map.insert(cval!(false), val!(2));
5050
map.insert(cval!([-1]), val!(5));
@@ -64,14 +64,35 @@ fn map() {
6464
);
6565
}
6666

67+
/// Use length-first ordering for keys.
68+
#[test]
69+
fn map_rfc7049() {
70+
let mut map = BTreeMap::new();
71+
map.insert(cval!(false), val!(2));
72+
map.insert(cval!([-1]), val!(5));
73+
map.insert(cval!(-1), val!(1));
74+
map.insert(cval!(10), val!(0));
75+
map.insert(cval!(100), val!(3));
76+
map.insert(cval!([100]), val!(7));
77+
map.insert(cval!("z"), val!(4));
78+
map.insert(cval!("aa"), val!(6));
79+
80+
let bytes1 = ciborium::ser::to_vec_canonical(&map, CanonicalizationScheme::Rfc7049).unwrap();
81+
82+
assert_eq!(
83+
hex::encode(&bytes1),
84+
"a80a002001f402186403617a048120056261610681186407"
85+
);
86+
}
87+
6788
/// Match [RFC 8949] deterministic ordering example.
6889
///
6990
/// The RFC specifies lexicographic byte ordering of serialized keys.
7091
///
7192
/// [RFC 8949]: https://www.rfc-editor.org/rfc/rfc8949.html#name-core-deterministic-encoding
7293
#[test]
7394
#[cfg(feature = "std")]
74-
fn map_canonical() {
95+
fn map_rfc8949() {
7596
let mut map = BTreeMap::new();
7697
map.insert(cval!(false), val!(2));
7798
map.insert(cval!([-1]), val!(5));

0 commit comments

Comments
 (0)