Add wrapper to prevent iteration of unordered maps
diff --git a/syntax/instantiate.rs b/syntax/instantiate.rs
index 2891485..e9c6f29 100644
--- a/syntax/instantiate.rs
+++ b/syntax/instantiate.rs
@@ -1,7 +1,7 @@
use crate::syntax::Type;
use proc_macro2::Ident;
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub enum ImplKey<'a> {
RustBox(&'a Ident),
RustVec(&'a Ident),
diff --git a/syntax/map.rs b/syntax/map.rs
new file mode 100644
index 0000000..a3b33ed
--- /dev/null
+++ b/syntax/map.rs
@@ -0,0 +1,89 @@
+use std::borrow::Borrow;
+use std::hash::Hash;
+use std::ops::Index;
+
+pub use self::unordered::UnorderedMap;
+pub use std::collections::hash_map::Entry;
+
+mod unordered {
+ use crate::syntax::set::UnorderedSet;
+ use std::borrow::Borrow;
+ use std::collections::hash_map::{Entry, HashMap};
+ use std::hash::Hash;
+
+ // Wrapper prohibits accidentally introducing iteration over the map, which
+ // could lead to nondeterministic generated code.
+ pub struct UnorderedMap<K, V>(HashMap<K, V>);
+
+ impl<K, V> UnorderedMap<K, V> {
+ pub fn new() -> Self {
+ UnorderedMap(HashMap::new())
+ }
+ }
+
+ impl<K, V> UnorderedMap<K, V>
+ where
+ K: Hash + Eq,
+ {
+ pub fn insert(&mut self, key: K, value: V) -> Option<V> {
+ self.0.insert(key, value)
+ }
+
+ pub fn contains_key<Q>(&self, key: &Q) -> bool
+ where
+ K: Borrow<Q>,
+ Q: ?Sized + Hash + Eq,
+ {
+ self.0.contains_key(key)
+ }
+
+ pub fn get<Q>(&self, key: &Q) -> Option<&V>
+ where
+ K: Borrow<Q>,
+ Q: ?Sized + Hash + Eq,
+ {
+ self.0.get(key)
+ }
+
+ pub fn entry(&mut self, key: K) -> Entry<K, V> {
+ self.0.entry(key)
+ }
+
+ pub fn remove<Q>(&mut self, key: &Q) -> Option<V>
+ where
+ K: Borrow<Q>,
+ Q: ?Sized + Hash + Eq,
+ {
+ self.0.remove(key)
+ }
+
+ pub fn keys(&self) -> UnorderedSet<K>
+ where
+ K: Copy,
+ {
+ let mut set = UnorderedSet::new();
+ for key in self.0.keys() {
+ set.insert(*key);
+ }
+ set
+ }
+ }
+}
+
+impl<K, V> Default for UnorderedMap<K, V> {
+ fn default() -> Self {
+ UnorderedMap::new()
+ }
+}
+
+impl<Q, K, V> Index<&Q> for UnorderedMap<K, V>
+where
+ K: Borrow<Q> + Hash + Eq,
+ Q: ?Sized + Hash + Eq,
+{
+ type Output = V;
+
+ fn index(&self, key: &Q) -> &V {
+ self.get(key).unwrap()
+ }
+}
diff --git a/syntax/mod.rs b/syntax/mod.rs
index 1dcb55c..96169e8 100644
--- a/syntax/mod.rs
+++ b/syntax/mod.rs
@@ -13,6 +13,7 @@
mod improper;
pub mod instantiate;
pub mod mangle;
+pub mod map;
mod names;
pub mod namespace;
mod parse;
diff --git a/syntax/set.rs b/syntax/set.rs
index 0df5f87..ca0c43e 100644
--- a/syntax/set.rs
+++ b/syntax/set.rs
@@ -105,6 +105,10 @@
{
self.0.get(value)
}
+
+ pub fn retain(&mut self, f: impl FnMut(&T) -> bool) {
+ self.0.retain(f);
+ }
}
}
diff --git a/syntax/toposort.rs b/syntax/toposort.rs
index 876f9ad..8fe55b8 100644
--- a/syntax/toposort.rs
+++ b/syntax/toposort.rs
@@ -1,6 +1,6 @@
+use crate::syntax::map::{Entry, UnorderedMap as Map};
use crate::syntax::report::Errors;
use crate::syntax::{Api, Struct, Type, Types};
-use std::collections::btree_map::{BTreeMap as Map, Entry};
enum Mark {
Visiting,
diff --git a/syntax/trivial.rs b/syntax/trivial.rs
index 070a366..b7ba4f9 100644
--- a/syntax/trivial.rs
+++ b/syntax/trivial.rs
@@ -1,7 +1,7 @@
+use crate::syntax::map::UnorderedMap;
use crate::syntax::set::{OrderedSet as Set, UnorderedSet};
use crate::syntax::{Api, Enum, ExternFn, Pair, RustName, Struct, Type};
use proc_macro2::Ident;
-use std::collections::BTreeMap as Map;
use std::fmt::{self, Display};
#[derive(Copy, Clone)]
@@ -17,11 +17,11 @@
pub fn required_trivial_reasons<'a>(
apis: &'a [Api],
all: &Set<&'a Type>,
- structs: &Map<&'a Ident, &'a Struct>,
- enums: &Map<&'a Ident, &'a Enum>,
+ structs: &UnorderedMap<&'a Ident, &'a Struct>,
+ enums: &UnorderedMap<&'a Ident, &'a Enum>,
cxx: &UnorderedSet<&'a Ident>,
-) -> Map<&'a Ident, Vec<TrivialReason<'a>>> {
- let mut required_trivial = Map::new();
+) -> UnorderedMap<&'a Ident, Vec<TrivialReason<'a>>> {
+ let mut required_trivial = UnorderedMap::new();
let mut insist_extern_types_are_trivial = |ident: &'a RustName, reason| {
if cxx.contains(&ident.rust)
diff --git a/syntax/types.rs b/syntax/types.rs
index 87a2992..7a45939 100644
--- a/syntax/types.rs
+++ b/syntax/types.rs
@@ -1,5 +1,6 @@
use crate::syntax::improper::ImproperCtype;
use crate::syntax::instantiate::ImplKey;
+use crate::syntax::map::UnorderedMap;
use crate::syntax::report::Errors;
use crate::syntax::set::{OrderedSet as Set, UnorderedSet};
use crate::syntax::trivial::{self, TrivialReason};
@@ -8,19 +9,18 @@
};
use proc_macro2::Ident;
use quote::ToTokens;
-use std::collections::BTreeMap as Map;
pub struct Types<'a> {
pub all: Set<&'a Type>,
- pub structs: Map<&'a Ident, &'a Struct>,
- pub enums: Map<&'a Ident, &'a Enum>,
+ pub structs: UnorderedMap<&'a Ident, &'a Struct>,
+ pub enums: UnorderedMap<&'a Ident, &'a Enum>,
pub cxx: UnorderedSet<&'a Ident>,
pub rust: UnorderedSet<&'a Ident>,
- pub aliases: Map<&'a Ident, &'a TypeAlias>,
- pub untrusted: Map<&'a Ident, &'a ExternType>,
- pub required_trivial: Map<&'a Ident, Vec<TrivialReason<'a>>>,
- pub explicit_impls: Map<ImplKey<'a>, &'a Impl>,
- pub resolutions: Map<&'a Ident, &'a Pair>,
+ pub aliases: UnorderedMap<&'a Ident, &'a TypeAlias>,
+ pub untrusted: UnorderedMap<&'a Ident, &'a ExternType>,
+ pub required_trivial: UnorderedMap<&'a Ident, Vec<TrivialReason<'a>>>,
+ pub explicit_impls: UnorderedMap<ImplKey<'a>, &'a Impl>,
+ pub resolutions: UnorderedMap<&'a Ident, &'a Pair>,
pub struct_improper_ctypes: UnorderedSet<&'a Ident>,
pub toposorted_structs: Vec<&'a Struct>,
}
@@ -28,14 +28,14 @@
impl<'a> Types<'a> {
pub fn collect(cx: &mut Errors, apis: &'a [Api]) -> Self {
let mut all = Set::new();
- let mut structs = Map::new();
- let mut enums = Map::new();
+ let mut structs = UnorderedMap::new();
+ let mut enums = UnorderedMap::new();
let mut cxx = UnorderedSet::new();
let mut rust = UnorderedSet::new();
- let mut aliases = Map::new();
- let mut untrusted = Map::new();
- let mut explicit_impls = Map::new();
- let mut resolutions = Map::new();
+ let mut aliases = UnorderedMap::new();
+ let mut untrusted = UnorderedMap::new();
+ let mut explicit_impls = UnorderedMap::new();
+ let mut resolutions = UnorderedMap::new();
let struct_improper_ctypes = UnorderedSet::new();
let toposorted_structs = Vec::new();
@@ -192,7 +192,7 @@
types.toposorted_structs = toposort::sort(cx, apis, &types);
- let mut unresolved_structs: Vec<&Ident> = types.structs.keys().copied().collect();
+ let mut unresolved_structs = types.structs.keys();
let mut new_information = true;
while new_information {
new_information = false;