pub struct StorageResource<K, V, P> { /* private fields */ }
Expand description

Interface for “storage protocol” ghost state. This is an extension-slash-variant on the more well-known concept of “PCM” ghost state, which we also have an interface for here. The unique feature of a storage protocol is the ability to use guard to manipulate shared references of ghost state.

Storage protocols are based on Leaf: Modularity for Temporary Sharing in Separation Logic.

The reference for the laws and operations we’re embedding here can be found at: https://github.com/secure-foundations/leaf/blob/9d72b880feb6af0a7e752b2b2a43806a0812ad56/src/guarding/protocol_relational.v

The reference version requires two monoids, the “protocol monoid” and the “base monoid”. In this interface, we fix the base monoid to be of the form Map<K, V>. (with composition of overlapping maps being undefined), which has all the necessary properties. Note that there’s no create_unit (it’s not sound to do this for an arbitrary location unless you already know a protocol was initialized at that location).

For applications, I generally advise using the tokenized_state_machine! system, rather than using this interface directly.

Implementations§

source§

impl<K, V, P: Protocol<K, V>> StorageResource<K, V, P>

source

pub open spec fn value(self) -> P

{}
source

pub open spec fn loc(self) -> Loc

{}
source

pub proof fn alloc(p: P, tracked s: Map<K, V>) -> tracked out : Self

requires
P::rel(p, s),
ensures
out.value() == p,
source

pub proof fn join(tracked a: Self, tracked b: Self) -> tracked out : Self

requires
a.loc() == b.loc(),
ensures
out.loc() == a.loc(),
out.value() == P::op(a.value(), b.value()),
source

pub proof fn split(tracked self, a_value: P, b_value: P) -> tracked out : (Self, Self)

requires
self.value() == P::op(a_value, b_value),
ensures
out.0.loc() == self.loc(),
out.1.loc() == self.loc(),
out.0.value() == a_value,
out.1.value() == b_value,
source

pub proof fn validate(tracked a: &Self) -> out : (P, Map<K, V>)

ensures
({
    let (q, t) = out;
    P::rel(P::op(a.value(), q), t)
}),

Since inv isn’t closed under inclusion, validity for an element is defined as the inclusion-closure of invariant, i.e., an element is valid if there exists another element x that, added to it, meets the invariant.

source

pub proof fn exchange(tracked p: Self, tracked s: Map<K, V>, new_p_value: P, new_s_value: Map<K, V> ) -> tracked out : (Self, Map<K, V>)

requires
exchanges(p.value(), s, new_p_value, new_s_value),
ensures
({
    let (new_p, new_s) = out;
    new_p.loc() == p.loc() && new_p.value() == new_p_value && new_s == new_s_value
}),

Most general kind of update, potentially depositing and withdrawing

source

pub proof fn deposit(tracked self, tracked base: Map<K, V>, new_value: P) -> tracked out : Self

requires
deposits(self.value(), base, new_value),
ensures
out.loc() == self.loc(),
out.value() == new_value,
source

pub proof fn withdraw(tracked self, new_value: P, new_base: Map<K, V>) -> tracked out : (Self, Map<K, V>)

requires
withdraws(self.value(), new_value, new_base),
ensures
out.0.loc() == self.loc(),
out.0.value() == new_value,
out.1 == new_base,
source

pub proof fn update(tracked self, new_value: P) -> tracked out : Self

requires
updates(self.value(), new_value),
ensures
out.loc() == self.loc(),
out.value() == new_value,

“Normal” update, no depositing or withdrawing

source

pub proof fn exchange_nondeterministic(tracked p: Self, tracked s: Map<K, V>, new_values: Set<(P, Map<K, V>)> ) -> tracked out : (Self, Map<K, V>)

requires
exchanges_nondeterministic(p.value(), s, new_values),
ensures
({
    let (new_p, new_s) = out;
    new_p.loc() == p.loc() && new_values.contains((new_p.value(), new_s))
}),
source

pub proof fn guard(tracked p: &Self, s_value: Map<K, V>) -> tracked s : &Map<K, V>

requires
guards(p.value(), s_value),
ensures
s == s_value,
source

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()),
incl(other.value(), out.value()),
source

pub proof fn weaken<'a>(tracked &'a self, target: P) -> tracked out : &'a Self

requires
incl(target, self.value()),
ensures
out.loc() == self.loc(),
out.value() == target,
source

pub proof fn validate_with_shared(tracked p: &mut Self, tracked x: &Self) -> res : (P, Map<K, V>)

requires
old(p).loc() == x.loc(),
ensures
*p == *old(p),
({
    let (q, t) = res;
    { P::rel(P::op(P::op(p.value(), x.value()), q), t) }
}),
source

pub proof fn exchange_with_shared(tracked p: Self, tracked x: &Self, tracked s: Map<K, V>, new_p_value: P, new_s_value: Map<K, V> ) -> tracked out : (Self, Map<K, V>)

requires
p.loc() == x.loc(),
exchanges(P::op(p.value(), x.value()), s, P::op(new_p_value, x.value()), new_s_value),
ensures
out.0.loc() == p.loc(),
out.0.value() == new_p_value,
out.1 == new_s_value,
source

pub proof fn exchange_nondeterministic_with_shared(tracked p: Self, tracked x: &Self, tracked s: Map<K, V>, new_values: Set<(P, Map<K, V>)> ) -> tracked out : (Self, Map<K, V>)

requires
p.loc() == x.loc(),
exchanges_nondeterministic(P::op(p.value(), x.value()), s, set_op(new_values, x.value())),
ensures
({
    let (new_p, new_s) = out;
    new_p.loc() == p.loc() && new_values.contains((new_p.value(), new_s))
}),

Most general kind of update, potentially depositing and withdrawing

Auto Trait Implementations§

§

impl<K, V, P> RefUnwindSafe for StorageResource<K, V, P>

§

impl<K, V, P> Send for StorageResource<K, V, P>
where K: Send + Sync, P: Send, V: Send + Sync,

§

impl<K, V, P> Sync for StorageResource<K, V, P>
where K: Send + Sync, P: Sync, V: Send + Sync,

§

impl<K, V, P> Unpin for StorageResource<K, V, P>
where K: Unpin, P: Unpin, V: Unpin,

§

impl<K, V, P> UnwindSafe for StorageResource<K, V, P>
where K: UnwindSafe, P: UnwindSafe, V: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.