1 //! This module contains collection types that don't expose their internal
2 //! ordering. This is a useful property for deterministic computations, such
3 //! as required by the query system.
5 use rustc_hash::{FxHashMap, FxHashSet};
6 use smallvec::SmallVec;
9 collections::hash_map::Entry,
16 fingerprint::Fingerprint,
17 stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey},
20 /// `UnordItems` is the order-less version of `Iterator`. It only contains methods
21 /// that don't (easily) expose an ordering of the underlying items.
23 /// Most methods take an `Fn` where the `Iterator`-version takes an `FnMut`. This
24 /// is to reduce the risk of accidentally leaking the internal order via the closure
25 /// environment. Otherwise one could easily do something like
27 /// ```rust,ignore (pseudo code)
28 /// let mut ordered = vec![];
29 /// unordered_items.all(|x| ordered.push(x));
32 /// It's still possible to do the same thing with an `Fn` by using interior mutability,
33 /// but the chance of doing it accidentally is reduced.
34 pub struct UnordItems<T, I: Iterator<Item = T>>(I);
36 impl<T, I: Iterator<Item = T>> UnordItems<T, I> {
38 pub fn map<U, F: Fn(T) -> U>(self, f: F) -> UnordItems<U, impl Iterator<Item = U>> {
39 UnordItems(self.0.map(f))
43 pub fn all<F: Fn(T) -> bool>(mut self, f: F) -> bool {
48 pub fn any<F: Fn(T) -> bool>(mut self, f: F) -> bool {
53 pub fn filter<F: Fn(&T) -> bool>(self, f: F) -> UnordItems<T, impl Iterator<Item = T>> {
54 UnordItems(self.0.filter(f))
58 pub fn filter_map<U, F: Fn(T) -> Option<U>>(
61 ) -> UnordItems<U, impl Iterator<Item = U>> {
62 UnordItems(self.0.filter_map(f))
66 pub fn max(self) -> Option<T>
74 pub fn min(self) -> Option<T>
82 pub fn sum<S>(self) -> S
90 pub fn product<S>(self) -> S
98 pub fn count(self) -> usize {
103 pub fn flat_map<U, F, O>(self, f: F) -> UnordItems<O, impl Iterator<Item = O>>
105 U: IntoIterator<Item = O>,
108 UnordItems(self.0.flat_map(f))
112 impl<'a, T: Clone + 'a, I: Iterator<Item = &'a T>> UnordItems<&'a T, I> {
114 pub fn cloned(self) -> UnordItems<T, impl Iterator<Item = T>> {
115 UnordItems(self.0.cloned())
119 impl<'a, T: Copy + 'a, I: Iterator<Item = &'a T>> UnordItems<&'a T, I> {
121 pub fn copied(self) -> UnordItems<T, impl Iterator<Item = T>> {
122 UnordItems(self.0.copied())
126 impl<T: Ord, I: Iterator<Item = T>> UnordItems<T, I> {
127 pub fn into_sorted<HCX>(self, hcx: &HCX) -> Vec<T>
129 T: ToStableHashKey<HCX>,
131 let mut items: Vec<T> = self.0.collect();
132 items.sort_by_cached_key(|x| x.to_stable_hash_key(hcx));
136 pub fn into_sorted_small_vec<HCX, const LEN: usize>(self, hcx: &HCX) -> SmallVec<[T; LEN]>
138 T: ToStableHashKey<HCX>,
140 let mut items: SmallVec<[T; LEN]> = self.0.collect();
141 items.sort_by_cached_key(|x| x.to_stable_hash_key(hcx));
146 /// This is a set collection type that tries very hard to not expose
147 /// any internal iteration. This is a useful property when trying to
148 /// uphold the determinism invariants imposed by the query system.
150 /// This collection type is a good choice for set-like collections the
151 /// keys of which don't have a semantic ordering.
153 /// See [MCP 533](https://github.com/rust-lang/compiler-team/issues/533)
154 /// for more information.
155 #[derive(Debug, Eq, PartialEq, Clone, Encodable, Decodable)]
156 pub struct UnordSet<V: Eq + Hash> {
160 impl<V: Eq + Hash> Default for UnordSet<V> {
162 fn default() -> Self {
163 Self { inner: FxHashSet::default() }
167 impl<V: Eq + Hash> UnordSet<V> {
169 pub fn new() -> Self {
170 Self { inner: Default::default() }
174 pub fn len(&self) -> usize {
179 pub fn insert(&mut self, v: V) -> bool {
184 pub fn contains<Q: ?Sized>(&self, v: &Q) -> bool
189 self.inner.contains(v)
193 pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> bool
202 pub fn items<'a>(&'a self) -> UnordItems<&'a V, impl Iterator<Item = &'a V>> {
203 UnordItems(self.inner.iter())
207 pub fn into_items(self) -> UnordItems<V, impl Iterator<Item = V>> {
208 UnordItems(self.inner.into_iter())
212 pub fn to_sorted<HCX>(&self, hcx: &HCX, cache_sort_key: bool) -> Vec<&V>
214 V: ToStableHashKey<HCX>,
216 let mut items: Vec<&V> = self.inner.iter().collect();
218 items.sort_by_cached_key(|k| k.to_stable_hash_key(hcx));
220 items.sort_unstable_by_key(|k| k.to_stable_hash_key(hcx));
227 pub fn to_sorted_stable_ord(&self) -> Vec<V>
229 V: Ord + StableOrd + Copy,
231 let mut items: Vec<V> = self.inner.iter().copied().collect();
232 items.sort_unstable();
237 pub fn into_sorted<HCX>(self, hcx: &HCX, cache_sort_key: bool) -> Vec<V>
239 V: ToStableHashKey<HCX>,
241 let mut items: Vec<V> = self.inner.into_iter().collect();
243 items.sort_by_cached_key(|k| k.to_stable_hash_key(hcx));
245 items.sort_unstable_by_key(|k| k.to_stable_hash_key(hcx));
251 // We can safely extend this UnordSet from a set of unordered values because that
252 // won't expose the internal ordering anywhere.
254 pub fn extend<I: Iterator<Item = V>>(&mut self, items: UnordItems<V, I>) {
255 self.inner.extend(items.0)
259 pub fn clear(&mut self) {
264 impl<V: Hash + Eq> Extend<V> for UnordSet<V> {
266 fn extend<T: IntoIterator<Item = V>>(&mut self, iter: T) {
267 self.inner.extend(iter)
271 impl<V: Hash + Eq> FromIterator<V> for UnordSet<V> {
273 fn from_iter<T: IntoIterator<Item = V>>(iter: T) -> Self {
274 UnordSet { inner: FxHashSet::from_iter(iter) }
278 impl<HCX, V: Hash + Eq + HashStable<HCX>> HashStable<HCX> for UnordSet<V> {
280 fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
281 hash_iter_order_independent(self.inner.iter(), hcx, hasher);
285 /// This is a map collection type that tries very hard to not expose
286 /// any internal iteration. This is a useful property when trying to
287 /// uphold the determinism invariants imposed by the query system.
289 /// This collection type is a good choice for map-like collections the
290 /// keys of which don't have a semantic ordering.
292 /// See [MCP 533](https://github.com/rust-lang/compiler-team/issues/533)
293 /// for more information.
294 #[derive(Debug, Eq, PartialEq, Clone, Encodable, Decodable)]
295 pub struct UnordMap<K: Eq + Hash, V> {
296 inner: FxHashMap<K, V>,
299 impl<K: Eq + Hash, V> Default for UnordMap<K, V> {
301 fn default() -> Self {
302 Self { inner: FxHashMap::default() }
306 impl<K: Hash + Eq, V> Extend<(K, V)> for UnordMap<K, V> {
308 fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
309 self.inner.extend(iter)
313 impl<K: Hash + Eq, V> FromIterator<(K, V)> for UnordMap<K, V> {
315 fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
316 UnordMap { inner: FxHashMap::from_iter(iter) }
320 impl<K: Hash + Eq, V, I: Iterator<Item = (K, V)>> From<UnordItems<(K, V), I>> for UnordMap<K, V> {
322 fn from(items: UnordItems<(K, V), I>) -> Self {
323 UnordMap { inner: FxHashMap::from_iter(items.0) }
327 impl<K: Eq + Hash, V> UnordMap<K, V> {
329 pub fn len(&self) -> usize {
334 pub fn insert(&mut self, k: K, v: V) -> Option<V> {
335 self.inner.insert(k, v)
339 pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
344 self.inner.contains_key(k)
348 pub fn is_empty(&self) -> bool {
349 self.inner.is_empty()
353 pub fn entry(&mut self, key: K) -> Entry<'_, K, V> {
354 self.inner.entry(key)
358 pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
367 pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
372 self.inner.get_mut(k)
376 pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V>
385 pub fn items<'a>(&'a self) -> UnordItems<(&'a K, &'a V), impl Iterator<Item = (&'a K, &'a V)>> {
386 UnordItems(self.inner.iter())
390 pub fn into_items(self) -> UnordItems<(K, V), impl Iterator<Item = (K, V)>> {
391 UnordItems(self.inner.into_iter())
394 // We can safely extend this UnordMap from a set of unordered values because that
395 // won't expose the internal ordering anywhere.
397 pub fn extend<I: Iterator<Item = (K, V)>>(&mut self, items: UnordItems<(K, V), I>) {
398 self.inner.extend(items.0)
402 pub fn to_sorted<HCX>(&self, hcx: &HCX, cache_sort_key: bool) -> Vec<(&K, &V)>
404 K: ToStableHashKey<HCX>,
406 let mut items: Vec<(&K, &V)> = self.inner.iter().collect();
408 items.sort_by_cached_key(|(k, _)| k.to_stable_hash_key(hcx));
410 items.sort_unstable_by_key(|(k, _)| k.to_stable_hash_key(hcx));
417 pub fn to_sorted_stable_ord(&self) -> Vec<(K, &V)>
419 K: Ord + StableOrd + Copy,
421 let mut items: Vec<(K, &V)> = self.inner.iter().map(|(&k, v)| (k, v)).collect();
422 items.sort_unstable_by_key(|&(k, _)| k);
427 pub fn into_sorted<HCX>(self, hcx: &HCX, cache_sort_key: bool) -> Vec<(K, V)>
429 K: ToStableHashKey<HCX>,
431 let mut items: Vec<(K, V)> = self.inner.into_iter().collect();
433 items.sort_by_cached_key(|(k, _)| k.to_stable_hash_key(hcx));
435 items.sort_unstable_by_key(|(k, _)| k.to_stable_hash_key(hcx));
441 pub fn values_sorted<HCX>(&self, hcx: &HCX, cache_sort_key: bool) -> impl Iterator<Item = &V>
443 K: ToStableHashKey<HCX>,
445 let mut items: Vec<(&K, &V)> = self.inner.iter().collect();
447 items.sort_by_cached_key(|(k, _)| k.to_stable_hash_key(hcx));
449 items.sort_unstable_by_key(|(k, _)| k.to_stable_hash_key(hcx));
451 items.into_iter().map(|(_, v)| v)
455 impl<K, Q: ?Sized, V> Index<&Q> for UnordMap<K, V>
457 K: Eq + Hash + Borrow<Q>,
463 fn index(&self, key: &Q) -> &V {
468 impl<HCX, K: Hash + Eq + HashStable<HCX>, V: HashStable<HCX>> HashStable<HCX> for UnordMap<K, V> {
470 fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
471 hash_iter_order_independent(self.inner.iter(), hcx, hasher);
475 /// This is a collection type that tries very hard to not expose
476 /// any internal iteration. This is a useful property when trying to
477 /// uphold the determinism invariants imposed by the query system.
479 /// This collection type is a good choice for collections the
480 /// keys of which don't have a semantic ordering and don't implement
483 /// See [MCP 533](https://github.com/rust-lang/compiler-team/issues/533)
484 /// for more information.
485 #[derive(Default, Debug, Eq, PartialEq, Clone, Encodable, Decodable)]
486 pub struct UnordBag<V> {
490 impl<V> UnordBag<V> {
492 pub fn new() -> Self {
493 Self { inner: Default::default() }
497 pub fn len(&self) -> usize {
502 pub fn push(&mut self, v: V) {
507 pub fn items(&self) -> UnordItems<&V, impl Iterator<Item = &V>> {
508 UnordItems(self.inner.iter())
512 pub fn into_items(self) -> UnordItems<V, impl Iterator<Item = V>> {
513 UnordItems(self.inner.into_iter())
516 // We can safely extend this UnordSet from a set of unordered values because that
517 // won't expose the internal ordering anywhere.
519 pub fn extend<I: Iterator<Item = V>>(&mut self, items: UnordItems<V, I>) {
520 self.inner.extend(items.0)
524 impl<T> Extend<T> for UnordBag<T> {
525 fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
526 self.inner.extend(iter)
530 impl<T, I: Iterator<Item = T>> From<UnordItems<T, I>> for UnordBag<T> {
531 fn from(value: UnordItems<T, I>) -> Self {
532 UnordBag { inner: Vec::from_iter(value.0) }
536 impl<HCX, V: Hash + Eq + HashStable<HCX>> HashStable<HCX> for UnordBag<V> {
538 fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
539 hash_iter_order_independent(self.inner.iter(), hcx, hasher);
543 fn hash_iter_order_independent<
546 I: Iterator<Item = T> + ExactSizeIterator,
550 hasher: &mut StableHasher,
553 len.hash_stable(hcx, hasher);
560 // No need to instantiate a hasher
561 it.next().unwrap().hash_stable(hcx, hasher);
564 let mut accumulator = Fingerprint::ZERO;
566 let mut item_hasher = StableHasher::new();
567 item.hash_stable(hcx, &mut item_hasher);
568 let item_fingerprint: Fingerprint = item_hasher.finish();
569 accumulator = accumulator.combine_commutative(item_fingerprint);
571 accumulator.hash_stable(hcx, hasher);
576 // Do not implement IntoIterator for the collections in this module.
577 // They only exist to hide iteration order in the first place.
578 impl<T> !IntoIterator for UnordBag<T> {}
579 impl<V> !IntoIterator for UnordSet<V> {}
580 impl<K, V> !IntoIterator for UnordMap<K, V> {}
581 impl<T, I> !IntoIterator for UnordItems<T, I> {}