use vstd::prelude::*;
pub use crate::value_eq::ValueEq as RegistryKey;
verus! {
pub open spec fn has_key<K, V>(entries: Seq<(K, V)>, n: int, k: K) -> bool {
exists|i: int| 0 <= i < n && entries[i].0 == k
}
pub proof fn lemma_has_key_extend<K, V>(entries: Seq<(K, V)>, n: int, k: K)
requires 0 <= n < entries.len(),
ensures
has_key(entries, n + 1, k) == (has_key(entries, n, k) || entries[n].0 == k),
{
if has_key(entries, n + 1, k) {
let i = choose|i: int| 0 <= i < n + 1 && entries[i].0 == k;
assert(i < n || i == n);
}
if has_key(entries, n, k) {
let i = choose|i: int| 0 <= i < n && entries[i].0 == k;
assert(0 <= i < n + 1 && entries[i].0 == k);
}
if entries[n].0 == k {
assert(0 <= n < n + 1 && entries[n].0 == k);
}
}
pub proof fn lemma_push_has_key<K, V>(entries: Seq<(K, V)>, a: K, b: V, kk: K)
ensures
has_key(entries.push((a, b)), entries.len() as int + 1, kk)
== (has_key(entries, entries.len() as int, kk) || kk == a),
{
let pushed = entries.push((a, b));
if has_key(entries, entries.len() as int, kk) {
let i = choose|i: int| 0 <= i < entries.len() && entries[i].0 == kk;
assert(pushed[i] == entries[i]);
}
if kk == a {
assert(pushed[entries.len() as int].0 == kk);
}
if has_key(pushed, entries.len() as int + 1, kk) {
let i = choose|i: int| 0 <= i < entries.len() as int + 1 && pushed[i].0 == kk;
if i < entries.len() {
assert(entries[i] == pushed[i]);
}
}
}
pub open spec fn has_pair<K, V>(entries: Seq<(K, V)>, n: int, k: K, v: V) -> bool {
exists|i: int| 0 <= i < n && entries[i].0 == k && entries[i].1 == v
}
pub open spec fn unique_mapping_entries<K, V>(entries: Seq<(K, V)>) -> bool {
forall|i: int, j: int|
(0 <= i < entries.len() && 0 <= j < entries.len() && i != j)
==> #[trigger] entries[i].0 != #[trigger] entries[j].0
}
pub open spec fn unique_keys<K>(keys: Seq<K>) -> bool {
forall|i: int, j: int|
(0 <= i < keys.len() && 0 <= j < keys.len() && i != j)
==> #[trigger] keys[i] != #[trigger] keys[j]
}
pub open spec fn contains_key_value<K>(keys: Seq<K>, key: K) -> bool {
exists|i: int| 0 <= i < keys.len() && #[trigger] keys[i] == key
}
pub proof fn contains_key_value_push<K>(keys: Seq<K>, added: K, key: K)
ensures
contains_key_value(keys.push(added), key)
== (contains_key_value(keys, key) || key == added),
{
let pushed = keys.push(added);
if contains_key_value(keys, key) {
let index = choose|index: int| 0 <= index < keys.len() && keys[index] == key;
assert(pushed[index] == keys[index]);
}
if key == added {
assert(pushed[keys.len() as int] == key);
}
if contains_key_value(pushed, key) {
let index = choose|index: int| 0 <= index < pushed.len() && pushed[index] == key;
if index < keys.len() {
assert(keys[index] == pushed[index]);
} else {
assert(index == keys.len());
}
}
}
pub proof fn contains_key_value_remove_unique<K>(keys: Seq<K>, removed: int, key: K)
requires
unique_keys(keys),
0 <= removed < keys.len(),
ensures
contains_key_value(keys.remove(removed), key)
== (contains_key_value(keys, key) && key != keys[removed]),
{
keys.remove_ensures(removed);
let reduced = keys.remove(removed);
if contains_key_value(reduced, key) {
let index = choose|index: int| 0 <= index < reduced.len() && reduced[index] == key;
let old_index = if index < removed { index } else { index + 1 };
assert(0 <= old_index < keys.len());
assert(old_index != removed);
assert(reduced[index] == keys[old_index]);
assert(contains_key_value(keys, key));
if key == keys[removed] {
assert(keys[old_index] == keys[removed]);
assert(false);
}
}
if contains_key_value(keys, key) && key != keys[removed] {
let old_index = choose|index: int| 0 <= index < keys.len() && keys[index] == key;
assert(old_index != removed);
let index = if old_index < removed { old_index } else { old_index - 1 };
assert(0 <= index < reduced.len());
assert(reduced[index] == keys[old_index]);
}
}
pub proof fn has_pair_remove_unique<K, V>(
entries: Seq<(K, V)>,
removed: int,
key: K,
value: V,
)
requires
unique_mapping_entries(entries),
0 <= removed < entries.len(),
ensures
has_pair(entries.remove(removed), (entries.len() - 1) as int, key, value)
== (has_pair(entries, entries.len() as int, key, value)
&& key != entries[removed].0),
{
entries.remove_ensures(removed);
let reduced = entries.remove(removed);
if has_pair(reduced, reduced.len() as int, key, value) {
let index = choose|index: int|
0 <= index < reduced.len()
&& reduced[index].0 == key
&& reduced[index].1 == value;
let old_index = if index < removed { index } else { index + 1 };
assert(0 <= old_index < entries.len());
assert(old_index != removed);
assert(reduced[index] == entries[old_index]);
assert(has_pair(entries, entries.len() as int, key, value));
if key == entries[removed].0 {
assert(entries[old_index].0 == entries[removed].0);
assert(false);
}
}
if has_pair(entries, entries.len() as int, key, value) && key != entries[removed].0 {
let old_index = choose|index: int|
0 <= index < entries.len()
&& entries[index].0 == key
&& entries[index].1 == value;
assert(old_index != removed);
let index = if old_index < removed { old_index } else { old_index - 1 };
assert(0 <= index < reduced.len());
assert(reduced[index] == entries[old_index]);
}
}
pub proof fn lemma_has_pair_extend<K, V>(entries: Seq<(K, V)>, n: int, k: K, v: V)
requires 0 <= n < entries.len(),
ensures
has_pair(entries, n + 1, k, v)
== (has_pair(entries, n, k, v) || (entries[n].0 == k && entries[n].1 == v)),
{
if has_pair(entries, n + 1, k, v) {
let i = choose|i: int| 0 <= i < n + 1 && entries[i].0 == k && entries[i].1 == v;
assert(i < n || i == n);
}
if has_pair(entries, n, k, v) {
let i = choose|i: int| 0 <= i < n && entries[i].0 == k && entries[i].1 == v;
assert(0 <= i < n + 1 && entries[i].0 == k && entries[i].1 == v);
}
if entries[n].0 == k && entries[n].1 == v {
assert(0 <= n < n + 1 && entries[n].0 == k && entries[n].1 == v);
}
}
pub proof fn lemma_push_has_pair<K, V>(entries: Seq<(K, V)>, a: K, b: V, kk: K, vv: V)
ensures
has_pair(entries.push((a, b)), entries.len() as int + 1, kk, vv)
== (has_pair(entries, entries.len() as int, kk, vv) || (kk == a && vv == b)),
{
let pushed = entries.push((a, b));
if has_pair(entries, entries.len() as int, kk, vv) {
let i = choose|i: int|
0 <= i < entries.len() && entries[i].0 == kk && entries[i].1 == vv;
assert(pushed[i] == entries[i]);
}
if kk == a && vv == b {
assert(pushed[entries.len() as int].0 == kk && pushed[entries.len() as int].1 == vv);
}
if has_pair(pushed, entries.len() as int + 1, kk, vv) {
let i = choose|i: int|
0 <= i < entries.len() as int + 1 && pushed[i].0 == kk && pushed[i].1 == vv;
if i < entries.len() {
assert(entries[i] == pushed[i]);
}
}
}
pub open spec fn without_key_to<K, V>(entries: Seq<(K, V)>, key: K, n: int)
-> Seq<(K, V)>
decreases n,
{
if n <= 0 || n > entries.len() {
Seq::empty()
} else {
let prefix = without_key_to(entries, key, n - 1);
if entries[n - 1].0 == key {
prefix
} else {
prefix.push(entries[n - 1])
}
}
}
pub open spec fn without_key_sequence<K, V>(entries: Seq<(K, V)>, key: K)
-> Seq<(K, V)>
{
without_key_to(entries, key, entries.len() as int)
}
pub struct ResourceRegistry<K, V> {
pub entries: Vec<(K, V)>,
}
impl<K: RegistryKey + Copy, V: Copy> ResourceRegistry<K, V> {
pub open spec fn unique_mapping(&self) -> bool {
unique_mapping_entries(self.entries@)
}
pub open spec fn contains_key(&self, k: K) -> bool {
has_key(self.entries@, self.entries@.len() as int, k)
}
pub open spec fn maps_to(&self, k: K, v: V) -> bool {
has_pair(self.entries@, self.entries@.len() as int, k, v)
}
pub proof fn unique_value(&self, k: K, left: V, right: V)
requires
self.unique_mapping(),
self.maps_to(k, left),
self.maps_to(k, right),
ensures left == right,
{
let left_index = choose|index: int|
0 <= index < self.entries@.len()
&& self.entries@[index].0 == k
&& self.entries@[index].1 == left;
let right_index = choose|index: int|
0 <= index < self.entries@.len()
&& self.entries@[index].0 == k
&& self.entries@[index].1 == right;
if left_index != right_index {
assert(self.entries@[left_index].0 != self.entries@[right_index].0);
}
assert(left_index == right_index);
}
pub proof fn maps_to_implies_contains(&self, k: K, v: V)
requires self.maps_to(k, v),
ensures self.contains_key(k),
{
let index = choose|index: int|
0 <= index < self.entries@.len()
&& self.entries@[index].0 == k
&& self.entries@[index].1 == v;
assert(0 <= index < self.entries@.len() && self.entries@[index].0 == k);
}
pub proof fn contains_has_value(&self, k: K)
requires self.contains_key(k),
ensures exists|v: V| self.maps_to(k, v),
{
let index = choose|index: int|
0 <= index < self.entries@.len() && self.entries@[index].0 == k;
let value = self.entries@[index].1;
assert(self.maps_to(k, value));
}
pub fn new() -> (r: ResourceRegistry<K, V>)
ensures
r.entries@.len() == 0,
r.unique_mapping(),
{
ResourceRegistry { entries: Vec::new() }
}
fn without_key(entries: &Vec<(K, V)>, k: K) -> (out: Vec<(K, V)>)
requires
forall|i: int, j: int|
(0 <= i < entries@.len() && 0 <= j < entries@.len() && i != j)
==> #[trigger] entries@[i].0 != #[trigger] entries@[j].0,
ensures
out@ == without_key_sequence(entries@, k),
forall|i: int| 0 <= i < out@.len() ==> out@[i].0 != k,
forall|i: int, j: int|
(0 <= i < out@.len() && 0 <= j < out@.len() && i != j)
==> #[trigger] out@[i].0 != #[trigger] out@[j].0,
forall|kk: K|
kk != k ==>
(#[trigger] has_key(out@, out@.len() as int, kk)
== has_key(entries@, entries@.len() as int, kk)),
forall|kk: K, vv: V|
kk != k ==>
(#[trigger] has_pair(out@, out@.len() as int, kk, vv)
== has_pair(entries@, entries@.len() as int, kk, vv)),
!has_key(entries@, entries@.len() as int, k) ==> out@ == entries@,
{
let mut out: Vec<(K, V)> = Vec::new();
let mut i: usize = 0;
while i < entries.len()
invariant
i <= entries.len(),
out@ == without_key_to(entries@, k, i as int),
forall|a: int, b: int|
(0 <= a < entries@.len() && 0 <= b < entries@.len() && a != b)
==> #[trigger] entries@[a].0 != #[trigger] entries@[b].0,
forall|a: int| 0 <= a < out@.len() ==> out@[a].0 != k,
forall|a: int, b: int|
(0 <= a < out@.len() && 0 <= b < out@.len() && a != b)
==> #[trigger] out@[a].0 != #[trigger] out@[b].0,
forall|kk: K|
kk != k ==>
(#[trigger] has_key(out@, out@.len() as int, kk)
== has_key(entries@, i as int, kk)),
forall|kk: K, vv: V|
kk != k ==>
(#[trigger] has_pair(out@, out@.len() as int, kk, vv)
== has_pair(entries@, i as int, kk, vv)),
!has_key(entries@, entries@.len() as int, k)
==> out@ == entries@.subrange(0, i as int),
decreases entries.len() - i,
{
let e = entries[i];
let ghost ob = out@;
if !e.0.value_eq(&k) {
assert(!has_key(entries@, i as int, e.0)) by {
if has_key(entries@, i as int, e.0) {
let t = choose|t: int| 0 <= t < i as int && entries@[t].0 == e.0;
assert(entries@[t].0 != entries@[i as int].0); }
}
assert(!has_key(ob, ob.len() as int, e.0)); out.push(e);
assert forall|a: int, b: int|
(0 <= a < out@.len() && 0 <= b < out@.len() && a != b)
implies #[trigger] out@[a].0 != #[trigger] out@[b].0 by {
if a < ob.len() && b < ob.len() {
} else if b == ob.len() && a < ob.len() {
assert(out@[a] == ob[a]);
assert(has_key(ob, ob.len() as int, ob[a].0));
} else if a == ob.len() && b < ob.len() {
assert(out@[b] == ob[b]);
assert(has_key(ob, ob.len() as int, ob[b].0));
}
}
}
assert(out@ == without_key_to(entries@, k, i as int + 1));
assert forall|kk: K| kk != k implies
(#[trigger] has_key(out@, out@.len() as int, kk)
== has_key(entries@, (i + 1) as int, kk)) by {
lemma_has_key_extend(entries@, i as int, kk);
if e.0 != k {
lemma_push_has_key(ob, e.0, e.1, kk);
}
}
assert forall|kk: K, vv: V| kk != k implies
(#[trigger] has_pair(out@, out@.len() as int, kk, vv)
== has_pair(entries@, (i + 1) as int, kk, vv)) by {
lemma_has_pair_extend(entries@, i as int, kk, vv);
if e.0 != k {
lemma_push_has_pair(ob, e.0, e.1, kk, vv);
}
}
proof {
if !has_key(entries@, entries@.len() as int, k) {
assert(e.0 != k) by {
if e.0 == k {
assert(has_key(entries@, entries@.len() as int, k));
}
}
assert(out@ == entries@.subrange(0, (i + 1) as int));
}
}
i = i + 1;
}
proof {
if !has_key(entries@, entries@.len() as int, k) {
assert(entries@.subrange(0, entries@.len() as int) =~= entries@);
}
}
out
}
pub fn lookup(&self, k: K) -> (res: Option<V>)
requires self.unique_mapping(),
ensures
res matches Option::Some(v) ==> self.maps_to(k, v),
res is None ==> !self.contains_key(k),
{
let len = self.entries.len();
let mut i: usize = 0;
while i < len
invariant
i <= len,
len == self.entries.len(),
forall|t: int| 0 <= t < i ==> self.entries@[t].0 != k,
decreases len - i,
{
if self.entries[i].0.value_eq(&k) {
assert(self.entries@[i as int].0 == k && self.entries@[i as int].1 == self.entries@[i as int].1);
return Some(self.entries[i].1);
}
i = i + 1;
}
assert(!self.contains_key(k));
None
}
pub fn register(&mut self, k: K, v: V)
requires old(self).unique_mapping(),
ensures
final(self).unique_mapping(),
final(self).maps_to(k, v),
final(self).entries@
== without_key_sequence(old(self).entries@, k).push((k, v)),
forall|kk: K|
kk != k ==>
(#[trigger] final(self).contains_key(kk) == old(self).contains_key(kk)),
forall|kk: K, vv: V|
kk != k ==>
(#[trigger] final(self).maps_to(kk, vv) == old(self).maps_to(kk, vv)),
!old(self).contains_key(k)
==> final(self).entries@ == old(self).entries@.push((k, v)),
{
let ghost old_entries = self.entries@;
let ghost was_absent = !self.contains_key(k);
let filtered = Self::without_key(&self.entries, k);
let ghost fb = filtered@;
proof {
if was_absent {
assert(fb == old_entries);
}
}
self.entries = filtered;
self.entries.push((k, v));
assert forall|i: int, j: int|
(0 <= i < self.entries@.len() && 0 <= j < self.entries@.len() && i != j)
implies #[trigger] self.entries@[i].0 != #[trigger] self.entries@[j].0 by {
if i < fb.len() && j < fb.len() {
} else if j == fb.len() && i < fb.len() {
assert(self.entries@[i] == fb[i]);
assert(fb[i].0 != k); } else if i == fb.len() && j < fb.len() {
assert(self.entries@[j] == fb[j]);
assert(fb[j].0 != k);
}
}
assert(self.maps_to(k, v)) by {
assert(self.entries@[fb.len() as int].0 == k && self.entries@[fb.len() as int].1 == v);
}
assert forall|kk: K| kk != k implies
(#[trigger] self.contains_key(kk) == old(self).contains_key(kk)) by {
lemma_push_has_key(fb, k, v, kk);
}
assert forall|kk: K, vv: V| kk != k implies
(#[trigger] self.maps_to(kk, vv) == old(self).maps_to(kk, vv)) by {
lemma_push_has_pair(fb, k, v, kk, vv);
}
}
pub fn deregister_at(&mut self, index: usize) -> (removed: (K, V))
requires
old(self).unique_mapping(),
index < old(self).entries.len(),
ensures
removed == old(self).entries@[index as int],
final(self).entries@ == old(self).entries@.remove(index as int),
final(self).entries@.len() + 1 == old(self).entries@.len(),
final(self).unique_mapping(),
forall|key: K, value: V|
#[trigger] final(self).maps_to(key, value)
== (old(self).maps_to(key, value) && key != removed.0),
{
let ghost before = self.entries@;
let removed = self.entries.remove(index);
assert(self.entries@ == before.remove(index as int));
assert(self.unique_mapping()) by {
assert forall|left: int, right: int|
0 <= left < self.entries@.len()
&& 0 <= right < self.entries@.len()
&& left != right
implies #[trigger] self.entries@[left].0 != #[trigger] self.entries@[right].0 by {
before.remove_ensures(index as int);
let old_left = if left < index { left } else { left + 1 };
let old_right = if right < index { right } else { right + 1 };
assert(0 <= old_left < before.len());
assert(0 <= old_right < before.len());
assert(old_left != old_right);
assert(self.entries@[left] == before[old_left]);
assert(self.entries@[right] == before[old_right]);
}
}
assert forall|key: K, value: V|
#[trigger] self.maps_to(key, value)
== (old(self).maps_to(key, value) && key != removed.0) by {
has_pair_remove_unique(before, index as int, key, value);
}
removed
}
pub fn deregister(&mut self, k: K)
requires
old(self).unique_mapping(),
old(self).contains_key(k),
ensures
final(self).unique_mapping(),
!final(self).contains_key(k),
final(self).entries@ == without_key_sequence(old(self).entries@, k),
forall|kk: K|
kk != k ==>
(#[trigger] final(self).contains_key(kk) == old(self).contains_key(kk)),
forall|kk: K, vv: V|
kk != k ==>
(#[trigger] final(self).maps_to(kk, vv) == old(self).maps_to(kk, vv)),
{
let filtered = Self::without_key(&self.entries, k);
let ghost fb = filtered@;
self.entries = filtered;
assert forall|kk: K, vv: V| kk != k implies
(#[trigger] self.maps_to(kk, vv) == old(self).maps_to(kk, vv)) by {
assert(has_pair(fb, fb.len() as int, kk, vv)
== has_pair(old(self).entries@, old(self).entries@.len() as int, kk, vv));
}
assert(!self.contains_key(k)) by {
if self.contains_key(k) {
let i = choose|i: int| 0 <= i < self.entries@.len() && self.entries@[i].0 == k;
assert(self.entries@[i].0 != k);
}
}
}
}
}