use super::super::prelude::*;
use core::borrow::Borrow;
use core::hash::{BuildHasher, Hash, Hasher};
use core::option::Option;
use core::option::Option::None;
use std::collections::hash_map::{DefaultHasher, RandomState};
use std::collections::{HashMap, HashSet};
verus! {
#[verifier::external_type_specification]
#[verifier::external_body]
pub struct ExDefaultHasher(DefaultHasher);
impl View for DefaultHasher {
type V = Seq<Seq<u8>>;
#[verifier::external_body]
closed spec fn view(&self) -> Seq<Seq<u8>>;
}
pub trait DefaultHasherAdditionalSpecFns {
spec fn spec_finish(s: Seq<Seq<u8>>) -> u64;
}
impl DefaultHasherAdditionalSpecFns for DefaultHasher {
#[verifier::external_body]
spec fn spec_finish(s: Seq<Seq<u8>>) -> u64;
}
#[verifier::external_fn_specification]
pub fn ex_default_hasher_new() -> (result: DefaultHasher)
ensures
result@ == Seq::<Seq<u8>>::empty(),
{
DefaultHasher::new()
}
#[verifier::external_fn_specification]
pub fn ex_default_hasher_write(state: &mut DefaultHasher, bytes: &[u8])
ensures
state@ == old::<&mut _>(state)@.push(bytes@),
{
state.write(bytes)
}
#[verifier::external_fn_specification]
pub fn ex_default_hasher_finish(state: &DefaultHasher) -> (result: u64)
ensures
result == DefaultHasher::spec_finish(state@),
{
state.finish()
}
#[verifier::external_body]
pub spec fn obeys_key_model<Key: ?Sized>() -> bool;
pub broadcast proof fn axiom_bool_obeys_hash_table_key_model()
ensures
#[trigger] obeys_key_model::<bool>(),
{
admit();
}
pub broadcast proof fn axiom_u8_obeys_hash_table_key_model()
ensures
#[trigger] obeys_key_model::<u8>(),
{
admit();
}
pub broadcast proof fn axiom_u16_obeys_hash_table_key_model()
ensures
#[trigger] obeys_key_model::<u16>(),
{
admit();
}
pub broadcast proof fn axiom_u32_obeys_hash_table_key_model()
ensures
#[trigger] obeys_key_model::<u32>(),
{
admit();
}
pub broadcast proof fn axiom_u64_obeys_hash_table_key_model()
ensures
#[trigger] obeys_key_model::<u64>(),
{
admit();
}
pub broadcast proof fn axiom_u128_obeys_hash_table_key_model()
ensures
#[trigger] obeys_key_model::<u128>(),
{
admit();
}
pub broadcast proof fn axiom_i8_obeys_hash_table_key_model()
ensures
#[trigger] obeys_key_model::<i8>(),
{
admit();
}
pub broadcast proof fn axiom_i16_obeys_hash_table_key_model()
ensures
#[trigger] obeys_key_model::<i16>(),
{
admit();
}
pub broadcast proof fn axiom_i32_obeys_hash_table_key_model()
ensures
#[trigger] obeys_key_model::<i32>(),
{
admit();
}
pub broadcast proof fn axiom_i164_obeys_hash_table_key_model()
ensures
#[trigger] obeys_key_model::<i64>(),
{
admit();
}
pub broadcast proof fn axiom_i128_obeys_hash_table_key_model()
ensures
#[trigger] obeys_key_model::<i128>(),
{
admit();
}
pub broadcast proof fn axiom_box_bool_obeys_hash_table_key_model()
ensures
#[trigger] obeys_key_model::<Box<bool>>(),
{
admit();
}
pub broadcast proof fn axiom_box_integer_type_obeys_hash_table_key_model<Key: Integer + ?Sized>()
requires
obeys_key_model::<Key>(),
ensures
#[trigger] obeys_key_model::<Box<Key>>(),
{
admit();
}
#[verifier::external_trait_specification]
pub trait ExHasher {
type ExternalTraitSpecificationFor: Hasher;
}
#[verifier::external_trait_specification]
pub trait ExBuildHasher {
type ExternalTraitSpecificationFor: BuildHasher;
type Hasher: Hasher;
}
#[verifier::external_body]
pub spec fn builds_valid_hashers<T: ?Sized>() -> bool;
#[verifier::external_type_specification]
#[verifier::external_body]
pub struct ExRandomState(RandomState);
pub broadcast proof fn axiom_random_state_builds_valid_hashers()
ensures
#[trigger] builds_valid_hashers::<RandomState>(),
{
admit();
}
#[verifier::external_type_specification]
#[verifier::external_body]
#[verifier::reject_recursive_types(Key)]
#[verifier::reject_recursive_types(Value)]
#[verifier::reject_recursive_types(S)]
pub struct ExHashMap<Key, Value, S>(HashMap<Key, Value, S>);
pub trait HashMapAdditionalSpecFns<Key, Value>: View<V = Map<Key, Value>> {
spec fn spec_index(&self, k: Key) -> Value
recommends
self@.contains_key(k),
;
}
impl<Key, Value, S> HashMapAdditionalSpecFns<Key, Value> for HashMap<Key, Value, S> {
#[verifier::inline]
open spec fn spec_index(&self, k: Key) -> Value {
self@.index(k)
}
}
impl<Key, Value, S> View for HashMap<Key, Value, S> {
type V = Map<Key, Value>;
#[verifier::external_body]
closed spec fn view(&self) -> Map<Key, Value>;
}
pub open spec fn spec_hash_map_len<Key, Value, S>(m: &HashMap<Key, Value, S>) -> usize;
pub broadcast proof fn axiom_spec_hash_map_len<Key, Value, S>(m: &HashMap<Key, Value, S>)
ensures
obeys_key_model::<Key>() && builds_valid_hashers::<S>() ==> #[trigger] spec_hash_map_len(m)
== m@.len(),
{
admit();
}
#[verifier::external_fn_specification]
#[verifier::when_used_as_spec(spec_hash_map_len)]
pub fn ex_hash_map_len<Key, Value, S>(m: &HashMap<Key, Value, S>) -> (len: usize)
ensures
len == spec_hash_map_len(m),
{
m.len()
}
#[verifier::external_fn_specification]
pub fn ex_hash_map_new<Key, Value>() -> (m: HashMap<Key, Value, RandomState>)
ensures
m@ == Map::<Key, Value>::empty(),
{
HashMap::<Key, Value>::new()
}
#[verifier::external_fn_specification]
pub fn ex_hash_map_with_capacity<Key, Value>(capacity: usize) -> (m: HashMap<
Key,
Value,
RandomState,
>)
ensures
m@ == Map::<Key, Value>::empty(),
{
HashMap::<Key, Value>::with_capacity(capacity)
}
#[verifier::external_fn_specification]
pub fn ex_hash_map_reserve<Key, Value, S>(m: &mut HashMap<Key, Value, S>, additional: usize) where
Key: Eq + Hash,
S: BuildHasher,
ensures
m@ == old(m)@,
{
m.reserve(additional)
}
#[verifier::external_fn_specification]
pub fn ex_hash_map_insert<Key, Value, S>(
m: &mut HashMap<Key, Value, S>,
k: Key,
v: Value,
) -> (result: Option<Value>) where Key: Eq + Hash, S: BuildHasher
ensures
obeys_key_model::<Key>() && builds_valid_hashers::<S>() ==> {
&&& m@ == old(m)@.insert(k, v)
&&& match result {
Some(v) => old(m)@.contains_key(k) && v == old(m)[k],
None => !old(m)@.contains_key(k),
}
},
{
m.insert(k, v)
}
pub spec fn contains_borrowed_key<Key, Value, Q: ?Sized>(m: Map<Key, Value>, k: &Q) -> bool;
pub broadcast proof fn axiom_contains_deref_key<Q, Value>(m: Map<Q, Value>, k: &Q)
ensures
#[trigger] contains_borrowed_key::<Q, Value, Q>(m, k) <==> m.contains_key(*k),
{
admit();
}
pub broadcast proof fn axiom_contains_box<Q, Value>(m: Map<Box<Q>, Value>, k: &Q)
ensures
#[trigger] contains_borrowed_key::<Box<Q>, Value, Q>(m, k) <==> m.contains_key(
Box::new(*k),
),
{
admit();
}
#[verifier::external_fn_specification]
pub fn ex_hash_contains_key<Key, Value, S, Q>(m: &HashMap<Key, Value, S>, k: &Q) -> (result:
bool) where Key: Borrow<Q> + Hash + Eq, Q: Hash + Eq + ?Sized, S: BuildHasher
ensures
obeys_key_model::<Key>() && builds_valid_hashers::<S>() ==> result == contains_borrowed_key(
m@,
k,
),
{
m.contains_key(k)
}
pub spec fn maps_borrowed_key_to_value<Key, Value, Q: ?Sized>(
m: Map<Key, Value>,
k: &Q,
v: Value,
) -> bool;
pub broadcast proof fn axiom_maps_deref_key_to_value<Q, Value>(m: Map<Q, Value>, k: &Q, v: Value)
ensures
#[trigger] maps_borrowed_key_to_value::<Q, Value, Q>(m, k, v) <==> m.contains_key(*k)
&& m[*k] == v,
{
admit();
}
pub broadcast proof fn axiom_maps_box_key_to_value<Q, Value>(m: Map<Box<Q>, Value>, q: &Q, v: Value)
ensures
#[trigger] maps_borrowed_key_to_value::<Box<Q>, Value, Q>(m, q, v) <==> {
let k = Box::new(*q);
&&& m.contains_key(k)
&&& m[k] == v
},
{
admit();
}
#[verifier::external_fn_specification]
pub fn ex_hash_map_get<'a, Key, Value, S, Q>(m: &'a HashMap<Key, Value, S>, k: &Q) -> (result:
Option<&'a Value>) where Key: Borrow<Q> + Hash + Eq, Q: Hash + Eq + ?Sized, S: BuildHasher
ensures
obeys_key_model::<Key>() && builds_valid_hashers::<S>() ==> match result {
Some(v) => maps_borrowed_key_to_value(m@, k, *v),
None => !contains_borrowed_key(m@, k),
},
{
m.get(k)
}
pub spec fn borrowed_key_removed<Key, Value, Q: ?Sized>(
old_m: Map<Key, Value>,
new_m: Map<Key, Value>,
k: &Q,
) -> bool;
pub broadcast proof fn axiom_deref_key_removed<Q, Value>(
old_m: Map<Q, Value>,
new_m: Map<Q, Value>,
k: &Q,
)
ensures
#[trigger] borrowed_key_removed::<Q, Value, Q>(old_m, new_m, k) <==> new_m == old_m.remove(
*k,
),
{
admit();
}
pub broadcast proof fn axiom_box_key_removed<Q, Value>(
old_m: Map<Box<Q>, Value>,
new_m: Map<Box<Q>, Value>,
q: &Q,
)
ensures
#[trigger] borrowed_key_removed::<Box<Q>, Value, Q>(old_m, new_m, q) <==> new_m
== old_m.remove(Box::new(*q)),
{
admit();
}
#[verifier::external_fn_specification]
pub fn ex_hash_map_remove<Key, Value, S, Q>(m: &mut HashMap<Key, Value, S>, k: &Q) -> (result:
Option<Value>) where Key: Borrow<Q> + Hash + Eq, Q: Hash + Eq + ?Sized, S: BuildHasher
ensures
obeys_key_model::<Key>() && builds_valid_hashers::<S>() ==> {
&&& borrowed_key_removed(old(m)@, m@, k)
&&& match result {
Some(v) => maps_borrowed_key_to_value(old(m)@, k, v),
None => !contains_borrowed_key(old(m)@, k),
}
},
{
m.remove(k)
}
#[verifier::external_fn_specification]
pub fn ex_hash_map_clear<Key, Value, S>(m: &mut HashMap<Key, Value, S>)
ensures
m@ == Map::<Key, Value>::empty(),
{
m.clear()
}
#[verifier::external_type_specification]
#[verifier::external_body]
#[verifier::reject_recursive_types(Key)]
#[verifier::reject_recursive_types(S)]
pub struct ExHashSet<Key, S>(HashSet<Key, S>);
impl<Key, S> View for HashSet<Key, S> {
type V = Set<Key>;
#[verifier::external_body]
closed spec fn view(&self) -> Set<Key>;
}
pub open spec fn spec_hash_set_len<Key, S>(m: &HashSet<Key, S>) -> usize;
pub broadcast proof fn axiom_spec_hash_set_len<Key, S>(m: &HashSet<Key, S>)
ensures
obeys_key_model::<Key>() && builds_valid_hashers::<S>() ==> #[trigger] spec_hash_set_len(m)
== m@.len(),
{
admit();
}
#[verifier::external_fn_specification]
#[verifier::when_used_as_spec(spec_hash_set_len)]
pub fn ex_hash_set_len<Key, S>(m: &HashSet<Key, S>) -> (len: usize)
ensures
len == spec_hash_set_len(m),
{
m.len()
}
#[verifier::external_fn_specification]
pub fn ex_hash_set_new<Key>() -> (m: HashSet<Key, RandomState>)
ensures
m@ == Set::<Key>::empty(),
{
HashSet::<Key>::new()
}
#[verifier::external_fn_specification]
pub fn ex_hash_set_with_capacity<Key>(capacity: usize) -> (m: HashSet<Key, RandomState>)
ensures
m@ == Set::<Key>::empty(),
{
HashSet::<Key>::with_capacity(capacity)
}
#[verifier::external_fn_specification]
pub fn ex_hash_set_reserve<Key, S>(m: &mut HashSet<Key, S>, additional: usize) where
Key: Eq + Hash,
S: BuildHasher,
ensures
m@ == old(m)@,
{
m.reserve(additional)
}
#[verifier::external_fn_specification]
pub fn ex_hash_set_insert<Key, S>(m: &mut HashSet<Key, S>, k: Key) -> (result: bool) where
Key: Eq + Hash,
S: BuildHasher,
ensures
obeys_key_model::<Key>() && builds_valid_hashers::<S>() ==> {
&&& m@ == old(m)@.insert(k)
&&& result == !old(m)@.contains(k)
},
{
m.insert(k)
}
pub spec fn set_contains_borrowed_key<Key, Q: ?Sized>(m: Set<Key>, k: &Q) -> bool;
pub broadcast proof fn axiom_set_contains_deref_key<Q>(m: Set<Q>, k: &Q)
ensures
#[trigger] set_contains_borrowed_key::<Q, Q>(m, k) <==> m.contains(*k),
{
admit();
}
pub broadcast proof fn axiom_set_contains_box<Q>(m: Set<Box<Q>>, k: &Q)
ensures
#[trigger] set_contains_borrowed_key::<Box<Q>, Q>(m, k) <==> m.contains(Box::new(*k)),
{
admit();
}
#[verifier::external_fn_specification]
pub fn ex_hash_set_contains<Key, S, Q>(m: &HashSet<Key, S>, k: &Q) -> (result: bool) where
Key: Borrow<Q> + Hash + Eq,
Q: Hash + Eq + ?Sized,
S: BuildHasher,
ensures
obeys_key_model::<Key>() && builds_valid_hashers::<S>() ==> result
== set_contains_borrowed_key(m@, k),
{
m.contains(k)
}
pub spec fn sets_borrowed_key_to_key<Key, Q: ?Sized>(m: Set<Key>, k: &Q, v: &Key) -> bool;
pub broadcast proof fn axiom_set_deref_key_to_value<Q>(m: Set<Q>, k: &Q, v: &Q)
ensures
#[trigger] sets_borrowed_key_to_key::<Q, Q>(m, k, v) <==> m.contains(*k) && k == v,
{
admit();
}
pub broadcast proof fn axiom_set_box_key_to_value<Q>(m: Set<Box<Q>>, q: &Q, v: &Box<Q>)
ensures
#[trigger] sets_borrowed_key_to_key::<Box<Q>, Q>(m, q, v) <==> (m.contains(*v) && Box::new(
*q,
) == v),
{
admit();
}
#[verifier::external_fn_specification]
pub fn ex_hash_set_get<'a, Key, S, Q>(m: &'a HashSet<Key, S>, k: &Q) -> (result: Option<
&'a Key,
>) where Key: Borrow<Q> + Hash + Eq, Q: Hash + Eq + ?Sized, S: BuildHasher
ensures
obeys_key_model::<Key>() && builds_valid_hashers::<S>() ==> match result {
Some(v) => sets_borrowed_key_to_key(m@, k, v),
None => !set_contains_borrowed_key(m@, k),
},
{
m.get(k)
}
pub spec fn sets_differ_by_borrowed_key<Key, Q: ?Sized>(
old_m: Set<Key>,
new_m: Set<Key>,
k: &Q,
) -> bool;
pub broadcast proof fn axiom_set_deref_key_removed<Q>(old_m: Set<Q>, new_m: Set<Q>, k: &Q)
ensures
#[trigger] sets_differ_by_borrowed_key::<Q, Q>(old_m, new_m, k) <==> new_m == old_m.remove(
*k,
),
{
admit();
}
pub broadcast proof fn axiom_set_box_key_removed<Q>(old_m: Set<Box<Q>>, new_m: Set<Box<Q>>, q: &Q)
ensures
#[trigger] sets_differ_by_borrowed_key::<Box<Q>, Q>(old_m, new_m, q) <==> new_m
== old_m.remove(Box::new(*q)),
{
admit();
}
#[verifier::external_fn_specification]
pub fn ex_hash_set_remove<Key, S, Q>(m: &mut HashSet<Key, S>, k: &Q) -> (result: bool) where
Key: Borrow<Q> + Hash + Eq,
Q: Hash + Eq + ?Sized,
S: BuildHasher,
ensures
obeys_key_model::<Key>() && builds_valid_hashers::<S>() ==> {
&&& sets_differ_by_borrowed_key(old(m)@, m@, k)
&&& result == set_contains_borrowed_key(old(m)@, k)
},
{
m.remove(k)
}
#[verifier::external_fn_specification]
pub fn ex_hash_set_clear<Key, S>(m: &mut HashSet<Key, S>)
ensures
m@ == Set::<Key>::empty(),
{
m.clear()
}
pub broadcast group group_hash_axioms {
axiom_box_key_removed,
axiom_contains_deref_key,
axiom_contains_box,
axiom_deref_key_removed,
axiom_maps_deref_key_to_value,
axiom_maps_box_key_to_value,
axiom_bool_obeys_hash_table_key_model,
axiom_u8_obeys_hash_table_key_model,
axiom_u16_obeys_hash_table_key_model,
axiom_u32_obeys_hash_table_key_model,
axiom_u64_obeys_hash_table_key_model,
axiom_u128_obeys_hash_table_key_model,
axiom_i8_obeys_hash_table_key_model,
axiom_i16_obeys_hash_table_key_model,
axiom_i32_obeys_hash_table_key_model,
axiom_i164_obeys_hash_table_key_model,
axiom_i128_obeys_hash_table_key_model,
axiom_box_bool_obeys_hash_table_key_model,
axiom_box_integer_type_obeys_hash_table_key_model,
axiom_random_state_builds_valid_hashers,
axiom_spec_hash_map_len,
axiom_set_box_key_removed,
axiom_set_contains_deref_key,
axiom_set_contains_box,
axiom_set_deref_key_removed,
axiom_set_deref_key_to_value,
axiom_set_box_key_to_value,
axiom_spec_hash_set_len,
}
}