#![allow(unused_imports)]
use super::super::invariant::*;
use super::super::predicate::*;
use super::super::prelude::*;
use super::CellId;
use super::pcell::*;
use verus as verus_;
verus_! {
#[verifier::accept_recursive_types(T)]
pub struct InvCell<T, Pred> {
pcell: PCell<T>,
perm_inv: Tracked<LocalInvariant<(Pred, CellId), PointsTo<T>, InvCellPred>>,
}
struct InvCellPred { }
impl<T, Pred: Predicate<T>> InvariantPredicate<(Pred, CellId), PointsTo<T>> for InvCellPred {
closed spec fn inv(k: (Pred, CellId), perm: PointsTo<T>) -> bool {
let (pred, pcell_id) = k;
{
&&& pred.predicate(*perm.value())
&&& pcell_id === perm.id()
}
}
}
impl<T, Pred> InvCell<T, Pred> {
#[verifier::type_invariant]
closed spec fn wf(&self) -> bool {
&&& self.perm_inv@.constant().1 === self.pcell.id()
}
pub closed spec fn predicate(&self) -> Pred {
self.perm_inv@.constant().0
}
}
impl<T, Pred: Predicate<T>> InvCell<T, Pred> {
pub open spec fn inv(&self, val: T) -> bool {
self.predicate().predicate(val)
}
pub fn new(val: T, Ghost(pred): Ghost<Pred>) -> (cell: Self)
requires
pred.predicate(val),
ensures
cell.predicate() == pred,
{
let (pcell, Tracked(perm)) = PCell::new(val);
let tracked perm_inv = LocalInvariant::new((pred, pcell.id()), perm, 0);
InvCell { pcell, perm_inv: Tracked(perm_inv) }
}
pub fn set(&self, val: T)
requires
self.inv(val),
{
let _ = self.replace(val);
}
pub fn replace(&self, val: T) -> (old_val: T)
requires
self.inv(val),
ensures
self.inv(old_val),
{
proof {
use_type_invariant(self);
}
let r;
open_local_invariant!(self.perm_inv.borrow() => perm => {
r = self.pcell.replace(Tracked(&mut perm), val);
});
r
}
pub fn get(&self) -> (val: T)
where T: Copy
ensures
self.inv(val),
{
proof {
use_type_invariant(self);
}
let r;
open_local_invariant!(self.perm_inv.borrow() => perm => {
r = *self.pcell.borrow(Tracked(&perm));
});
r
}
#[allow(non_shorthand_field_patterns)]
pub fn into_inner(self) -> (val: T)
ensures
self.inv(val),
{
proof {
use_type_invariant(&self);
}
let InvCell { pcell, perm_inv: Tracked(perm_inv) } = self;
let tracked perm = perm_inv.into_inner();
pcell.into_inner(Tracked(perm))
}
}
}