use super::super::modes::*;
use super::super::prelude::*;
use super::super::set::*;
use super::Loc;
use super::option::*;
use super::pcm;
use super::pcm::PCM;
use super::relations::*;
verus! {
broadcast use super::super::iset::group_iset_lemmas;
#[verifier::accept_recursive_types(RA)]
pub tracked struct Resource<RA: ResourceAlgebra> {
pcm: pcm::Resource<Option<RA>>,
}
pub trait ResourceAlgebra: Sized {
spec fn valid(self) -> bool;
spec fn op(a: Self, b: Self) -> Self;
proof fn associative(a: Self, b: Self, c: Self)
ensures
Self::op(a, Self::op(b, c)) == Self::op(Self::op(a, b), c),
;
proof fn commutative(a: Self, b: Self)
ensures
Self::op(a, b) == Self::op(b, a),
;
proof fn valid_op(a: Self, b: Self)
requires
Self::op(a, b).valid(),
ensures
a.valid(),
;
}
impl<RA: ResourceAlgebra> Resource<RA> {
#[verifier::type_invariant]
spec fn inv(self) -> bool {
self.pcm.value() is Some
}
pub closed spec fn value(self) -> RA {
self.pcm.value()->Some_0
}
pub closed spec fn loc(self) -> Loc {
self.pcm.loc()
}
pub proof fn alloc(value: RA) -> (tracked out: Self)
requires
value.valid(),
ensures
out.value() == value,
{
let tracked pcm = pcm::Resource::alloc(Some(value));
Resource { pcm }
}
pub proof fn join(tracked self, tracked other: Self) -> (tracked out: Self)
requires
self.loc() == other.loc(),
ensures
out.loc() == self.loc(),
out.value() == RA::op(self.value(), other.value()),
{
use_type_invariant(&self);
use_type_invariant(&other);
let tracked pcm = self.pcm.join(other.pcm);
Resource { pcm }
}
pub proof fn split(tracked self, left: RA, right: RA) -> (tracked out: (Self, Self))
requires
self.value() == RA::op(left, right),
ensures
out.0.loc() == self.loc(),
out.1.loc() == self.loc(),
out.0.value() == left,
out.1.value() == right,
{
use_type_invariant(&self);
let tracked (left, right) = self.pcm.split(Some(left), Some(right));
(Resource { pcm: left }, Resource { pcm: right })
}
pub proof fn validate(tracked &self)
ensures
self.value().valid(),
{
use_type_invariant(self);
self.pcm.validate();
}
pub proof fn update_nondeterministic(tracked self, new_values: ISet<RA>) -> (tracked out: Self)
requires
frame_preserving_update_nondeterministic_opt(self.value(), new_values),
ensures
out.loc() == self.loc(),
new_values.contains(out.value()),
{
use_type_invariant(&self);
let opt_new_values = new_values.map(|v| Some(v));
lemma_frame_preserving_update_nondeterministic_opt(self.value(), new_values);
let tracked pcm = self.pcm.update_nondeterministic(opt_new_values);
Resource { pcm }
}
pub proof fn update(tracked self, new_value: RA) -> (tracked out: Self)
requires
frame_preserving_update_opt(self.value(), new_value),
ensures
out.loc() == self.loc(),
out.value() == new_value,
{
let new_values = iset![new_value];
assert(new_values.contains(new_value));
self.update_nondeterministic(new_values)
}
pub proof fn extract(tracked &mut self) -> (tracked other: Self)
ensures
other.loc() == old(self).loc(),
other.value() == old(self).value(),
{
self.validate();
let tracked mut other = Self::alloc(self.value());
tracked_swap(self, &mut other);
other
}
pub proof fn validate_2(tracked &mut self, tracked other: &Resource<RA>)
requires
old(self).loc() == other.loc(),
ensures
*final(self) == *old(self),
RA::op(final(self).value(), other.value()).valid(),
{
use_type_invariant(&*self);
use_type_invariant(other);
self.pcm.validate_2(&other.pcm);
}
pub proof fn update_nondeterministic_with_shared(
tracked self,
tracked other: &Resource<RA>,
new_values: ISet<RA>,
) -> (tracked out: Self)
requires
self.loc() == other.loc(),
frame_preserving_update_nondeterministic_opt(
RA::op(self.value(), other.value()),
set_op(new_values, other.value()),
),
ensures
out.loc() == self.loc(),
new_values.contains(out.value()),
{
use_type_invariant(&self);
use_type_invariant(other);
let a = RA::op(self.value(), other.value());
let bs = set_op(new_values, other.value());
lemma_frame_preserving_update_nondeterministic_opt(a, bs);
lemma_set_op_opt(new_values, other.value());
let new_values_opt = new_values.map(|v| Some(v));
let tracked pcm = self.pcm.update_nondeterministic_with_shared(&other.pcm, new_values_opt);
Resource { pcm }
}
pub proof fn update_with_shared(
tracked self,
tracked other: &Resource<RA>,
new_value: RA,
) -> (tracked out: Self)
requires
self.loc() == other.loc(),
frame_preserving_update_opt(
RA::op(self.value(), other.value()),
RA::op(new_value, other.value()),
),
ensures
out.loc() == self.loc(),
out.value() == new_value,
{
let new_values = iset![new_value];
let so = set_op(new_values, other.value());
assert(new_values.contains(new_value));
assert(so == iset![new_value].map(|n| RA::op(new_value, other.value())));
assert(so.contains(RA::op(new_value, other.value())));
self.update_nondeterministic_with_shared(other, new_values)
}
pub proof fn join_shared<'a>(tracked &'a self, tracked other: &'a Self) -> (tracked out:
&'a Self)
requires
self.loc() == other.loc(),
ensures
out.loc() == self.loc(),
incl(self.value(), out.value()) || self.value() == out.value(),
incl(other.value(), out.value()) || other.value() == out.value(),
{
use_type_invariant(self);
use_type_invariant(other);
let tracked pcm = self.pcm.join_shared(&other.pcm);
assert(pcm.value() is Some);
assert(incl(Some(self.value()), pcm.value()));
assert(incl(Some(other.value()), pcm.value()));
lemma_incl_opt_rev(self.value(), pcm.value()->Some_0);
lemma_incl_opt_rev(other.value(), pcm.value()->Some_0);
Self::mk_ref(pcm)
}
pub proof fn weaken(tracked &self, target: RA) -> (tracked out: &Self)
requires
incl(target, self.value()),
ensures
out.loc() == self.loc(),
out.value() == target,
{
use_type_invariant(self);
lemma_incl_opt(target, self.value());
let tracked pcm = self.pcm.weaken(Some(target));
Self::mk_ref(pcm)
}
pub proof fn duplicate_previous(tracked &self, value: RA) -> (tracked out: Self)
requires
frame_preserving_update_opt(self.value(), RA::op(value, self.value())),
ensures
out.loc() == self.loc(),
out.value() == value,
{
use_type_invariant(self);
let b = RA::op(value, self.value());
lemma_frame_preserving_opt(self.value(), b);
let tracked pcm = self.pcm.duplicate_previous(Some(value));
Resource { pcm }
}
pub proof fn join_shared_to_target<'a>(
tracked &'a self,
tracked other: &'a Self,
target: RA,
) -> (tracked out: &'a Self)
requires
self.loc() == other.loc(),
conjunct_shared(Some(self.value()), Some(other.value()), Some(target)),
ensures
out.loc() == self.loc(),
out.value() == target,
{
let tracked joined = self.join_shared(other);
joined.validate();
assert(Some(joined.value()).valid());
if self.value() == joined.value() {
Some(self.value()).op_unit();
assert(incl(Some(self.value()), Some(joined.value())));
} else {
lemma_incl_opt(self.value(), joined.value());
}
if other.value() == joined.value() {
Some(other.value()).op_unit();
assert(incl(Some(other.value()), Some(joined.value())));
} else {
lemma_incl_opt(other.value(), joined.value());
}
assert(incl(Some(target), Some(joined.value())));
lemma_incl_opt_rev(target, joined.value());
if joined.value() == target {
joined
} else {
joined.weaken(target)
}
}
proof fn mk_ref<'a>(tracked pcm: &'a pcm::Resource<Option<RA>>) -> (tracked res: &'a Self)
requires
pcm.value() is Some,
ensures
res.pcm == pcm,
{
shr_ref_struct_wrap(pcm, &Self { pcm: arbitrary() }, "", "pcm")
}
}
}