Skip to main content

vstd/std_specs/
hash.rs

1//! This code adds specifications for the standard-library types
2//! `std::collections::HashMap` and `std::collections::HashSet`.
3//!
4//! Most of the specification only applies if you use `HashMap<Key,
5//! Value>` or `HashSet<Key>`. If you use some custom build hasher,
6//! e.g., with`HashMap<Key, Value, CustomBuildHasher>`, the
7//! specification won't specify much.
8//!
9//! Likewise, the specification is only meaningful when the `Key`
10//! obeys our hash table model, i.e., (1) `Key::hash` is
11//! deterministic, (2) any two `Key`s are identical if and only if the
12//! executable `==` operator considers them equal, and (3)
13//! `Key::clone` produces a result equal to its input. We have an
14//! axiom that all primitive types and `Box`es thereof obey this
15//! model. But if you want to use some other key type `MyKey`, you
16//! need to explicitly state your assumption that it does so with
17//! `assume(vstd::std_specs::hash::obeys_key_model::<MyKey>());`. In
18//! the future, we plan to devise a way for you to prove that it does
19//! so, so that you don't have to make such an assumption.
20//!
21//! By default, the Verus standard library brings useful axioms
22//! about the behavior of `HashMap` and `HashSet` into the ambient
23//! reasoning context by broadcasting the group
24//! `vstd::std_specs::hash::group_hash_axioms`.
25use super::super::prelude::*;
26use super::iter::IteratorSpec;
27
28use core::alloc::Allocator;
29use core::borrow::Borrow;
30use core::hash::{BuildHasher, Hash, Hasher};
31use core::marker::PhantomData;
32use core::option::Option;
33use core::option::Option::None;
34use std::collections::hash_map;
35use std::collections::hash_map::{
36    DefaultHasher, Entry, Keys, OccupiedEntry, RandomState, VacantEntry, Values,
37};
38use std::collections::hash_set;
39use std::collections::{HashMap, HashSet};
40
41verus! {
42
43/// Specifications for the behavior of
44/// [`std::collections::hash_map::DefaultHasher`](https://doc.rust-lang.org/std/collections/hash_map/struct.DefaultHasher.html).
45///
46/// We model a `DefaultHasher` as having a view (i.e., an abstract
47/// state) of type `Seq<Seq<u8>>`. This reflects the sequence of write
48/// operations performed so far, where each write is modeled as having
49/// written a sequence of bytes. There's also a specification for
50/// how a view will be transformed by `finish` into a `u64`.
51#[verifier::external_type_specification]
52#[verifier::external_body]
53pub struct ExDefaultHasher(DefaultHasher);
54
55impl View for DefaultHasher {
56    type V = Seq<Seq<u8>>;
57
58    #[verifier::external_body]
59    uninterp spec fn view(&self) -> Seq<Seq<u8>>;
60}
61
62pub trait DefaultHasherAdditionalSpecFns {
63    spec fn spec_finish(s: Seq<Seq<u8>>) -> u64;
64}
65
66impl DefaultHasherAdditionalSpecFns for DefaultHasher {
67    #[verifier::external_body]
68    uninterp spec fn spec_finish(s: Seq<Seq<u8>>) -> u64;
69}
70
71// This is the specification of behavior for `DefaultHasher::new()`.
72pub assume_specification[ DefaultHasher::new ]() -> (result: DefaultHasher)
73    ensures
74        result@ == Seq::<Seq<u8>>::empty(),
75;
76
77// This is the specification of behavior for `DefaultHasher::write(&[u8])`.
78pub assume_specification[ DefaultHasher::write ](state: &mut DefaultHasher, bytes: &[u8])
79    ensures
80        final(state)@ == old(state)@.push(bytes@),
81;
82
83// This is the specification of behavior for `DefaultHasher::finish()`.
84pub assume_specification[ DefaultHasher::finish ](state: &DefaultHasher) -> (result: u64)
85    ensures
86        result == DefaultHasher::spec_finish(state@),
87;
88
89/// Specifies whether a type `Key` conforms to our requirements to be
90/// a key in our hash table (and hash set) model.
91///
92/// The three requirements are (1) the hash function is deterministic,
93/// (2) any two keys of type `Key` are identical if and only if they
94/// are considered equal by the executable `==` operator, and (3) the
95/// executable `Key::clone` function produces a result identical to
96/// its input. Requirement (1) isn't satisfied by having `Key`
97/// implement `Hash`, since this trait doesn't mandate determinism.
98///
99/// The standard library has axioms that all primitive types and `Box`es
100/// thereof obey this model. If you want to use some other key
101/// type `MyKey`, you need to explicitly state your assumption that it
102/// does so with
103/// `assume(vstd::std_specs::hash::obeys_key_model::<MyKey>())`.
104/// In the future, we plan to devise a way for you to prove that it
105/// does so, so that you don't have to make such an assumption.
106#[verifier::external_body]
107pub uninterp spec fn obeys_key_model<Key: ?Sized>() -> bool;
108
109// These axioms state that any primitive type, or `Box` thereof,
110// obeys the requirements to be a key in a hash table that
111// conforms to our hash-table model.
112// (Declare each separately to enable pruning of unused primitive types.)
113pub broadcast proof fn axiom_bool_obeys_hash_table_key_model()
114    ensures
115        #[trigger] obeys_key_model::<bool>(),
116{
117    admit();
118}
119
120pub broadcast proof fn axiom_u8_obeys_hash_table_key_model()
121    ensures
122        #[trigger] obeys_key_model::<u8>(),
123{
124    admit();
125}
126
127pub broadcast proof fn axiom_u16_obeys_hash_table_key_model()
128    ensures
129        #[trigger] obeys_key_model::<u16>(),
130{
131    admit();
132}
133
134pub broadcast proof fn axiom_u32_obeys_hash_table_key_model()
135    ensures
136        #[trigger] obeys_key_model::<u32>(),
137{
138    admit();
139}
140
141pub broadcast proof fn axiom_u64_obeys_hash_table_key_model()
142    ensures
143        #[trigger] obeys_key_model::<u64>(),
144{
145    admit();
146}
147
148pub broadcast proof fn axiom_u128_obeys_hash_table_key_model()
149    ensures
150        #[trigger] obeys_key_model::<u128>(),
151{
152    admit();
153}
154
155pub broadcast proof fn axiom_usize_obeys_hash_table_key_model()
156    ensures
157        #[trigger] obeys_key_model::<usize>(),
158{
159    admit();
160}
161
162pub broadcast proof fn axiom_i8_obeys_hash_table_key_model()
163    ensures
164        #[trigger] obeys_key_model::<i8>(),
165{
166    admit();
167}
168
169pub broadcast proof fn axiom_i16_obeys_hash_table_key_model()
170    ensures
171        #[trigger] obeys_key_model::<i16>(),
172{
173    admit();
174}
175
176pub broadcast proof fn axiom_i32_obeys_hash_table_key_model()
177    ensures
178        #[trigger] obeys_key_model::<i32>(),
179{
180    admit();
181}
182
183pub broadcast proof fn axiom_i64_obeys_hash_table_key_model()
184    ensures
185        #[trigger] obeys_key_model::<i64>(),
186{
187    admit();
188}
189
190pub broadcast proof fn axiom_i128_obeys_hash_table_key_model()
191    ensures
192        #[trigger] obeys_key_model::<i128>(),
193{
194    admit();
195}
196
197pub broadcast proof fn axiom_isize_obeys_hash_table_key_model()
198    ensures
199        #[trigger] obeys_key_model::<isize>(),
200{
201    admit();
202}
203
204pub broadcast proof fn axiom_box_bool_obeys_hash_table_key_model()
205    ensures
206        #[trigger] obeys_key_model::<Box<bool>>(),
207{
208    admit();
209}
210
211pub broadcast proof fn axiom_box_integer_type_obeys_hash_table_key_model<Key: Integer + ?Sized>()
212    requires
213        obeys_key_model::<Key>(),
214    ensures
215        #[trigger] obeys_key_model::<Box<Key>>(),
216{
217    admit();
218}
219
220#[verifier::external_trait_specification]
221pub trait ExHasher {
222    type ExternalTraitSpecificationFor: Hasher;
223}
224
225// Our model for the external trait `BuildHasher` is that for any two
226// `Hasher`s it builds, if they're both given the same write sequence
227// then their states will match and they'll produce the same digest
228// when invoked with `finish()`.
229//
230// We don't expect that all types implementing the `BuildHasher` trait
231// will conform to our model, just the types T for which
232// `builds_valid_hashers::<T>()` holds.
233#[verifier::external_trait_specification]
234pub trait ExBuildHasher {
235    type ExternalTraitSpecificationFor: BuildHasher;
236
237    type Hasher: Hasher;
238}
239
240/// Specifies whether a type conforms to our requirements to be a hash builder
241/// in our hash table (and hash set) model.
242///
243/// Our model requires that for any two `Hasher`s that the `BuildHasher` builds,
244/// if they're both given the same write sequence
245/// then their states will match and they'll produce the same digest
246/// when invoked with `finish()`.
247///
248/// The standard library has an axiom that `RandomState`, the default `BuildHasher`
249/// used by `HashMap` and `HashSet`, implements this model.
250/// If you want to use some other hash builder type `MyHashBuilder`,
251/// you need to explicitly state your assumption that it does so with
252/// `assume(vstd::std_specs::hash::builds_valid_hashers::<MyHashBuilder>())`.
253#[verifier::external_body]
254pub uninterp spec fn builds_valid_hashers<T: ?Sized>() -> bool;
255
256/// Specifications for the behavior of
257/// [`std::hash::RandomState`](https://doc.rust-lang.org/std/hash/struct.RandomState.html).
258///
259/// `RandomState` is the default `BuildHasher` used by Rust's `HashMap` and `HashSet` implementations.
260/// We have an axiom that `RandomState` satisfies [`builds_valid_hashers()`](https://verus-lang.github.io/verus/verusdoc/vstd/std_specs/hash/fn.builds_valid_hashers.html)
261/// and thereby conforms to our model of how `BuildHasher` behaves.
262#[verifier::external_type_specification]
263#[verifier::external_body]
264pub struct ExRandomState(RandomState);
265
266pub broadcast proof fn axiom_random_state_builds_valid_hashers()
267    ensures
268        #[trigger] builds_valid_hashers::<RandomState>(),
269{
270    admit();
271}
272
273/// Specifications for the behavior of
274/// [`std::collections::hash_map::Keys`](https://doc.rust-lang.org/std/collections/hash_map/struct.Keys.html).
275#[verifier::external_type_specification]
276#[verifier::external_body]
277#[verifier::accept_recursive_types(Key)]
278#[verifier::accept_recursive_types(Value)]
279pub struct ExKeys<'a, Key: 'a, Value: 'a>(Keys<'a, Key, Value>);
280
281// To allow reasoning about the "contents" of the Keys iterator, without using
282// a prophecy, we need a function that gives us the underlying sequence of the original keys.
283pub uninterp spec fn into_iter_keys<'a, Key, Value>(i: Keys<'a, Key, Value>) -> Seq<Key>;
284
285impl<'a, K, V> super::iter::IteratorSpecImpl for Keys<'a, K, V> {
286    open spec fn obeys_prophetic_iter_laws(&self) -> bool {
287        true
288    }
289
290    uninterp spec fn remaining(&self) -> Seq<Self::Item>;
291
292    uninterp spec fn will_return_none(&self) -> bool;
293
294    uninterp spec fn decrease(&self) -> Option<nat>;
295
296    open spec fn peek(&self, index: int) -> Option<Self::Item> {
297        if 0 <= index < into_iter_keys(*self).len() {
298            Some(&into_iter_keys(*self)[index])
299        } else {
300            None
301        }
302    }
303}
304
305/// Specifications for the behavior of
306/// [`std::collections::hash_map::Values`](https://doc.rust-lang.org/std/collections/hash_map/struct.Values.html).
307#[verifier::external_type_specification]
308#[verifier::external_body]
309#[verifier::accept_recursive_types(Key)]
310#[verifier::accept_recursive_types(Value)]
311pub struct ExValues<'a, Key: 'a, Value: 'a>(Values<'a, Key, Value>);
312
313// To allow reasoning about the "contents" of the Values iterator, without using
314// a prophecy, we need a function that gives us the underlying sequence of the original values.
315pub uninterp spec fn into_iter_values<'a, Key, Value>(i: Values<'a, Key, Value>) -> Seq<Value>;
316
317impl<'a, K, V> super::iter::IteratorSpecImpl for Values<'a, K, V> {
318    open spec fn obeys_prophetic_iter_laws(&self) -> bool {
319        true
320    }
321
322    uninterp spec fn remaining(&self) -> Seq<Self::Item>;
323
324    uninterp spec fn will_return_none(&self) -> bool;
325
326    uninterp spec fn decrease(&self) -> Option<nat>;
327
328    open spec fn peek(&self, index: int) -> Option<Self::Item> {
329        if 0 <= index < into_iter_values(*self).len() {
330            Some(&into_iter_values(*self)[index])
331        } else {
332            None
333        }
334    }
335}
336
337// The `iter` method of a `HashMap` returns an iterator of type `hash_map::Iter`,
338// so we specify that type here.
339#[verifier::external_type_specification]
340#[verifier::external_body]
341#[verifier::accept_recursive_types(Key)]
342#[verifier::accept_recursive_types(Value)]
343pub struct ExMapIter<'a, Key: 'a, Value: 'a>(hash_map::Iter<'a, Key, Value>);
344
345// To allow reasoning about the "contents" of the Iter iterator, without using
346// a prophecy, we need a function that gives us the underlying sequence of the original map.
347pub uninterp spec fn into_iter<'a, Key, Value>(i: hash_map::Iter<'a, Key, Value>) -> Seq<
348    (Key, Value),
349>;
350
351impl<'a, K, V> super::iter::IteratorSpecImpl for hash_map::Iter<'a, K, V> {
352    open spec fn obeys_prophetic_iter_laws(&self) -> bool {
353        true
354    }
355
356    uninterp spec fn remaining(&self) -> Seq<Self::Item>;
357
358    uninterp spec fn will_return_none(&self) -> bool;
359
360    uninterp spec fn decrease(&self) -> Option<nat>;
361
362    open spec fn peek(&self, index: int) -> Option<Self::Item> {
363        if 0 <= index < into_iter(*self).len() {
364            let (k, v) = into_iter(*self)[index];
365            Some((&k, &v))
366        } else {
367            None
368        }
369    }
370}
371
372pub assume_specification<'a, Key, Value, S, A: Allocator>[ HashMap::<Key, Value, S, A>::iter ](
373    m: &'a HashMap<Key, Value, S, A>,
374) -> (iter: hash_map::Iter<'a, Key, Value>)
375    ensures
376        obeys_key_model::<Key>() && builds_valid_hashers::<S>() ==> {
377            &&& IteratorSpec::remaining(&iter).len() == m@.dom().len()
378            &&& forall|i: int|
379                #![trigger m@.contains_key(*IteratorSpec::remaining(&iter)[i].0)]
380                #![trigger m@[*IteratorSpec::remaining(&iter)[i].0]]
381                0 <= i < IteratorSpec::remaining(&iter).len() ==> m@.contains_key(
382                    *IteratorSpec::remaining(&iter)[i].0,
383                ) && m@[*IteratorSpec::remaining(&iter)[i].0] == *IteratorSpec::remaining(
384                    &iter,
385                )[i].1
386            &&& forall|k: Key| #[trigger]
387                m@.contains_key(k) ==> IteratorSpec::remaining(&iter).contains((&k, &m@[k]))
388            &&& IteratorSpec::remaining(&iter).unref().to_set() == m@.kv_pairs()
389            &&& iter.remaining().no_duplicates()
390            &&& into_iter(iter) == IteratorSpec::remaining(&iter).unref()
391            &&& IteratorSpec::decrease(&iter) is Some
392        },
393;
394
395/// Specifications for the behavior of [`std::collections::HashMap`](https://doc.rust-lang.org/std/collections/struct.HashMap.html).
396///
397/// We model a `HashMap` as having a view of type `Map<Key, Value>`, which reflects the current state of the map.
398///
399/// These specifications are only meaningful if `obeys_key_model::<Key>()` and `builds_valid_hashers::<S>()` hold.
400/// See [`obeys_key_model()`](https://verus-lang.github.io/verus/verusdoc/vstd/std_specs/hash/fn.obeys_key_model.html)
401/// for information on use with primitive types and other types,
402/// and see [`builds_valid_hashers()`](https://verus-lang.github.io/verus/verusdoc/vstd/std_specs/hash/fn.builds_valid_hashers.html)
403/// for information on use with Rust's default implementation and custom implementations.
404///
405/// Axioms about the behavior of HashMap are present in the broadcast group `vstd::std_specs::hash::group_hash_axioms`.
406#[verifier::external_type_specification]
407#[verifier::external_body]
408#[verifier::accept_recursive_types(Key)]
409#[verifier::accept_recursive_types(Value)]
410#[verifier::reject_recursive_types(S)]
411#[verifier::reject_recursive_types(A)]
412pub struct ExHashMap<Key, Value, S, A: Allocator>(HashMap<Key, Value, S, A>);
413
414pub trait HashMapAdditionalSpecFns<Key, Value>: View<V = Map<Key, Value>> {
415    spec fn spec_index(&self, k: Key) -> Value
416        recommends
417            self@.contains_key(k),
418    ;
419}
420
421impl<Key, Value, S, A: Allocator> HashMapAdditionalSpecFns<Key, Value> for HashMap<
422    Key,
423    Value,
424    S,
425    A,
426> {
427    #[verifier::inline]
428    open spec fn spec_index(&self, k: Key) -> Value {
429        self@.index(k)
430    }
431}
432
433/// The actual definition of `HashMap::deep_view`.
434///
435/// This is a separate function since it introduces a lot of quantifiers and revealing an opaque trait
436/// method is not supported. In most cases, it's easier to use one of the lemmas below instead
437/// of revealing this function directly.
438#[verifier::opaque]
439pub open spec fn hash_map_deep_view_impl<
440    Key: DeepView,
441    Value: DeepView,
442    S,
443    A: core::alloc::Allocator,
444>(m: HashMap<Key, Value, S, A>) -> Map<Key::V, Value::V> {
445    Map::new(
446        m@.dom().map(|k: Key| k.deep_view()),
447        |dk: Key::V|
448            {
449                let k = choose|k: Key| m@.contains_key(k) && #[trigger] k.deep_view() == dk;
450                m@[k].deep_view()
451            },
452    )
453}
454
455pub broadcast proof fn lemma_hashmap_deepview_dom<K: DeepView, V: DeepView>(m: HashMap<K, V>)
456    ensures
457        #[trigger] m.deep_view().dom() == m@.dom().map(|k: K| k.deep_view()),
458{
459    reveal(hash_map_deep_view_impl);
460    broadcast use group_hash_axioms;
461    broadcast use crate::vstd::group_vstd_default;
462
463    assert(m.deep_view().dom() =~= m@.dom().map(|k: K| k.deep_view()));
464}
465
466pub broadcast proof fn lemma_hashmap_deepview_properties<K: DeepView, V: DeepView>(m: HashMap<K, V>)
467    requires
468        crate::relations::injective(|k: K| k.deep_view()),
469    ensures
470        #![trigger m.deep_view()]
471        // all elements in m.view() are present in m.deep_view()
472        forall|k: K| #[trigger]
473            m@.contains_key(k) ==> m.deep_view().contains_key(k.deep_view())
474                && m.deep_view()[k.deep_view()] == m@[k].deep_view(),
475        // all elements in m.deep_view() are present in m.view()
476        forall|dk: <K as DeepView>::V| #[trigger]
477            m.deep_view().contains_key(dk) ==> exists|k: K|
478                k.deep_view() == dk && #[trigger] m@.contains_key(k),
479{
480    reveal(hash_map_deep_view_impl);
481    broadcast use group_hash_axioms;
482    broadcast use crate::vstd::group_vstd_default;
483
484    lemma_hashmap_deepview_dom(m);
485    assert(m.deep_view().dom() == m@.dom().map(|k: K| k.deep_view()));
486    assert forall|k: K| #[trigger] m@.contains_key(k) implies m.deep_view().contains_key(
487        k.deep_view(),
488    ) && m.deep_view()[k.deep_view()] == m@[k].deep_view() by {
489        assert(m@.dom().contains(k));
490        assert(m@.dom().map(|k: K| k.deep_view()).contains(k.deep_view()));
491        assert(m.deep_view().dom().contains(k.deep_view()));
492        let k2 = choose|k2: K| m@.contains_key(k2) && #[trigger] k2.deep_view() == k.deep_view();
493        assert forall|k1: K, k2: K| #[trigger]
494            k1.deep_view() == #[trigger] k2.deep_view() implies k1 == k2 by {
495            let ghost k_deepview = |k: K| k.deep_view();
496            assert(crate::relations::injective(k_deepview));
497            assert(k_deepview(k1) == k_deepview(k2));
498        }
499        assert(k2 == k);
500    }
501    assert forall|dk: K::V| #[trigger] m.deep_view().contains_key(dk) implies exists|k: K|
502        k.deep_view() == dk && #[trigger] m@.contains_key(k) by {
503        assert(m.deep_view().dom().contains(dk));
504        assert(m@.dom().map(|k: K| k.deep_view()).contains(dk));
505        let k = choose|k: K| #[trigger] m@.dom().contains(k) && k.deep_view() == dk;
506        assert(m@.contains_key(k));
507    }
508}
509
510pub broadcast proof fn lemma_hashmap_deepview_values<K: DeepView, V: DeepView>(m: HashMap<K, V>)
511    requires
512        crate::relations::injective(|k: K| k.deep_view()),
513    ensures
514        #[trigger] m.deep_view().values() =~= m@.values().map(|v: V| v.deep_view()),
515{
516    reveal(hash_map_deep_view_impl);
517    broadcast use group_hash_axioms;
518    broadcast use lemma_hashmap_deepview_properties;
519    broadcast use crate::vstd::group_vstd_default;
520
521    let lhs = m.deep_view().values();
522    let rhs = m@.values().map(|v: V| v.deep_view());
523    assert forall|v: V::V| #[trigger] lhs.contains(v) implies rhs.contains(v) by {
524        let dk = choose|dk: K::V| #[trigger]
525            m.deep_view().contains_key(dk) && m.deep_view()[dk] == v;
526        let k = choose|k: K| #[trigger] m@.contains_key(k) && k.deep_view() == dk;
527        let ov = choose|ov: V| #[trigger] m@.contains_key(k) && m@[k] == ov && ov.deep_view() == v;
528        assert(v == ov.deep_view());
529        assert(m@.values().contains(ov));
530    }
531}
532
533/// Borrowing a key works the same way on deep_view as on view,
534/// if deep_view is injective; see `axiom_contains_deref_key`.
535pub broadcast proof fn axiom_hashmap_deepview_borrow<
536    K: DeepView + Borrow<Q>,
537    V: DeepView,
538    Q: View<V = <K as DeepView>::V> + Hash + Eq + ?Sized,
539>(m: HashMap<K, V>, k: &Q)
540    requires
541        obeys_key_model::<K>(),
542        crate::relations::injective(|k: K| k.deep_view()),
543    ensures
544        #[trigger] contains_borrowed_key(m@, k) <==> m.deep_view().contains_key(k@),
545{
546    admit();
547}
548
549pub uninterp spec fn spec_hash_map_len<Key, Value, S, A: Allocator>(
550    m: &HashMap<Key, Value, S, A>,
551) -> usize;
552
553pub broadcast proof fn axiom_spec_hash_map_len<Key, Value, S, A: Allocator>(
554    m: &HashMap<Key, Value, S, A>,
555)
556    ensures
557        obeys_key_model::<Key>() && builds_valid_hashers::<S>() ==> #[trigger] spec_hash_map_len(m)
558            == m@.len(),
559{
560    admit();
561}
562
563#[verifier::when_used_as_spec(spec_hash_map_len)]
564pub assume_specification<Key, Value, S, A: Allocator>[ HashMap::<Key, Value, S, A>::len ](
565    m: &HashMap<Key, Value, S, A>,
566) -> (len: usize)
567    ensures
568        len == spec_hash_map_len(m),
569;
570
571pub assume_specification<Key, Value, S, A: Allocator>[ HashMap::<Key, Value, S, A>::is_empty ](
572    m: &HashMap<Key, Value, S, A>,
573) -> (res: bool)
574    ensures
575        res == m@.is_empty(),
576;
577
578pub assume_specification<K: Clone, V: Clone, S: Clone, A: Allocator + Clone>[ <HashMap::<
579    K,
580    V,
581    S,
582    A,
583> as Clone>::clone ](this: &HashMap<K, V, S, A>) -> (other: HashMap<K, V, S, A>)
584    ensures
585        other@.dom() == this@.dom(),
586        forall|key|
587            #![trigger other@.dom().contains(key)]
588            other@.dom().contains(key) ==> cloned(this@[key], #[trigger] other@[key]),
589;
590
591pub assume_specification<Key, Value>[ HashMap::<Key, Value>::new ]() -> (m: HashMap<
592    Key,
593    Value,
594    RandomState,
595>)
596    ensures
597        m@ == Map::<Key, Value>::empty(),
598;
599
600pub assume_specification<K, V, S: core::default::Default>[ <HashMap<
601    K,
602    V,
603    S,
604> as core::default::Default>::default ]() -> (m: HashMap<K, V, S>)
605    ensures
606        m@ == Map::<K, V>::empty(),
607;
608
609pub assume_specification<Key, Value>[ HashMap::<Key, Value>::with_capacity ](capacity: usize) -> (m:
610    HashMap<Key, Value, RandomState>)
611    ensures
612        m@ == Map::<Key, Value>::empty(),
613;
614
615pub assume_specification<Key: Eq + Hash, Value, S: BuildHasher, A: Allocator>[ HashMap::<
616    Key,
617    Value,
618    S,
619    A,
620>::reserve ](m: &mut HashMap<Key, Value, S, A>, additional: usize)
621    ensures
622        final(m)@ == old(m)@,
623;
624
625pub assume_specification<Key: Eq + Hash, Value, S: BuildHasher, A: Allocator>[ HashMap::<
626    Key,
627    Value,
628    S,
629    A,
630>::insert ](m: &mut HashMap<Key, Value, S, A>, k: Key, v: Value) -> (result: Option<Value>)
631    ensures
632        obeys_key_model::<Key>() && builds_valid_hashers::<S>() ==> {
633            &&& final(m)@ == old(m)@.insert(k, v)
634            &&& match result {
635                Some(v) => old(m)@.contains_key(k) && v == old(m)[k],
636                None => !old(m)@.contains_key(k),
637            }
638        },
639;
640
641// The specification for `contains_key` has a parameter `key: &Q`
642// where you'd expect to find `key: &Key`. This allows for the case
643// that `Key` can be borrowed as something other than `&Key`. For
644// instance, `Box<u32>` can be borrowed as `&u32` and `String` can be
645// borrowed as `&str`, so in those cases `Q` would be `u32` and `str`
646// respectively.
647// To deal with this, we have a specification function that opaquely
648// specifies what it means for a map to contain a borrowed key of type
649// `&Q`. And the postcondition of `contains_key` just says that its
650// result matches the output of that specification function. But this
651// isn't very helpful by itself, since there's no body to that
652// specification function. So we have special-case axioms that say
653// what this means in two important circumstances: (1) `Key = Q` and
654// (2) `Key = Box<Q>`.
655pub uninterp spec fn contains_borrowed_key<Key, Value, Q: ?Sized>(
656    m: Map<Key, Value>,
657    k: &Q,
658) -> bool;
659
660pub broadcast proof fn axiom_contains_deref_key<Q, Value>(m: Map<Q, Value>, k: &Q)
661    ensures
662        #[trigger] contains_borrowed_key::<Q, Value, Q>(m, k) <==> m.contains_key(*k),
663{
664    admit();
665}
666
667pub broadcast proof fn axiom_contains_box<Q, Value>(m: Map<Box<Q>, Value>, k: &Q)
668    ensures
669        #[trigger] contains_borrowed_key::<Box<Q>, Value, Q>(m, k) <==> m.contains_key(
670            Box::new(*k),
671        ),
672{
673    admit();
674}
675
676pub assume_specification<
677    Key: Borrow<Q> + Hash + Eq,
678    Value,
679    S: BuildHasher,
680    A: Allocator,
681    Q: Hash + Eq + ?Sized,
682>[ HashMap::<Key, Value, S, A>::contains_key::<Q> ](
683    m: &HashMap<Key, Value, S, A>,
684    k: &Q,
685) -> (result: bool)
686    ensures
687        obeys_key_model::<Key>() && builds_valid_hashers::<S>() ==> result == contains_borrowed_key(
688            m@,
689            k,
690        ),
691;
692
693// The specification for `get` has a parameter `key: &Q` where you'd
694// expect to find `key: &Key`. This allows for the case that `Key` can
695// be borrowed as something other than `&Key`. For instance,
696// `Box<u32>` can be borrowed as `&u32` and `String` can be borrowed
697// as `&str`, so in those cases `Q` would be `u32` and `str`
698// respectively.
699// To deal with this, we have a specification function that opaquely
700// specifies what it means for a map to map a borrowed key of type
701// `&Q` to a certain value. And the postcondition of `get` says that
702// its result matches the output of that specification function. (It
703// also says that its result corresponds to the output of
704// `contains_borrowed_key`, discussed above.) But this isn't very
705// helpful by itself, since there's no body to that specification
706// function. So we have special-case axioms that say what this means
707// in two important circumstances: (1) `Key = Q` and (2) `Key =
708// Box<Q>`.
709pub uninterp spec fn maps_borrowed_key_to_value<Key, Value, Q: ?Sized>(
710    m: Map<Key, Value>,
711    k: &Q,
712    v: Value,
713) -> bool;
714
715pub broadcast proof fn axiom_maps_deref_key_to_value<Q, Value>(m: Map<Q, Value>, k: &Q, v: Value)
716    ensures
717        #[trigger] maps_borrowed_key_to_value::<Q, Value, Q>(m, k, v) <==> m.contains_key(*k)
718            && m[*k] == v,
719{
720    admit();
721}
722
723pub broadcast proof fn axiom_maps_box_key_to_value<Q, Value>(m: Map<Box<Q>, Value>, q: &Q, v: Value)
724    ensures
725        #[trigger] maps_borrowed_key_to_value::<Box<Q>, Value, Q>(m, q, v) <==> {
726            let k = Box::new(*q);
727            &&& m.contains_key(k)
728            &&& m[k] == v
729        },
730{
731    admit();
732}
733
734pub assume_specification<
735    'a,
736    Key: Borrow<Q> + Hash + Eq,
737    Value,
738    S: BuildHasher,
739    A: Allocator,
740    Q: Hash + Eq + ?Sized,
741>[ HashMap::<Key, Value, S, A>::get::<Q> ](m: &'a HashMap<Key, Value, S, A>, k: &Q) -> (result:
742    Option<&'a Value>)
743    ensures
744        obeys_key_model::<Key>() && builds_valid_hashers::<S>() ==> match result {
745            Some(v) => maps_borrowed_key_to_value(m@, k, *v),
746            None => !contains_borrowed_key(m@, k),
747        },
748;
749
750// The specification for `remove` has a parameter `key: &Q` where
751// you'd expect to find `key: &Key`. This allows for the case that
752// `Key` can be borrowed as something other than `&Key`. For instance,
753// `Box<u32>` can be borrowed as `&u32` and `String` can be borrowed
754// as `&str`, so in those cases `Q` would be `u32` and `str`
755// respectively. To deal with this, we have a specification function
756// that opaquely specifies what it means for two maps to be related by
757// a remove of a certain `&Q`. And the postcondition of `remove` says
758// that `old(self)@` and `self@` satisfy that relationship. (It also
759// says that its result corresponds to the output of
760// `contains_borrowed_key` and `maps_borrowed_key_to_value`, discussed
761// above.) But this isn't very helpful by itself, since there's no
762// body to that specification function. So we have special-case axioms
763// that say what this means in two important circumstances: (1) `Key =
764// Q` and (2) `Key = Box<Q>`.
765pub uninterp spec fn borrowed_key_removed<Key, Value, Q: ?Sized>(
766    old_m: Map<Key, Value>,
767    new_m: Map<Key, Value>,
768    k: &Q,
769) -> bool;
770
771pub broadcast proof fn axiom_deref_key_removed<Q, Value>(
772    old_m: Map<Q, Value>,
773    new_m: Map<Q, Value>,
774    k: &Q,
775)
776    ensures
777        #[trigger] borrowed_key_removed::<Q, Value, Q>(old_m, new_m, k) <==> new_m == old_m.remove(
778            *k,
779        ),
780{
781    admit();
782}
783
784pub broadcast proof fn axiom_box_key_removed<Q, Value>(
785    old_m: Map<Box<Q>, Value>,
786    new_m: Map<Box<Q>, Value>,
787    q: &Q,
788)
789    ensures
790        #[trigger] borrowed_key_removed::<Box<Q>, Value, Q>(old_m, new_m, q) <==> new_m
791            == old_m.remove(Box::new(*q)),
792{
793    admit();
794}
795
796pub assume_specification<
797    Key: Borrow<Q> + Hash + Eq,
798    Value,
799    S: BuildHasher,
800    A: Allocator,
801    Q: Hash + Eq + ?Sized,
802>[ HashMap::<Key, Value, S, A>::remove::<Q> ](m: &mut HashMap<Key, Value, S, A>, k: &Q) -> (result:
803    Option<Value>)
804    ensures
805        obeys_key_model::<Key>() && builds_valid_hashers::<S>() ==> {
806            &&& borrowed_key_removed(old(m)@, final(m)@, k)
807            &&& match result {
808                Some(v) => maps_borrowed_key_to_value(old(m)@, k, v),
809                None => !contains_borrowed_key(old(m)@, k),
810            }
811        },
812;
813
814pub assume_specification<Key, Value, S, A: Allocator>[ HashMap::<Key, Value, S, A>::clear ](
815    m: &mut HashMap<Key, Value, S, A>,
816)
817    ensures
818        final(m)@ == Map::<Key, Value>::empty(),
819;
820
821pub assume_specification<'a, Key, Value, S, A: Allocator>[ HashMap::<Key, Value, S, A>::keys ](
822    m: &'a HashMap<Key, Value, S, A>,
823) -> (keys: Keys<'a, Key, Value>)
824    ensures
825        obeys_key_model::<Key>() && builds_valid_hashers::<S>() ==> {
826            &&& IteratorSpec::remaining(&keys).unref().to_set() == m@.dom()
827            &&& IteratorSpec::remaining(&keys).no_duplicates()
828            &&& IteratorSpec::remaining(&keys).len() == m@.dom().len()
829            &&& into_iter_keys(keys) == IteratorSpec::remaining(&keys).unref()
830            &&& IteratorSpec::decrease(&keys) is Some
831        },
832;
833
834pub assume_specification<'a, Key, Value, S, A: Allocator>[ HashMap::<Key, Value, S, A>::values ](
835    m: &'a HashMap<Key, Value, S, A>,
836) -> (values: Values<'a, Key, Value>)
837    ensures
838        obeys_key_model::<Key>() && builds_valid_hashers::<S>() ==> {
839            &&& IteratorSpec::remaining(&values).unref().to_set() == m@.values()
840            &&& IteratorSpec::remaining(&values).len() == m@.dom().len()
841            &&& into_iter_values(values) == IteratorSpec::remaining(&values).unref()
842            &&& IteratorSpec::decrease(&values) is Some
843        },
844;
845
846pub broadcast proof fn axiom_hashmap_decreases<Key, Value, S>(m: HashMap<Key, Value, S>)
847    ensures
848        #[trigger] (decreases_to!(m => m@)),
849{
850    admit();
851}
852
853// The `iter` method of a `HashSet` returns an iterator of type `hash_set::Iter`,
854// so we specify that type here.
855#[verifier::external_type_specification]
856#[verifier::external_body]
857#[verifier::accept_recursive_types(Key)]
858pub struct ExSetIter<'a, Key: 'a>(hash_set::Iter<'a, Key>);
859
860// To allow reasoning about the "contents" of the HashSet iterator, without using
861// a prophecy, we need a function that gives us the underlying sequence of the original keys.
862pub uninterp spec fn into_iter_hash_keys<'a, Key>(i: hash_set::Iter::<'a, Key>) -> Seq<Key>;
863
864impl<'a, K> super::iter::IteratorSpecImpl for hash_set::Iter::<'a, K> {
865    open spec fn obeys_prophetic_iter_laws(&self) -> bool {
866        true
867    }
868
869    uninterp spec fn remaining(&self) -> Seq<Self::Item>;
870
871    uninterp spec fn will_return_none(&self) -> bool;
872
873    uninterp spec fn decrease(&self) -> Option<nat>;
874
875    open spec fn peek(&self, index: int) -> Option<Self::Item> {
876        if 0 <= index < into_iter_hash_keys(*self).len() {
877            Some(&into_iter_hash_keys(*self)[index])
878        } else {
879            None
880        }
881    }
882}
883
884/// Specifications for the behavior of [`std::collections::HashSet`](https://doc.rust-lang.org/std/collections/struct.HashSet.html).
885///
886/// We model a `HashSet` as having a view of type `Set<Key>`, which reflects the current state of the set.
887///
888/// These specifications are only meaningful if `obeys_key_model::<Key>()` and `builds_valid_hashers::<S>()` hold.
889/// See [`obeys_key_model()`](https://verus-lang.github.io/verus/verusdoc/vstd/std_specs/hash/fn.obeys_key_model.html)
890/// for information on use with primitive types and custom types,
891/// and see [`builds_valid_hashers()`](https://verus-lang.github.io/verus/verusdoc/vstd/std_specs/hash/fn.builds_valid_hashers.html)
892/// for information on use with Rust's default implementation and custom implementations.
893///
894/// Axioms about the behavior of HashSet are present in the broadcast group `vstd::std_specs::hash::group_hash_axioms`.
895#[verifier::external_type_specification]
896#[verifier::external_body]
897#[verifier::accept_recursive_types(Key)]
898#[verifier::reject_recursive_types(S)]
899#[verifier::reject_recursive_types(A)]
900pub struct ExHashSet<Key, S, A: Allocator>(HashSet<Key, S, A>);
901
902pub uninterp spec fn spec_hash_set_len<Key, S, A: Allocator>(m: &HashSet<Key, S, A>) -> usize;
903
904pub broadcast proof fn axiom_spec_hash_set_len<Key, S, A: Allocator>(m: &HashSet<Key, S, A>)
905    ensures
906        obeys_key_model::<Key>() && builds_valid_hashers::<S>() ==> #[trigger] spec_hash_set_len(m)
907            == m@.len(),
908{
909    admit();
910}
911
912#[verifier::when_used_as_spec(spec_hash_set_len)]
913pub assume_specification<Key, S, A: Allocator>[ HashSet::<Key, S, A>::len ](
914    m: &HashSet<Key, S, A>,
915) -> (len: usize)
916    ensures
917        len == spec_hash_set_len(m),
918;
919
920pub assume_specification<Key, S, A: Allocator>[ HashSet::<Key, S, A>::is_empty ](
921    m: &HashSet<Key, S, A>,
922) -> (res: bool)
923    ensures
924        res == m@.is_empty(),
925;
926
927pub assume_specification<Key>[ HashSet::<Key>::new ]() -> (m: HashSet<Key, RandomState>)
928    ensures
929        m@ == Set::<Key>::empty(),
930;
931
932pub assume_specification<T, S: core::default::Default>[ <HashSet<
933    T,
934    S,
935> as core::default::Default>::default ]() -> (m: HashSet<T, S>)
936    ensures
937        m@ == Set::<T>::empty(),
938;
939
940pub assume_specification<Key>[ HashSet::<Key>::with_capacity ](capacity: usize) -> (m: HashSet<
941    Key,
942    RandomState,
943>)
944    ensures
945        m@ == Set::<Key>::empty(),
946;
947
948pub assume_specification<Key: Eq + Hash, S: BuildHasher, A: Allocator>[ HashSet::<
949    Key,
950    S,
951    A,
952>::reserve ](m: &mut HashSet<Key, S, A>, additional: usize)
953    ensures
954        final(m)@ == old(m)@,
955;
956
957pub assume_specification<Key: Eq + Hash, S: BuildHasher, A: Allocator>[ HashSet::<
958    Key,
959    S,
960    A,
961>::insert ](m: &mut HashSet<Key, S, A>, k: Key) -> (result: bool)
962    ensures
963        obeys_key_model::<Key>() && builds_valid_hashers::<S>() ==> {
964            &&& final(m)@ == old(m)@.insert(k)
965            &&& result == !old(m)@.contains(k)
966        },
967;
968
969// The specification for `contains` has a parameter `key: &Q`
970// where you'd expect to find `key: &Key`. This allows for the case
971// that `Key` can be borrowed as something other than `&Key`. For
972// instance, `Box<u32>` can be borrowed as `&u32` and `String` can be
973// borrowed as `&str`, so in those cases `Q` would be `u32` and `str`
974// respectively.
975// To deal with this, we have a specification function that opaquely
976// specifies what it means for a set to contain a borrowed key of type
977// `&Q`. And the postcondition of `contains` just says that its
978// result matches the output of that specification function. But this
979// isn't very helpful by itself, since there's no body to that
980// specification function. So we have special-case axioms that say
981// what this means in two important circumstances: (1) `Key = Q` and
982// (2) `Key = Box<Q>`.
983pub uninterp spec fn set_contains_borrowed_key<Key, Q: ?Sized>(m: Set<Key>, k: &Q) -> bool;
984
985pub broadcast proof fn axiom_set_contains_deref_key<Q>(m: Set<Q>, k: &Q)
986    ensures
987        #[trigger] set_contains_borrowed_key::<Q, Q>(m, k) <==> m.contains(*k),
988{
989    admit();
990}
991
992pub broadcast proof fn axiom_set_contains_box<Q>(m: Set<Box<Q>>, k: &Q)
993    ensures
994        #[trigger] set_contains_borrowed_key::<Box<Q>, Q>(m, k) <==> m.contains(Box::new(*k)),
995{
996    admit();
997}
998
999pub assume_specification<
1000    Key: Borrow<Q> + Hash + Eq,
1001    S: BuildHasher,
1002    A: Allocator,
1003    Q: Hash + Eq + ?Sized,
1004>[ HashSet::<Key, S, A>::contains ](m: &HashSet<Key, S, A>, k: &Q) -> (result: bool)
1005    ensures
1006        obeys_key_model::<Key>() && builds_valid_hashers::<S>() ==> result
1007            == set_contains_borrowed_key(m@, k),
1008;
1009
1010// The specification for `get` has a parameter `key: &Q` where you'd
1011// expect to find `key: &Key`. This allows for the case that `Key` can
1012// be borrowed as something other than `&Key`. For instance,
1013// `Box<u32>` can be borrowed as `&u32` and `String` can be borrowed
1014// as `&str`, so in those cases `Q` would be `u32` and `str`
1015// respectively.
1016// To deal with this, we have a specification function that opaquely
1017// specifies what it means for a returned reference to point to an
1018// element of a HashSet. And the postcondition of `get` says that
1019// its result matches the output of that specification function. (It
1020// also says that its result corresponds to the output of
1021// `contains_borrowed_key`, discussed above.) But this isn't very
1022// helpful by itself, since there's no body to that specification
1023// function. So we have special-case axioms that say what this means
1024// in two important circumstances: (1) `Key = Q` and (2) `Key =
1025// Box<Q>`.
1026pub uninterp spec fn sets_borrowed_key_to_key<Key, Q: ?Sized>(m: Set<Key>, k: &Q, v: &Key) -> bool;
1027
1028pub broadcast proof fn axiom_set_deref_key_to_value<Q>(m: Set<Q>, k: &Q, v: &Q)
1029    ensures
1030        #[trigger] sets_borrowed_key_to_key::<Q, Q>(m, k, v) <==> m.contains(*k) && k == v,
1031{
1032    admit();
1033}
1034
1035pub broadcast proof fn axiom_set_box_key_to_value<Q>(m: Set<Box<Q>>, q: &Q, v: &Box<Q>)
1036    ensures
1037        #[trigger] sets_borrowed_key_to_key::<Box<Q>, Q>(m, q, v) <==> (m.contains(*v) && Box::new(
1038            *q,
1039        ) == v),
1040{
1041    admit();
1042}
1043
1044pub assume_specification<
1045    'a,
1046    Key: Borrow<Q> + Hash + Eq,
1047    S: BuildHasher,
1048    A: Allocator,
1049    Q: Hash + Eq + ?Sized,
1050>[ HashSet::<Key, S, A>::get::<Q> ](m: &'a HashSet<Key, S, A>, k: &Q) -> (result: Option<&'a Key>)
1051    ensures
1052        obeys_key_model::<Key>() && builds_valid_hashers::<S>() ==> match result {
1053            Some(v) => sets_borrowed_key_to_key(m@, k, v),
1054            None => !set_contains_borrowed_key(m@, k),
1055        },
1056;
1057
1058// The specification for `remove` has a parameter `key: &Q` where
1059// you'd expect to find `key: &Key`. This allows for the case that
1060// `Key` can be borrowed as something other than `&Key`. For instance,
1061// `Box<u32>` can be borrowed as `&u32` and `String` can be borrowed
1062// as `&str`, so in those cases `Q` would be `u32` and `str`
1063// respectively. To deal with this, we have a specification function
1064// that opaquely specifies what it means for two sets to be related by
1065// a remove of a certain `&Q`. And the postcondition of `remove` says
1066// that `old(self)@` and `self@` satisfy that relationship. (It also
1067// says that its result corresponds to the output of
1068// `set_contains_borrowed_key`, discussed above.) But this isn't very
1069// helpful by itself, since there's no body to that specification
1070// function. So we have special-case axioms that say what this means
1071// in two important circumstances: (1) `Key = Q` and (2) `Key = Box<Q>`.
1072pub uninterp spec fn sets_differ_by_borrowed_key<Key, Q: ?Sized>(
1073    old_m: Set<Key>,
1074    new_m: Set<Key>,
1075    k: &Q,
1076) -> bool;
1077
1078pub broadcast proof fn axiom_set_deref_key_removed<Q>(old_m: Set<Q>, new_m: Set<Q>, k: &Q)
1079    ensures
1080        #[trigger] sets_differ_by_borrowed_key::<Q, Q>(old_m, new_m, k) <==> new_m == old_m.remove(
1081            *k,
1082        ),
1083{
1084    admit();
1085}
1086
1087pub broadcast proof fn axiom_set_box_key_removed<Q>(old_m: Set<Box<Q>>, new_m: Set<Box<Q>>, q: &Q)
1088    ensures
1089        #[trigger] sets_differ_by_borrowed_key::<Box<Q>, Q>(old_m, new_m, q) <==> new_m
1090            == old_m.remove(Box::new(*q)),
1091{
1092    admit();
1093}
1094
1095pub assume_specification<
1096    Key: Borrow<Q> + Hash + Eq,
1097    S: BuildHasher,
1098    A: Allocator,
1099    Q: Hash + Eq + ?Sized,
1100>[ HashSet::<Key, S, A>::remove::<Q> ](m: &mut HashSet<Key, S, A>, k: &Q) -> (result: bool)
1101    ensures
1102        obeys_key_model::<Key>() && builds_valid_hashers::<S>() ==> {
1103            &&& sets_differ_by_borrowed_key(old(m)@, final(m)@, k)
1104            &&& result == set_contains_borrowed_key(old(m)@, k)
1105        },
1106;
1107
1108pub assume_specification<Key, S, A: Allocator>[ HashSet::<Key, S, A>::clear ](
1109    m: &mut HashSet<Key, S, A>,
1110)
1111    ensures
1112        final(m)@ == Set::<Key>::empty(),
1113;
1114
1115pub assume_specification<'a, Key, S, A: Allocator>[ HashSet::<Key, S, A>::iter ](
1116    m: &'a HashSet<Key, S, A>,
1117) -> (hash_keys: hash_set::Iter<'a, Key>)
1118    ensures
1119        obeys_key_model::<Key>() && builds_valid_hashers::<S>() ==> {
1120            &&& IteratorSpec::remaining(&hash_keys).unref().to_set() == m@
1121            &&& IteratorSpec::remaining(&hash_keys).no_duplicates()
1122            &&& IteratorSpec::remaining(&hash_keys).len() == m@.len()
1123            &&& into_iter_hash_keys(hash_keys) == IteratorSpec::remaining(&hash_keys).unref()
1124            &&& IteratorSpec::decrease(&hash_keys) is Some
1125        },
1126;
1127
1128pub broadcast proof fn axiom_hashset_decreases<Key, S, A: Allocator>(m: HashSet<Key, S, A>)
1129    ensures
1130        #[trigger] (decreases_to!(m => m@)),
1131{
1132    admit();
1133}
1134
1135//////// Entry API
1136// Specs for OccupiedEntry, VacantEntry, and the Entry enum
1137// OccupiedEntry and VacantEntry are both opaque;
1138// Entry is just an enum wrapper around the other 2, so we leave it transparent.
1139#[verifier::reject_recursive_types_in_ground_variants(K)]
1140#[verifier::reject_recursive_types_in_ground_variants(V)]
1141#[verifier::reject_recursive_types(A)]
1142#[verifier::external_body]
1143#[verifier::external_type_specification]
1144pub struct ExOccupiedEntry<'a, K: 'a, V: 'a, A: Allocator>(OccupiedEntry<'a, K, V, A>);
1145
1146#[verifier::reject_recursive_types_in_ground_variants(K)]
1147#[verifier::accept_recursive_types(V)]
1148#[verifier::reject_recursive_types(A)]
1149#[verifier::external_body]
1150#[verifier::external_type_specification]
1151pub struct ExVacantEntry<'a, K: 'a, V: 'a, A: Allocator>(VacantEntry<'a, K, V, A>);
1152
1153#[verifier::external_type_specification]
1154#[verifier::reject_recursive_types(A)]
1155pub struct ExEntry<'a, K: 'a, V: 'a, A: Allocator>(Entry<'a, K, V, A>);
1156
1157/// Specification for an [`OccupiedEntry`].
1158/// Contains the current key and value in the entry,
1159/// and prophesies the final value after this instantiation of the entry API is complete.
1160/// The final value is optional, since the user might choose to remove the entry.
1161pub trait OccupiedEntrySpecFns<K, V, A>: Sized {
1162    spec fn spec_key(self) -> K;
1163
1164    spec fn value(self) -> V;
1165
1166    #[verifier::prophetic]
1167    spec fn final_value(self) -> Option<V>;
1168}
1169
1170impl<'a, K, V, A: Allocator> OccupiedEntrySpecFns<K, V, A> for OccupiedEntry<'a, K, V, A> {
1171    uninterp spec fn spec_key(self) -> K;
1172
1173    uninterp spec fn value(self) -> V;
1174
1175    #[verifier::prophetic]
1176    uninterp spec fn final_value(self) -> Option<V>;
1177}
1178
1179/// Specification for a [`VacantEntry`].
1180/// Contains the current key for the entry,
1181/// and prophesies the final value after this instantiation of the entry API is complete.
1182/// The final value is optional, since the user may or may not choose to insert a value.
1183pub trait VacantEntrySpecFns<K, V, A>: Sized {
1184    spec fn spec_key(self) -> K;
1185
1186    #[verifier::prophetic]
1187    spec fn final_value(self) -> Option<V>;
1188}
1189
1190impl<'a, K, V, A: Allocator> VacantEntrySpecFns<K, V, A> for VacantEntry<'a, K, V, A> {
1191    uninterp spec fn spec_key(self) -> K;
1192
1193    #[verifier::prophetic]
1194    uninterp spec fn final_value(self) -> Option<V>;
1195}
1196
1197/// Specification for an [`Entry`].
1198/// Contains the current key for the entry,
1199/// and prophesies the final value after this instantiation of the entry API is complete.
1200pub trait EntrySpecFns<K, V, A>: Sized {
1201    spec fn spec_key(self) -> K;
1202
1203    spec fn value(self) -> Option<V>;
1204
1205    #[verifier::prophetic]
1206    spec fn final_value(self) -> Option<V>;
1207}
1208
1209impl<'a, K, V, A: Allocator> EntrySpecFns<K, V, A> for Entry<'a, K, V, A> {
1210    open spec fn spec_key(self) -> K {
1211        match self {
1212            Entry::Occupied(occupied_entry) => occupied_entry.spec_key(),
1213            Entry::Vacant(vacant_entry) => vacant_entry.spec_key(),
1214        }
1215    }
1216
1217    open spec fn value(self) -> Option<V> {
1218        match self {
1219            Entry::Occupied(occupied_entry) => Some(occupied_entry.value()),
1220            Entry::Vacant(vacant_entry) => None,
1221        }
1222    }
1223
1224    #[verifier::prophetic]
1225    open spec fn final_value(self) -> Option<V> {
1226        match self {
1227            Entry::Occupied(occupied_entry) => occupied_entry.final_value(),
1228            Entry::Vacant(vacant_entry) => vacant_entry.final_value(),
1229        }
1230    }
1231}
1232
1233pub broadcast axiom fn axiom_has_resolved_occupied_entry<K, V, A: Allocator>(
1234    entry: OccupiedEntry<K, V, A>,
1235)
1236    ensures
1237        #[trigger] has_resolved(entry) ==> entry.final_value() == Some(entry.value()),
1238;
1239
1240pub broadcast axiom fn axiom_has_resolved_vacant_entry<K, V, A: Allocator>(
1241    entry: VacantEntry<K, V, A>,
1242)
1243    ensures
1244        #[trigger] has_resolved(entry) ==> entry.final_value() == None::<V>,
1245;
1246
1247pub broadcast proof fn axiom_has_resolved_entry<K, V, A: Allocator>(entry: Entry<K, V, A>)
1248    ensures
1249        #[trigger] has_resolved(entry) ==> entry.final_value() == entry.value(),
1250{
1251    broadcast use axiom_has_resolved_occupied_entry;
1252    broadcast use axiom_has_resolved_vacant_entry;
1253
1254}
1255
1256pub assume_specification<'a, Key: Hash + Eq, Value, S: BuildHasher, A: Allocator>[ HashMap::<
1257    Key,
1258    Value,
1259    S,
1260    A,
1261>::entry ](m: &'a mut HashMap<Key, Value, S, A>, key: Key) -> (entry: Entry<'a, Key, Value, A>)
1262    ensures
1263        obeys_key_model::<Key>() && builds_valid_hashers::<S>() ==> (entry.key() == key
1264            && entry.value() == old(m)@.get(key) && final(m)@ == (match entry.final_value() {
1265            Some(value) => old(m)@.insert(key, value),
1266            None => old(m)@.remove(key),
1267        })),
1268;
1269
1270//// Entry
1271#[verifier::allow_in_spec]
1272pub assume_specification<'a, 'b, K, V, A: Allocator>[ Entry::key ](
1273    entry: &'b Entry::<'a, K, V, A>,
1274) -> (key: &'b K)
1275    returns
1276        &entry.spec_key(),
1277;
1278
1279pub assume_specification<'a, K, V, A: Allocator>[ Entry::or_insert ](
1280    entry: Entry::<'a, K, V, A>,
1281    default: V,
1282) -> (value: &'a mut V)
1283    ensures
1284        *value == (match entry.value() {
1285            Some(v) => v,
1286            None => default,
1287        }),
1288        entry.final_value() == Some(*final(value)),
1289;
1290
1291pub assume_specification<'a, K, V, A: Allocator>[ Entry::insert_entry ](
1292    entry: Entry::<'a, K, V, A>,
1293    value: V,
1294) -> (occ_entry: OccupiedEntry<'a, K, V, A>)
1295    ensures
1296        occ_entry.key() == entry.key(),
1297        occ_entry.value() == value,
1298        entry.final_value() == occ_entry.final_value(),
1299;
1300
1301//// OccupiedEntry
1302// This module works around a bug with `allow_in_spec` that creates duplicate spec fn names
1303mod m_occ {
1304    use super::*;
1305
1306    #[verifier::allow_in_spec]
1307    pub assume_specification<'a, 'b, K, V, A: Allocator>[ OccupiedEntry::key ](
1308        entry: &'b OccupiedEntry::<'a, K, V, A>,
1309    ) -> (key: &'b K)
1310        returns
1311            &entry.spec_key(),
1312    ;
1313
1314}
1315
1316pub assume_specification<'a, K, V, A: Allocator>[ OccupiedEntry::remove_entry ](
1317    entry: OccupiedEntry::<'a, K, V, A>,
1318) -> (kv: (K, V))
1319    ensures
1320        entry.final_value() == None,
1321    returns
1322        (*entry.key(), entry.value()),
1323;
1324
1325pub assume_specification<'a, 'b, K, V, A: Allocator>[ OccupiedEntry::get ](
1326    entry: &'b OccupiedEntry::<'a, K, V, A>,
1327) -> (value: &'b V)
1328    ensures
1329        *value == entry.value(),
1330;
1331
1332pub assume_specification<'a, 'b, K, V, A: Allocator>[ OccupiedEntry::get_mut ](
1333    entry: &'b mut OccupiedEntry::<'a, K, V, A>,
1334) -> (value: &'b mut V)
1335    ensures
1336        *value == old(entry).value(),
1337        final(entry).key() == old(entry).key(),
1338        final(entry).value() == *final(value),
1339        final(entry).final_value() == old(entry).final_value(),
1340;
1341
1342pub assume_specification<'a, K, V, A: Allocator>[ OccupiedEntry::into_mut ](
1343    entry: OccupiedEntry::<'a, K, V, A>,
1344) -> (value: &mut V)
1345    ensures
1346        *value == entry.value(),
1347        entry.final_value() == Some(*final(value)),
1348;
1349
1350pub assume_specification<'a, K, V, A: Allocator>[ OccupiedEntry::insert ](
1351    entry: &mut OccupiedEntry::<'a, K, V, A>,
1352    value: V,
1353) -> (old_value: V)
1354    ensures
1355        old_value == old(entry).value(),
1356        final(entry).key() == old(entry).key(),
1357        final(entry).value() == value,
1358        final(entry).final_value() == old(entry).final_value(),
1359;
1360
1361pub assume_specification<'a, K, V, A: Allocator>[ OccupiedEntry::remove ](
1362    entry: OccupiedEntry::<'a, K, V, A>,
1363) -> (value: V)
1364    ensures
1365        value == entry.value(),
1366        entry.final_value() == None,
1367;
1368
1369//// VacantEntry
1370// This module works around a bug with `allow_in_spec` that creates duplicate spec fn names
1371mod m_vac {
1372    use super::*;
1373
1374    #[verifier::allow_in_spec]
1375    pub assume_specification<'a, 'b, K: 'a, V: 'a, A: Allocator>[ VacantEntry::key ](
1376        entry: &'b VacantEntry::<'a, K, V, A>,
1377    ) -> (key: &'b K)
1378        returns
1379            &entry.spec_key(),
1380    ;
1381
1382}
1383
1384pub assume_specification<'a, K: 'a, V: 'a, A: Allocator>[ VacantEntry::into_key ](
1385    entry: VacantEntry::<'a, K, V, A>,
1386) -> (key: K)
1387    ensures
1388        key == entry.key(),
1389        entry.final_value() == None,
1390;
1391
1392pub assume_specification<'a, K: 'a, V: 'a, A: Allocator>[ VacantEntry::insert ](
1393    entry: VacantEntry::<'a, K, V, A>,
1394    value: V,
1395) -> (value_ref: &mut V)
1396    ensures
1397        *value_ref == value,
1398        entry.final_value() == Some(*final(value_ref)),
1399;
1400
1401pub assume_specification<'a, K: 'a, V: 'a, A: Allocator>[ VacantEntry::insert_entry ](
1402    entry: VacantEntry::<'a, K, V, A>,
1403    value: V,
1404) -> (occ_entry: OccupiedEntry::<'a, K, V, A>)
1405    ensures
1406        occ_entry.key() == entry.key(),
1407        occ_entry.value() == value,
1408        entry.final_value() == occ_entry.final_value(),
1409;
1410
1411pub broadcast group group_hash_axioms {
1412    axiom_box_key_removed,
1413    axiom_contains_deref_key,
1414    axiom_contains_box,
1415    axiom_deref_key_removed,
1416    axiom_maps_deref_key_to_value,
1417    axiom_maps_box_key_to_value,
1418    axiom_hashmap_deepview_borrow,
1419    axiom_bool_obeys_hash_table_key_model,
1420    axiom_u8_obeys_hash_table_key_model,
1421    axiom_u16_obeys_hash_table_key_model,
1422    axiom_u32_obeys_hash_table_key_model,
1423    axiom_u64_obeys_hash_table_key_model,
1424    axiom_u128_obeys_hash_table_key_model,
1425    axiom_usize_obeys_hash_table_key_model,
1426    axiom_i8_obeys_hash_table_key_model,
1427    axiom_i16_obeys_hash_table_key_model,
1428    axiom_i32_obeys_hash_table_key_model,
1429    axiom_i64_obeys_hash_table_key_model,
1430    axiom_i128_obeys_hash_table_key_model,
1431    axiom_isize_obeys_hash_table_key_model,
1432    axiom_box_bool_obeys_hash_table_key_model,
1433    axiom_box_integer_type_obeys_hash_table_key_model,
1434    axiom_random_state_builds_valid_hashers,
1435    axiom_spec_hash_map_len,
1436    axiom_set_box_key_removed,
1437    axiom_set_contains_deref_key,
1438    axiom_set_contains_box,
1439    axiom_set_deref_key_removed,
1440    axiom_set_deref_key_to_value,
1441    axiom_set_box_key_to_value,
1442    axiom_spec_hash_set_len,
1443    axiom_hashmap_decreases,
1444    axiom_hashset_decreases,
1445    axiom_has_resolved_occupied_entry,
1446    axiom_has_resolved_vacant_entry,
1447    axiom_has_resolved_entry,
1448}
1449
1450} // verus!