check for hash collision
@@ -5,7 +5,7 @@ use serde::ser::{self, Impossible, Serialize};
use std::io;
use std::vec::Vec;
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
use dfx_info::{Type, Field};
use leb128::write::{signed as sleb128_encode, unsigned as leb128_encode};
@@ -290,6 +290,15 @@ fn idl_hash(id: &str) -> u32 {
s
}
+fn sort_fields(fs: &Vec<Field>) -> Vec<(u32, &Type)> {
+ let mut fs: Vec<(u32, &Type)> =
+ fs.into_iter().map(|Field {id,ty}| (idl_hash(id), ty)).collect();
+ fs.sort_unstable_by_key(|(id,_)| *id);
+ let unique_ids: HashSet<_> = fs.iter().map(|(id,_)| id).collect();
+ assert_eq!(unique_ids.len(), fs.len());
+ fs
+}
+
// TypeSerialize is implemented outside of the serde framework, as serde only supports value, not type.
impl TypeSerialize
@@ -333,10 +342,7 @@ impl TypeSerialize
self.encode(&mut buf, ty)?;
},
Type::Record(fs) => {
- let mut fs: Vec<(u32, &Type)> = fs.into_iter().map(
- |Field {id, ty}| (idl_hash(id), ty)).collect();
- // TODO check for hash collision
- fs.sort_unstable_by_key(|(id,_)| *id);
+ let fs = sort_fields(fs);
for (_, ty) in fs.iter() {
self.build_type(ty).unwrap();
};
@@ -348,6 +354,19 @@ impl TypeSerialize
self.encode(&mut buf, ty)?;
};
},
+ Type::Variant(fs) => {
+ let fs = sort_fields(fs);
+ for (_, ty) in fs.iter() {
+ self.build_type(ty).unwrap();
+ };
+
+ sleb128_encode(&mut buf, -21)?;
+ leb128_encode(&mut buf, fs.len() as u64)?;
+ for (id, ty) in fs.iter() {
+ leb128_encode(&mut buf, *id as u64)?;
+ self.encode(&mut buf, ty)?;
+ };
+ },
_ => panic!("unreachable"),
};
self.type_table[idx] = buf;
