use super::super::imap::*;
use super::super::imap_lib::*;
use super::super::iset_lib::*;
use super::super::modes::*;
use super::super::prelude::*;
use super::Loc;
use super::algebra::ResourceAlgebra;
#[cfg(verus_keep_ghost)]
use super::incorporate;
use super::pcm::PCM;
use super::pcm::Resource;
#[cfg(verus_keep_ghost)]
use super::split_mut;
verus! {
broadcast use {super::super::group_vstd_default, super::super::imap::group_imap_lemmas};
#[verifier::reject_recursive_types(K)]
#[verifier::ext_equal]
enum AuthCarrier<K, V> {
Auth(IMap<K, V>),
Frac,
Invalid,
}
#[verifier::reject_recursive_types(K)]
#[verifier::ext_equal]
enum FracCarrier<K, V> {
Frac { owning: IMap<K, V>, dup: IMap<K, V> },
Invalid,
}
impl<K, V> AuthCarrier<K, V> {
spec fn valid(self) -> bool {
!(self is Invalid)
}
spec fn map(self) -> IMap<K, V>
recommends
self.valid(),
{
match self {
AuthCarrier::Auth(m) => m,
AuthCarrier::Frac => IMap::empty(),
AuthCarrier::Invalid => IMap::empty(),
}
}
}
impl<K, V> FracCarrier<K, V> {
spec fn valid(self) -> bool {
match self {
FracCarrier::Invalid => false,
FracCarrier::Frac { owning, dup } => owning.dom().disjoint(dup.dom()),
}
}
spec fn owning_map(self) -> IMap<K, V> {
match self {
FracCarrier::Frac { owning, .. } => owning,
FracCarrier::Invalid => IMap::empty(),
}
}
spec fn dup_map(self) -> IMap<K, V> {
match self {
FracCarrier::Frac { dup, .. } => dup,
FracCarrier::Invalid => IMap::empty(),
}
}
}
#[verifier::reject_recursive_types(K)]
#[verifier::ext_equal]
tracked struct MapCarrier<K, V> {
auth: AuthCarrier<K, V>,
frac: FracCarrier<K, V>,
}
impl<K, V> ResourceAlgebra for MapCarrier<K, V> {
closed spec fn valid(self) -> bool {
match (self.auth, self.frac) {
(AuthCarrier::Invalid, _) => false,
(_, FracCarrier::Invalid) => false,
(AuthCarrier::Auth(auth), FracCarrier::Frac { owning, dup }) => {
&&& owning <= auth
&&& dup <= auth
&&& owning.dom().disjoint(dup.dom())
},
(AuthCarrier::Frac, FracCarrier::Frac { owning, dup }) => owning.dom().disjoint(
dup.dom(),
),
}
}
closed spec fn op(a: Self, b: Self) -> Self {
let auth = match (a.auth, b.auth) {
(AuthCarrier::Invalid, _) => AuthCarrier::Invalid,
(_, AuthCarrier::Invalid) => AuthCarrier::Invalid,
(AuthCarrier::Auth(_), AuthCarrier::Auth(_)) => AuthCarrier::Invalid,
(AuthCarrier::Frac, AuthCarrier::Frac) => AuthCarrier::Frac,
(AuthCarrier::Auth(_), _) => a.auth,
(_, AuthCarrier::Auth(_)) => b.auth,
};
let frac = match (a.frac, b.frac) {
(FracCarrier::Invalid, _) => FracCarrier::Invalid,
(_, FracCarrier::Invalid) => FracCarrier::Invalid,
(
FracCarrier::Frac { owning: a_owning, dup: a_dup },
FracCarrier::Frac { owning: b_owning, dup: b_dup },
) => {
let non_overlapping = {
&&& a_owning.dom().disjoint(b_dup.dom())
&&& b_owning.dom().disjoint(a_dup.dom())
&&& a_owning.dom().disjoint(b_owning.dom())
};
let aggreement = a_dup.agrees(b_dup);
if non_overlapping && aggreement {
FracCarrier::Frac {
owning: a_owning.union_prefer_right(b_owning),
dup: a_dup.union_prefer_right(b_dup),
}
} else {
FracCarrier::Invalid
}
},
};
MapCarrier { auth, frac }
}
proof fn valid_op(a: Self, b: Self) {
broadcast use lemma_submap_of_trans;
let ab = MapCarrier::op(a, b);
lemma_submap_of_op_frac(a, b);
if !a.frac.owning_map().dom().disjoint(a.frac.dup_map().dom()) {
lemma_iset_disjoint_iff_empty_intersection(
a.frac.owning_map().dom(),
a.frac.dup_map().dom(),
);
let a_k = choose|k: K|
a.frac.owning_map().dom().intersect(a.frac.dup_map().dom()).contains(k);
assert(ab.frac.owning_map().dom().intersect(ab.frac.dup_map().dom()).contains(a_k)); };
}
proof fn commutative(a: Self, b: Self) {
let ab = Self::op(a, b);
let ba = Self::op(b, a);
assert(ab == ba);
}
proof fn associative(a: Self, b: Self, c: Self) {
let bc = Self::op(b, c);
let ab = Self::op(a, b);
let a_bc = Self::op(a, bc);
let ab_c = Self::op(ab, c);
assert(a_bc == ab_c);
}
}
impl<K, V> PCM for MapCarrier<K, V> {
closed spec fn unit() -> Self {
MapCarrier {
auth: AuthCarrier::Frac,
frac: FracCarrier::Frac { owning: IMap::empty(), dup: IMap::empty() },
}
}
proof fn op_unit(self) {
let x = Self::op(self, Self::unit());
assert(self == x);
}
proof fn unit_valid() {
}
}
proof fn lemma_submap_of_op_frac<K, V>(a: MapCarrier<K, V>, b: MapCarrier<K, V>)
requires
MapCarrier::op(a, b).valid(),
ensures
a.frac.owning_map() <= MapCarrier::op(a, b).frac.owning_map(),
a.frac.dup_map() <= MapCarrier::op(a, b).frac.dup_map(),
b.frac.owning_map() <= MapCarrier::op(a, b).frac.owning_map(),
b.frac.dup_map() <= MapCarrier::op(a, b).frac.dup_map(),
{
let ab = MapCarrier::op(a, b);
assert(ab.frac.owning_map() == a.frac.owning_map().union_prefer_right(b.frac.owning_map()));
assert(ab.frac.dup_map() == a.frac.dup_map().union_prefer_right(b.frac.dup_map()));
assert(a.frac.owning_map().dom().disjoint(b.frac.owning_map().dom()));
}
broadcast proof fn lemma_submap_of_op<K, V>(a: MapCarrier<K, V>, b: MapCarrier<K, V>)
requires
#[trigger] MapCarrier::op(a, b).valid(),
ensures
a.frac.owning_map() <= MapCarrier::op(a, b).frac.owning_map(),
a.frac.dup_map() <= MapCarrier::op(a, b).frac.dup_map(),
a.auth.map() <= MapCarrier::op(a, b).auth.map(),
b.frac.owning_map() <= MapCarrier::op(a, b).frac.owning_map(),
b.frac.dup_map() <= MapCarrier::op(a, b).frac.dup_map(),
b.auth.map() <= MapCarrier::op(a, b).auth.map(),
a.valid(),
b.valid(),
{
lemma_submap_of_op_frac(a, b);
MapCarrier::valid_op(a, b);
MapCarrier::commutative(a, b);
MapCarrier::valid_op(b, a);
let ab = MapCarrier::op(a, b);
assert(ab.auth.map() == a.auth.map().union_prefer_right(b.auth.map()));
}
#[verifier::reject_recursive_types(K)]
pub tracked struct GhostMapAuth<K, V> {
r: Resource<MapCarrier<K, V>>,
}
#[verifier::reject_recursive_types(K)]
pub tracked struct GhostSubmap<K, V> {
r: Resource<MapCarrier<K, V>>,
}
#[verifier::reject_recursive_types(K)]
pub tracked struct GhostPersistentSubmap<K, V> {
r: Resource<MapCarrier<K, V>>,
}
#[verifier::reject_recursive_types(K)]
pub tracked struct GhostPointsTo<K, V> {
submap: GhostSubmap<K, V>,
}
#[verifier::reject_recursive_types(K)]
pub tracked struct GhostPersistentPointsTo<K, V> {
submap: GhostPersistentSubmap<K, V>,
}
impl<K, V> GhostMapAuth<K, V> {
#[verifier::type_invariant]
spec fn inv(self) -> bool {
&&& self.r.value().auth is Auth
&&& self.r.value().frac == FracCarrier::Frac {
owning: IMap::<K, V>::empty(),
dup: IMap::<K, V>::empty(),
}
}
pub closed spec fn id(self) -> Loc {
self.r.loc()
}
pub closed spec fn view(self) -> IMap<K, V> {
self.r.value().auth.map()
}
pub open spec fn dom(self) -> ISet<K> {
self@.dom()
}
pub open spec fn spec_index(self, key: K) -> V
recommends
self.dom().contains(key),
{
self@[key]
}
pub proof fn dummy() -> (tracked result: GhostMapAuth<K, V>) {
let tracked (auth, submap) = GhostMapAuth::<K, V>::new(IMap::empty());
auth
}
pub proof fn take(tracked &mut self) -> (tracked result: GhostMapAuth<K, V>)
ensures
result == *old(self),
{
use_type_invariant(&*self);
let tracked mut r = Self::dummy();
tracked_swap(self, &mut r);
r
}
pub proof fn empty(tracked &self) -> (tracked result: GhostSubmap<K, V>)
ensures
result.id() == self.id(),
result@ == IMap::<K, V>::empty(),
{
use_type_invariant(self);
let tracked r = Resource::<MapCarrier<_, _>>::create_unit(self.r.loc());
GhostSubmap { r }
}
pub proof fn insert_map(tracked &mut self, m: IMap<K, V>) -> (tracked result: GhostSubmap<K, V>)
requires
old(self)@.dom().disjoint(m.dom()),
ensures
final(self).id() == old(self).id(),
final(self)@ == old(self)@.union_prefer_right(m),
result.id() == final(self).id(),
result@ == m,
{
broadcast use lemma_submap_of_trans;
broadcast use lemma_submap_of_op;
let tracked mut mself = Self::dummy();
tracked_swap(self, &mut mself);
use_type_invariant(&mself);
assert(mself.inv());
let tracked mut self_r = mself.r;
let full_carrier = MapCarrier {
auth: AuthCarrier::Auth(self_r.value().auth.map().union_prefer_right(m)),
frac: FracCarrier::Frac { owning: m, dup: IMap::empty() },
};
assert(full_carrier.valid());
let tracked updated_r = self_r.update(full_carrier);
let auth_carrier = MapCarrier {
auth: updated_r.value().auth,
frac: FracCarrier::Frac { owning: IMap::empty(), dup: IMap::empty() },
};
let frac_carrier = MapCarrier { auth: AuthCarrier::Frac, frac: updated_r.value().frac };
assert(updated_r.value() == MapCarrier::op(auth_carrier, frac_carrier));
let tracked (auth_r, frac_r) = updated_r.split(auth_carrier, frac_carrier);
self.r = auth_r;
GhostSubmap { r: frac_r }
}
pub proof fn insert(tracked &mut self, k: K, v: V) -> (tracked result: GhostPointsTo<K, V>)
requires
!old(self)@.contains_key(k),
ensures
final(self).id() == old(self).id(),
final(self)@ == old(self)@.insert(k, v),
result.id() == final(self).id(),
result@ == (k, v),
{
let tracked submap = self.insert_map(imap![k => v]);
GhostPointsTo { submap }
}
pub proof fn delete(tracked &mut self, tracked submap: GhostSubmap<K, V>)
requires
submap.id() == old(self).id(),
ensures
final(self).id() == old(self).id(),
final(self)@ == old(self)@.remove_keys(submap@.dom()),
{
broadcast use lemma_submap_of_trans;
broadcast use lemma_submap_of_op;
use_type_invariant(&*self);
use_type_invariant(&submap);
let tracked mut mself = Self::dummy();
tracked_swap(self, &mut mself);
let tracked mut self_r = mself.r;
self_r = self_r.join(submap.r);
let auth_map = self_r.value().auth.map();
let new_auth_map = auth_map.remove_keys(submap@.dom());
let new_r = MapCarrier {
auth: AuthCarrier::Auth(new_auth_map),
frac: FracCarrier::Frac { owning: IMap::empty(), dup: IMap::empty() },
};
self.r = self_r.update(new_r);
}
pub proof fn delete_points_to(tracked &mut self, tracked p: GhostPointsTo<K, V>)
requires
p.id() == old(self).id(),
ensures
final(self).id() == old(self).id(),
final(self)@ == old(self)@.remove(p.key()),
{
use_type_invariant(&p);
p.lemma_map_view();
self.delete(p.submap);
}
pub proof fn new(m: IMap<K, V>) -> (tracked result: (GhostMapAuth<K, V>, GhostSubmap<K, V>))
ensures
result.0.id() == result.1.id(),
result.0@ == m,
result.1@ == m,
{
let tracked full_r = Resource::alloc(
MapCarrier {
auth: AuthCarrier::Auth(m),
frac: FracCarrier::Frac { owning: m, dup: IMap::empty() },
},
);
let auth_carrier = MapCarrier {
auth: AuthCarrier::Auth(m),
frac: FracCarrier::Frac { owning: IMap::empty(), dup: IMap::empty() },
};
let frac_carrier = MapCarrier {
auth: AuthCarrier::Frac,
frac: FracCarrier::Frac { owning: m, dup: IMap::empty() },
};
assert(full_r.value() == MapCarrier::op(auth_carrier, frac_carrier));
let tracked (auth_r, frac_r) = full_r.split(auth_carrier, frac_carrier);
(GhostMapAuth { r: auth_r }, GhostSubmap { r: frac_r })
}
}
impl<K, V> GhostSubmap<K, V> {
#[verifier::type_invariant]
spec fn inv(self) -> bool {
&&& self.r.value().auth is Frac
&&& self.r.value().frac is Frac
&&& self.r.value().frac.dup_map().is_empty()
}
pub open spec fn is_points_to(self) -> bool {
&&& self@.len() == 1
&&& self.dom().finite()
&&& !self@.is_empty()
}
pub closed spec fn id(self) -> Loc {
self.r.loc()
}
pub closed spec fn view(self) -> IMap<K, V> {
self.r.value().frac.owning_map()
}
pub open spec fn dom(self) -> ISet<K> {
self@.dom()
}
pub open spec fn spec_index(self, key: K) -> V
recommends
self.dom().contains(key),
{
self@[key]
}
pub proof fn dummy() -> (tracked result: GhostSubmap<K, V>) {
let tracked (auth, submap) = GhostMapAuth::<K, V>::new(IMap::empty());
submap
}
pub proof fn empty(tracked &self) -> (tracked result: GhostSubmap<K, V>)
ensures
result.id() == self.id(),
result@ == IMap::<K, V>::empty(),
{
use_type_invariant(self);
let tracked r = Resource::<MapCarrier<_, _>>::create_unit(self.r.loc());
GhostSubmap { r }
}
pub proof fn take(tracked &mut self) -> (tracked result: GhostSubmap<K, V>)
ensures
old(self).id() == final(self).id(),
final(self)@.is_empty(),
result == *old(self),
result.id() == final(self).id(),
{
use_type_invariant(&*self);
let tracked mut r = self.empty();
tracked_swap(self, &mut r);
r
}
pub proof fn agree(tracked self: &GhostSubmap<K, V>, tracked auth: &GhostMapAuth<K, V>)
requires
self.id() == auth.id(),
ensures
self@ <= auth@,
{
broadcast use lemma_submap_of_trans;
use_type_invariant(self);
use_type_invariant(auth);
let tracked joined = self.r.join_shared(&auth.r);
joined.validate();
assert(self.r.value().frac.owning_map() <= joined.value().frac.owning_map());
}
pub proof fn combine(tracked &mut self, tracked other: GhostSubmap<K, V>)
requires
old(self).id() == other.id(),
ensures
final(self).id() == old(self).id(),
final(self)@ == old(self)@.union_prefer_right(other@),
old(self)@.dom().disjoint(other@.dom()),
{
use_type_invariant(&*self);
use_type_invariant(&other);
self.r.validate_2(&other.r);
incorporate(&mut self.r, other.r);
}
pub proof fn combine_points_to(tracked &mut self, tracked other: GhostPointsTo<K, V>)
requires
old(self).id() == other.id(),
ensures
final(self).id() == old(self).id(),
final(self)@ == old(self)@.insert(other.key(), other.value()),
!old(self)@.contains_key(other.key()),
{
use_type_invariant(&*self);
use_type_invariant(&other);
other.lemma_map_view();
self.combine(other.submap);
}
pub proof fn disjoint(tracked &mut self, tracked other: &GhostSubmap<K, V>)
requires
old(self).id() == other.id(),
ensures
final(self).id() == old(self).id(),
final(self)@ == old(self)@,
final(self)@.dom().disjoint(other@.dom()),
{
use_type_invariant(&*self);
use_type_invariant(other);
self.r.validate_2(&other.r);
}
pub proof fn disjoint_persistent(tracked &mut self, tracked other: &GhostPersistentSubmap<K, V>)
requires
old(self).id() == other.id(),
ensures
final(self).id() == old(self).id(),
final(self)@ == old(self)@,
final(self)@.dom().disjoint(other@.dom()),
{
use_type_invariant(&*self);
use_type_invariant(other);
self.r.validate_2(&other.r);
}
pub proof fn disjoint_points_to(tracked &mut self, tracked other: &GhostPointsTo<K, V>)
requires
old(self).id() == other.id(),
ensures
final(self).id() == old(self).id(),
final(self)@ == old(self)@,
!final(self)@.contains_key(other.key()),
{
use_type_invariant(&*self);
use_type_invariant(other);
self.disjoint(&other.submap);
}
pub proof fn disjoint_persistent_points_to(
tracked &mut self,
tracked other: &GhostPersistentPointsTo<K, V>,
)
requires
old(self).id() == other.id(),
ensures
final(self).id() == old(self).id(),
final(self)@ == old(self)@,
!final(self)@.contains_key(other.key()),
{
use_type_invariant(&*self);
use_type_invariant(other);
self.disjoint_persistent(&other.submap);
}
pub proof fn split(tracked &mut self, s: ISet<K>) -> (tracked result: GhostSubmap<K, V>)
requires
s <= old(self)@.dom(),
ensures
final(self).id() == old(self).id(),
result.id() == final(self).id(),
old(self)@ == final(self)@.union_prefer_right(result@),
result@.dom() =~= s,
final(self)@.dom() =~= old(self)@.dom() - s,
{
use_type_invariant(&*self);
let self_carrier = MapCarrier {
auth: AuthCarrier::Frac,
frac: FracCarrier::Frac {
owning: self.r.value().frac.owning_map().remove_keys(s),
dup: self.r.value().frac.dup_map(),
},
};
let res_carrier = MapCarrier {
auth: AuthCarrier::Frac,
frac: FracCarrier::Frac {
owning: self.r.value().frac.owning_map().restrict(s),
dup: self.r.value().frac.dup_map(),
},
};
assert(self.r.value().frac == MapCarrier::op(self_carrier, res_carrier).frac);
let tracked r = split_mut(&mut self.r, self_carrier, res_carrier);
GhostSubmap { r }
}
pub proof fn split_with_olddom(
tracked &mut self,
s: ISet<K>,
olddom: ISet<K>,
) -> (tracked result: GhostSubmap<K, V>)
requires
olddom == old(self)@.dom(),
s <= olddom,
ensures
final(self).id() == old(self).id(),
result.id() == final(self).id(),
old(self)@ == final(self)@.union_prefer_right(result@),
result@.dom() == s,
final(self)@.dom() == olddom - s,
{
let tracked out = self.split(s);
assert(olddom == old(self)@.dom());
assert(self@.dom() == old(self)@.dom() - s);
assert(self@.dom() == olddom - s);
assert(out@.dom() == s);
out
}
pub proof fn split_points_to(tracked &mut self, k: K) -> (tracked result: GhostPointsTo<K, V>)
requires
old(self)@.contains_key(k),
ensures
final(self).id() == old(self).id(),
result.id() == final(self).id(),
old(self)@ == final(self)@.insert(result.key(), result.value()),
result.key() == k,
final(self)@ == old(self)@.remove(k),
{
use_type_invariant(&*self);
let tracked submap = self.split(iset![k]);
GhostPointsTo { submap }
}
pub proof fn update(tracked &mut self, tracked auth: &mut GhostMapAuth<K, V>, m: IMap<K, V>)
requires
m.dom() <= old(self)@.dom(),
old(self).id() == old(auth).id(),
ensures
final(self).id() == old(self).id(),
final(auth).id() == old(auth).id(),
final(self)@ == old(self)@.union_prefer_right(m),
final(auth)@ == old(auth)@.union_prefer_right(m),
{
broadcast use lemma_submap_of_trans;
broadcast use lemma_submap_of_op;
use_type_invariant(&*self);
use_type_invariant(&*auth);
let tracked mut mself = Self::dummy();
tracked_swap(self, &mut mself);
let tracked mut frac_r = mself.r;
let tracked mut mauth = GhostMapAuth::<K, V>::dummy();
tracked_swap(auth, &mut mauth);
let tracked mut auth_r = mauth.r;
frac_r.validate_2(&auth_r);
let tracked mut full_r = frac_r.join(auth_r);
assert(full_r.value().frac.owning_map() == frac_r.value().frac.owning_map());
let auth_carrier = AuthCarrier::Auth(full_r.value().auth.map().union_prefer_right(m));
let frac_carrier = FracCarrier::Frac {
owning: full_r.value().frac.owning_map().union_prefer_right(m),
dup: IMap::empty(),
};
let new_full_carrier = MapCarrier { auth: auth_carrier, frac: frac_carrier };
assert(new_full_carrier.valid());
let tracked r_upd = full_r.update(new_full_carrier);
let new_auth_carrier = MapCarrier {
auth: r_upd.value().auth,
frac: FracCarrier::Frac { owning: IMap::empty(), dup: IMap::empty() },
};
let new_frac_carrier = MapCarrier { auth: AuthCarrier::Frac, frac: r_upd.value().frac };
assert(r_upd.value().frac == MapCarrier::op(new_auth_carrier, new_frac_carrier).frac);
assert(r_upd.value() == MapCarrier::op(new_auth_carrier, new_frac_carrier));
let tracked (new_auth_r, new_frac_r) = r_upd.split(new_auth_carrier, new_frac_carrier);
auth.r = new_auth_r;
self.r = new_frac_r;
}
pub proof fn points_to(tracked self) -> (tracked r: GhostPointsTo<K, V>)
requires
self.is_points_to(),
ensures
self@ == imap![r.key() => r.value()],
self.id() == r.id(),
{
let tracked r = GhostPointsTo { submap: self };
r.lemma_map_view();
r
}
pub proof fn persist(tracked self) -> (tracked r: GhostPersistentSubmap<K, V>)
ensures
self@ == r@,
self.id() == r.id(),
{
broadcast use lemma_submap_of_trans;
broadcast use lemma_submap_of_op;
use_type_invariant(&self);
let tracked mut r = self.r;
let self_carrier = MapCarrier {
auth: AuthCarrier::Frac,
frac: FracCarrier::Frac {
owning: self.r.value().frac.owning_map(),
dup: self.r.value().frac.dup_map(),
},
};
let res_carrier = MapCarrier {
auth: AuthCarrier::Frac,
frac: FracCarrier::Frac {
owning: self.r.value().frac.dup_map(),
dup: self.r.value().frac.owning_map(),
},
};
let tracked r = r.update(res_carrier);
GhostPersistentSubmap { r }
}
}
impl<K, V> GhostPersistentSubmap<K, V> {
#[verifier::type_invariant]
spec fn inv(self) -> bool {
&&& self.r.value().auth is Frac
&&& self.r.value().frac is Frac
&&& self.r.value().frac.owning_map().is_empty()
}
pub open spec fn is_points_to(self) -> bool {
&&& self@.len() == 1
&&& self.dom().finite()
&&& !self@.is_empty()
}
pub closed spec fn id(self) -> Loc {
self.r.loc()
}
pub closed spec fn view(self) -> IMap<K, V> {
self.r.value().frac.dup_map()
}
pub open spec fn dom(self) -> ISet<K> {
self@.dom()
}
pub open spec fn spec_index(self, key: K) -> V
recommends
self.dom().contains(key),
{
self@[key]
}
pub proof fn dummy() -> (tracked result: GhostPersistentSubmap<K, V>) {
let tracked owned = GhostSubmap::<K, V>::dummy();
owned.persist()
}
pub proof fn empty(tracked &self) -> (tracked result: GhostPersistentSubmap<K, V>)
ensures
result.id() == self.id(),
result@ == IMap::<K, V>::empty(),
{
use_type_invariant(self);
let tracked r = Resource::<MapCarrier<_, _>>::create_unit(self.r.loc());
GhostSubmap { r }.persist()
}
pub proof fn duplicate(tracked &self) -> (tracked result: GhostPersistentSubmap<K, V>)
ensures
result.id() == self.id(),
result@ == self@,
{
use_type_invariant(&*self);
assert(MapCarrier::op(self.r.value(), self.r.value()) == self.r.value());
let tracked r = super::lib::duplicate(&self.r);
GhostPersistentSubmap { r }
}
pub proof fn agree(
tracked self: &GhostPersistentSubmap<K, V>,
tracked auth: &GhostMapAuth<K, V>,
)
requires
self.id() == auth.id(),
ensures
self@ <= auth@,
{
broadcast use lemma_submap_of_trans;
use_type_invariant(self);
use_type_invariant(auth);
let tracked joined = self.r.join_shared(&auth.r);
joined.validate();
assert(self.r.value().frac.dup_map() <= joined.value().frac.dup_map());
}
pub proof fn combine(tracked &mut self, tracked other: GhostPersistentSubmap<K, V>)
requires
old(self).id() == other.id(),
ensures
final(self).id() == old(self).id(),
final(self)@ == old(self)@.union_prefer_right(other@),
old(self)@.agrees(other@),
{
use_type_invariant(&*self);
use_type_invariant(&other);
self.r.validate_2(&other.r);
incorporate(&mut self.r, other.r);
}
pub proof fn combine_points_to(tracked &mut self, tracked other: GhostPersistentPointsTo<K, V>)
requires
old(self).id() == other.id(),
ensures
final(self).id() == old(self).id(),
final(self)@ == old(self)@.insert(other.key(), other.value()),
old(self)@.contains_key(other.key()) ==> old(self)@[other.key()] == other.value(),
{
use_type_invariant(&*self);
use_type_invariant(&other);
other.lemma_map_view();
self.combine(other.submap);
}
pub proof fn disjoint(tracked &mut self, tracked other: &GhostSubmap<K, V>)
requires
old(self).id() == other.id(),
ensures
final(self).id() == old(self).id(),
final(self)@ == old(self)@,
final(self)@.dom().disjoint(other@.dom()),
{
use_type_invariant(&*self);
use_type_invariant(other);
self.r.validate_2(&other.r);
}
pub proof fn intersection_agrees(tracked &mut self, tracked other: &GhostPersistentSubmap<K, V>)
requires
old(self).id() == other.id(),
ensures
final(self).id() == old(self).id(),
final(self)@ == old(self)@,
final(self)@.agrees(other@),
{
use_type_invariant(&*self);
use_type_invariant(other);
self.r.validate_2(&other.r);
}
pub proof fn disjoint_points_to(tracked &mut self, tracked other: &GhostPointsTo<K, V>)
requires
old(self).id() == other.id(),
ensures
final(self).id() == old(self).id(),
final(self)@ == old(self)@,
!final(self)@.contains_key(other.key()),
{
use_type_invariant(&*self);
use_type_invariant(other);
self.disjoint(&other.submap);
}
pub proof fn intersection_agrees_points_to(
tracked &mut self,
tracked other: &GhostPersistentPointsTo<K, V>,
)
requires
old(self).id() == other.id(),
ensures
final(self).id() == old(self).id(),
final(self)@ == old(self)@,
final(self)@.contains_key(other.key()) ==> final(self)@[other.key()] == other.value(),
{
use_type_invariant(&*self);
use_type_invariant(other);
self.intersection_agrees(&other.submap);
}
pub proof fn split(tracked &mut self, s: ISet<K>) -> (tracked result: GhostPersistentSubmap<
K,
V,
>)
requires
s <= old(self)@.dom(),
ensures
final(self).id() == old(self).id(),
result.id() == final(self).id(),
old(self)@ == final(self)@.union_prefer_right(result@),
result@.dom() =~= s,
final(self)@.dom() =~= old(self)@.dom() - s,
{
use_type_invariant(&*self);
let tracked mut r = Resource::alloc(MapCarrier::<K, V>::unit());
tracked_swap(&mut self.r, &mut r);
let self_carrier = MapCarrier {
auth: AuthCarrier::Frac,
frac: FracCarrier::Frac {
owning: r.value().frac.owning_map(),
dup: r.value().frac.dup_map().remove_keys(s),
},
};
let res_carrier = MapCarrier {
auth: AuthCarrier::Frac,
frac: FracCarrier::Frac {
owning: r.value().frac.owning_map(),
dup: r.value().frac.dup_map().restrict(s),
},
};
assert(r.value().frac == MapCarrier::op(self_carrier, res_carrier).frac);
let tracked (self_r, res_r) = r.split(self_carrier, res_carrier);
self.r = self_r;
GhostPersistentSubmap { r: res_r }
}
pub proof fn split_points_to(tracked &mut self, k: K) -> (tracked result:
GhostPersistentPointsTo<K, V>)
requires
old(self)@.contains_key(k),
ensures
final(self).id() == old(self).id(),
result.id() == final(self).id(),
old(self)@ == final(self)@.insert(result.key(), result.value()),
result.key() == k,
final(self)@ == old(self)@.remove(k),
{
use_type_invariant(&*self);
let tracked submap = self.split(iset![k]);
GhostPersistentPointsTo { submap }
}
pub proof fn points_to(tracked self) -> (tracked r: GhostPersistentPointsTo<K, V>)
requires
self.is_points_to(),
ensures
self@ == imap![r.key() => r.value()],
self.id() == r.id(),
{
let tracked r = GhostPersistentPointsTo { submap: self };
r.lemma_map_view();
r
}
}
impl<K, V> GhostPointsTo<K, V> {
#[verifier::type_invariant]
spec fn inv(self) -> bool {
self.submap.is_points_to()
}
pub closed spec fn id(self) -> Loc {
self.submap.id()
}
pub open spec fn view(self) -> (K, V) {
(self.key(), self.value())
}
pub closed spec fn key(self) -> K {
self.submap.dom().choose()
}
pub closed spec fn value(self) -> V {
self.submap[self.key()]
}
pub proof fn agree(tracked self: &GhostPointsTo<K, V>, tracked auth: &GhostMapAuth<K, V>)
requires
self.id() == auth.id(),
ensures
auth@.contains_pair(self.key(), self.value()),
{
use_type_invariant(self);
use_type_invariant(auth);
self.lemma_map_view();
self.submap.agree(auth);
assert(self.submap@ <= auth@);
assert(self.submap@.dom().contains(self.key()));
assert(auth@.dom().contains(self.key()));
assert(self.submap@[self.key()] == self.value());
assert(auth@[self.key()] == self.value());
}
pub proof fn combine(tracked self, tracked other: GhostPointsTo<K, V>) -> (tracked r:
GhostSubmap<K, V>)
requires
self.id() == other.id(),
ensures
r.id() == self.id(),
r@ == imap![self.key() => self.value(), other.key() => other.value()],
self.key() != other.key(),
{
use_type_invariant(&self);
use_type_invariant(&other);
let tracked mut submap = self.submap();
submap.combine_points_to(other);
submap
}
pub proof fn disjoint(tracked &mut self, tracked other: &GhostPointsTo<K, V>)
requires
old(self).id() == other.id(),
ensures
final(self).id() == old(self).id(),
final(self)@ == old(self)@,
final(self).key() != other.key(),
{
use_type_invariant(&*self);
use_type_invariant(other);
self.submap.disjoint(&other.submap);
}
pub proof fn disjoint_submap(tracked &mut self, tracked other: &GhostSubmap<K, V>)
requires
old(self).id() == other.id(),
ensures
final(self).id() == old(self).id(),
final(self)@ == old(self)@,
!other.dom().contains(final(self).key()),
{
use_type_invariant(&*self);
use_type_invariant(other);
self.submap.disjoint(other);
}
pub proof fn disjoint_persistent_submap(
tracked &mut self,
tracked other: &GhostPersistentSubmap<K, V>,
)
requires
old(self).id() == other.id(),
ensures
final(self).id() == old(self).id(),
final(self)@ == old(self)@,
!other.dom().contains(final(self).key()),
{
use_type_invariant(&*self);
use_type_invariant(other);
self.submap.disjoint_persistent(other);
}
pub proof fn disjoint_persistent(
tracked &mut self,
tracked other: &GhostPersistentPointsTo<K, V>,
)
requires
old(self).id() == other.id(),
ensures
final(self).id() == old(self).id(),
final(self)@ == old(self)@,
final(self).key() != other.key(),
{
use_type_invariant(&*self);
use_type_invariant(other);
self.submap.disjoint_persistent_points_to(other);
}
pub proof fn update(tracked &mut self, tracked auth: &mut GhostMapAuth<K, V>, v: V)
requires
old(self).id() == old(auth).id(),
ensures
final(self).id() == old(self).id(),
final(auth).id() == old(auth).id(),
final(self).key() == old(self).key(),
final(self)@ == (final(self).key(), v),
final(auth)@ == old(auth)@.union_prefer_right(imap![final(self).key() => v]),
{
broadcast use lemma_submap_of_trans;
broadcast use lemma_submap_of_op;
use_type_invariant(&*self);
use_type_invariant(&*auth);
let ghost old_dom = self.submap.dom();
self.lemma_map_view();
let m = imap![self.key() => v];
assert(self.submap@.union_prefer_right(m) == m);
self.submap.update(auth, m);
}
pub proof fn submap(tracked self) -> (tracked r: GhostSubmap<K, V>)
ensures
r.id() == self.id(),
r@ == imap![self.key() => self.value()],
{
self.lemma_map_view();
self.submap
}
proof fn lemma_map_view(tracked &self)
ensures
self.submap@ == imap![self.key() => self.value()],
{
use_type_invariant(self);
let key = self.key();
let target_dom = iset![key];
assert(self.submap@.dom().len() == 1);
assert(target_dom.len() == 1);
assert(self.submap@.dom().finite());
assert(target_dom.finite());
assert(self.submap@.dom().contains(key));
assert(target_dom.contains(key));
assert(self.submap@.dom().remove(key).len() == 0);
assert(target_dom.remove(key).len() == 0);
assert(self.submap@.dom() =~= target_dom);
assert(self.submap@ == imap![self.key() => self.value()]);
}
pub proof fn lemma_view(self)
ensures
self@ == (self.key(), self.value()),
{
}
pub proof fn persist(tracked self) -> (tracked r: GhostPersistentPointsTo<K, V>)
ensures
self@ == r@,
self.id() == r.id(),
{
use_type_invariant(&self);
self.submap.persist().points_to()
}
}
impl<K, V> GhostPersistentPointsTo<K, V> {
#[verifier::type_invariant]
spec fn inv(self) -> bool {
self.submap.is_points_to()
}
pub closed spec fn id(self) -> Loc {
self.submap.id()
}
pub open spec fn view(self) -> (K, V) {
(self.key(), self.value())
}
pub closed spec fn key(self) -> K {
self.submap.dom().choose()
}
pub closed spec fn value(self) -> V {
self.submap[self.key()]
}
pub proof fn duplicate(tracked &self) -> (tracked result: GhostPersistentPointsTo<K, V>)
ensures
result.id() == self.id(),
result@ == self@,
{
use_type_invariant(&*self);
let tracked submap = self.submap.duplicate();
GhostPersistentPointsTo { submap }
}
pub proof fn agree(
tracked self: &GhostPersistentPointsTo<K, V>,
tracked auth: &GhostMapAuth<K, V>,
)
requires
self.id() == auth.id(),
ensures
auth@.contains_pair(self.key(), self.value()),
{
use_type_invariant(self);
use_type_invariant(auth);
self.lemma_map_view();
self.submap.agree(auth);
assert(self.submap@ <= auth@);
assert(self.submap@.contains_key(self.key()));
}
pub proof fn combine(
tracked self,
tracked other: GhostPersistentPointsTo<K, V>,
) -> (tracked submap: GhostPersistentSubmap<K, V>)
requires
self.id() == other.id(),
ensures
submap.id() == self.id(),
submap@ == imap![self.key() => self.value(), other.key() => other.value()],
self.key() != other.key() ==> submap@.len() == 2,
self.key() == other.key() ==> submap@.len() == 1,
{
use_type_invariant(&self);
use_type_invariant(&other);
let tracked mut submap = self.submap();
submap.combine_points_to(other);
submap
}
pub proof fn disjoint(tracked &mut self, tracked other: &GhostPointsTo<K, V>)
requires
old(self).id() == other.id(),
ensures
final(self).id() == old(self).id(),
final(self)@ == old(self)@,
final(self).key() != other.key(),
{
use_type_invariant(&*self);
use_type_invariant(other);
self.disjoint_submap(&other.submap);
}
pub proof fn disjoint_submap(tracked &mut self, tracked other: &GhostSubmap<K, V>)
requires
old(self).id() == other.id(),
ensures
final(self).id() == old(self).id(),
final(self)@ == old(self)@,
!other@.contains_key(final(self).key()),
{
use_type_invariant(&*self);
use_type_invariant(other);
self.submap.disjoint(&other);
}
pub proof fn intersection_agrees(
tracked &mut self,
tracked other: &GhostPersistentPointsTo<K, V>,
)
requires
old(self).id() == other.id(),
ensures
final(self).id() == old(self).id(),
final(self)@ == old(self)@,
final(self).key() == other.key() ==> final(self).value() == other.value(),
{
use_type_invariant(&*self);
use_type_invariant(other);
self.submap.intersection_agrees_points_to(&other);
}
pub proof fn intersection_agrees_submap(
tracked &mut self,
tracked other: &GhostPersistentSubmap<K, V>,
)
requires
old(self).id() == other.id(),
ensures
final(self).id() == old(self).id(),
final(self)@ == old(self)@,
other@.contains_key(final(self).key()) ==> other@[final(self).key()]
== final(self).value(),
{
use_type_invariant(&*self);
use_type_invariant(other);
self.submap.intersection_agrees(other);
}
pub proof fn submap(tracked self) -> (tracked r: GhostPersistentSubmap<K, V>)
ensures
r.id() == self.id(),
r@ == imap![self.key() => self.value()],
{
self.lemma_map_view();
self.submap
}
proof fn lemma_map_view(tracked &self)
ensures
self.submap@ == imap![self.key() => self.value()],
{
use_type_invariant(self);
let key = self.key();
let target_dom = iset![key];
assert(self.submap@.dom().len() == 1);
assert(target_dom.len() == 1);
assert(self.submap@.dom().finite());
assert(target_dom.finite());
assert(self.submap@.dom().contains(key));
assert(target_dom.contains(key));
assert(self.submap@.dom().remove(key).len() == 0);
assert(target_dom.remove(key).len() == 0);
assert(self.submap@.dom() =~= target_dom);
assert(self.submap@ == imap![self.key() => self.value()]);
}
pub proof fn lemma_view(self)
ensures
self@ == (self.key(), self.value()),
{
}
}
}