use core::cell::UnsafeCell;
use core::marker;
use core::{mem, mem::MaybeUninit};
#[allow(unused_imports)]
use super::invariant::*;
#[allow(unused_imports)]
use super::modes::*;
#[allow(unused_imports)]
use super::pervasive::*;
#[allow(unused_imports)]
use super::prelude::*;
#[allow(unused_imports)]
use super::set::*;
#[allow(unused_imports)]
use super::*;
verus! {
broadcast use super::map::group_map_axioms, super::set::group_set_axioms;
#[verifier::external_body]
#[verifier::accept_recursive_types(V)]
pub struct PCell<V> {
ucell: UnsafeCell<MaybeUninit<V>>,
}
#[verifier::external]
unsafe impl<T> Sync for PCell<T> {
}
#[verifier::external]
unsafe impl<T> Send for PCell<T> {
}
#[verifier::external_body]
#[verifier::reject_recursive_types_in_ground_variants(V)]
pub tracked struct PointsTo<V> {
phantom: marker::PhantomData<V>,
no_copy: NoCopy,
}
pub ghost struct PointsToData<V> {
pub pcell: CellId,
pub value: Option<V>,
}
#[doc(hidden)]
#[macro_export]
macro_rules! pcell_opt_internal {
[$pcell:expr => $val:expr] => {
$crate::vstd::cell::PointsToData {
pcell: $pcell,
value: $val,
}
};
}
#[macro_export]
macro_rules! pcell_opt {
[$($tail:tt)*] => {
::builtin_macros::verus_proof_macro_exprs!(
$crate::vstd::cell::pcell_opt_internal!($($tail)*)
)
}
}
pub use pcell_opt_internal;
pub use pcell_opt;
#[verifier::external_body]
pub struct CellId {
id: int,
}
impl<V> PointsTo<V> {
pub spec fn view(self) -> PointsToData<V>;
#[verifier::inline]
pub open spec fn id(&self) -> CellId {
self.view().pcell
}
#[verifier::inline]
pub open spec fn opt_value(&self) -> Option<V> {
self.view().value
}
#[verifier::inline]
pub open spec fn is_init(&self) -> bool {
self.view().value.is_some()
}
#[verifier::inline]
pub open spec fn is_uninit(&self) -> bool {
self.view().value.is_none()
}
#[verifier::inline]
pub open spec fn value(&self) -> V {
self.view().value.unwrap()
}
}
impl<V> PCell<V> {
pub spec fn id(&self) -> CellId;
#[inline(always)]
#[verifier::external_body]
pub const fn empty() -> (pt: (PCell<V>, Tracked<PointsTo<V>>))
ensures
pt.1@@ === pcell_opt![ pt.0.id() => Option::None ],
{
let p = PCell { ucell: UnsafeCell::new(MaybeUninit::uninit()) };
(p, Tracked::assume_new())
}
#[inline(always)]
#[verifier::external_body]
pub const fn new(v: V) -> (pt: (PCell<V>, Tracked<PointsTo<V>>))
ensures
(pt.1@@ === PointsToData { pcell: pt.0.id(), value: Option::Some(v) }),
{
let p = PCell { ucell: UnsafeCell::new(MaybeUninit::new(v)) };
(p, Tracked::assume_new())
}
#[inline(always)]
#[verifier::external_body]
pub fn put(&self, Tracked(perm): Tracked<&mut PointsTo<V>>, v: V)
requires
old(perm)@ === pcell_opt![ self.id() => Option::None ],
ensures
perm@ === pcell_opt![ self.id() => Option::Some(v) ],
opens_invariants none
no_unwind
{
unsafe {
*(self.ucell.get()) = MaybeUninit::new(v);
}
}
#[inline(always)]
#[verifier::external_body]
pub fn take(&self, Tracked(perm): Tracked<&mut PointsTo<V>>) -> (v: V)
requires
self.id() === old(perm)@.pcell,
old(perm)@.value.is_Some(),
ensures
perm@.pcell === old(perm)@.pcell,
perm@.value === Option::None,
v === old(perm)@.value.get_Some_0(),
opens_invariants none
no_unwind
{
unsafe {
let mut m = MaybeUninit::uninit();
mem::swap(&mut m, &mut *self.ucell.get());
m.assume_init()
}
}
#[inline(always)]
#[verifier::external_body]
pub fn replace(&self, Tracked(perm): Tracked<&mut PointsTo<V>>, in_v: V) -> (out_v: V)
requires
self.id() === old(perm)@.pcell,
old(perm)@.value.is_Some(),
ensures
perm@.pcell === old(perm)@.pcell,
perm@.value === Option::Some(in_v),
out_v === old(perm)@.value.get_Some_0(),
opens_invariants none
no_unwind
{
unsafe {
let mut m = MaybeUninit::new(in_v);
mem::swap(&mut m, &mut *self.ucell.get());
m.assume_init()
}
}
#[inline(always)]
#[verifier::external_body]
pub fn borrow<'a>(&'a self, Tracked(perm): Tracked<&'a PointsTo<V>>) -> (v: &'a V)
requires
self.id() === perm@.pcell,
perm@.value.is_Some(),
ensures
*v === perm@.value.get_Some_0(),
opens_invariants none
no_unwind
{
unsafe { (*self.ucell.get()).assume_init_ref() }
}
#[inline(always)]
pub fn into_inner(self, Tracked(perm): Tracked<PointsTo<V>>) -> (v: V)
requires
self.id() === perm@.pcell,
perm@.value.is_Some(),
ensures
v === perm@.value.get_Some_0(),
opens_invariants none
no_unwind
{
let tracked mut perm = perm;
self.take(Tracked(&mut perm))
}
}
impl<V: Copy> PCell<V> {
#[inline(always)]
#[verifier::external_body]
pub fn write(&self, Tracked(perm): Tracked<&mut PointsTo<V>>, in_v: V)
requires
self.id() === old(perm)@.pcell,
old(perm)@.value.is_Some(),
ensures
perm@.pcell === old(perm)@.pcell,
perm@.value === Some(in_v),
opens_invariants none
no_unwind
{
let _out = self.replace(Tracked(&mut *perm), in_v);
}
}
struct InvCellPred {}
impl<T> InvariantPredicate<(Set<T>, PCell<T>), PointsTo<T>> for InvCellPred {
closed spec fn inv(k: (Set<T>, PCell<T>), perm: PointsTo<T>) -> bool {
let (possible_values, pcell) = k;
{
&&& perm@.value.is_Some()
&&& possible_values.contains(perm@.value.get_Some_0())
&&& pcell.id() === perm@.pcell
}
}
}
#[verifier::reject_recursive_types(T)]
pub struct InvCell<T> {
possible_values: Ghost<Set<T>>,
pcell: PCell<T>,
perm_inv: Tracked<LocalInvariant<(Set<T>, PCell<T>), PointsTo<T>, InvCellPred>>,
}
impl<T> InvCell<T> {
#[verifier::type_invariant]
closed spec fn wf(&self) -> bool {
&&& self.perm_inv@.constant() === (self.possible_values@, self.pcell)
}
pub closed spec fn inv(&self, val: T) -> bool {
&&& self.possible_values@.contains(val)
}
pub fn new(val: T, Ghost(f): Ghost<spec_fn(T) -> bool>) -> (cell: Self)
requires
f(val),
ensures
forall|v| f(v) <==> cell.inv(v),
{
let (pcell, Tracked(perm)) = PCell::new(val);
let ghost possible_values = Set::new(f);
let tracked perm_inv = LocalInvariant::new((possible_values, pcell), perm, 0);
InvCell { possible_values: Ghost(possible_values), pcell, perm_inv: Tracked(perm_inv) }
}
}
impl<T> InvCell<T> {
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
}
}
impl<T: Copy> InvCell<T> {
pub fn get(&self) -> (val: T)
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
}
}
}