Skip to main content

vstd/
tokens.rs

1use super::multiset::*;
2use super::prelude::*;
3use core::marker::PhantomData;
4
5use verus as verus_;
6verus_! {
7
8// Note that the tokenized_state_machine! macro creates trusted implementations
9// of all these traits. Therefore all the proof functions in here are trusted.
10// The 'collection types', (MapToken, SetToken, MultisetToken) are verified, but the properties
11// of these types is still assumed by the Verus macro, so they're still mostly trusted.
12
13#[verusfmt::skip]
14broadcast use {
15    super::set_lib::group_set_lib_default,
16    super::set::group_set_axioms,
17    super::map::group_map_axioms };
18
19/// Unique identifier for every VerusSync instance.
20/// Every "Token" and "Instance" object has an `InstanceId`. These ID values must agree
21/// to perform any token operation.
22pub type InstanceId = super::resource::Loc;
23
24/// Interface for VerusSync tokens created for a field marked with the
25/// `variable`, `option` or `persistent_option` strategies.
26///
27/// | VerusSync Strategy  | Field type  | Token trait            |
28/// |---------------------|-------------|------------------------|
29/// | `variable`          | `V`         | [`UniqueValueToken<V>`](`UniqueValueToken`)        |
30/// | `option`            | `Option<V>` | [`UniqueValueToken<V>`](`UniqueValueToken`)        |
31/// | `persistent_option` | `Option<V>` | `ValueToken<V> + Copy` |
32///
33/// For the cases where the tokens are not `Copy`, then token is necessarily _unique_
34/// per-instance; the sub-trait, [`UniqueValueToken<V>`](`UniqueValueToken`), provides
35/// an additional lemma to prove uniqueness.
36
37pub trait ValueToken<Value> : Sized {
38    spec fn instance_id(&self) -> InstanceId;
39    spec fn value(&self) -> Value;
40
41    /// All tokens (for the same instance) must agree on the value.
42    proof fn agree(tracked &self, tracked other: &Self)
43        requires self.instance_id() == other.instance_id(),
44        ensures self.value() == other.value();
45
46    /// Return an arbitrary token. It's not possible to do anything interesting
47    /// with this token because it doesn't have a specified instance.
48    proof fn arbitrary() -> (tracked s: Self);
49}
50
51/// Interface for VerusSync tokens created for a field marked with the `variable` or `option` strategies.
52///
53/// See the super-trait [`ValueToken`](ValueToken) for more information.
54pub trait UniqueValueToken<Value> : ValueToken<Value> {
55    /// The token for a given instance must be unique; in other words, if we have two
56    /// tokens, they must be for distinct instances.
57    /// Though the first argument is mutable, the value is not really mutated;
58    /// this is only used to ensure unique ownership of the argument.
59    proof fn unique(tracked &mut self, tracked other: &Self)
60        ensures
61            self.instance_id() != other.instance_id(),
62            *self == *old(self);
63}
64
65/// Interface for VerusSync tokens created for a field marked with the
66/// `map` or `persistent_map` strategies.
67///
68/// | VerusSync Strategy  | Field type  | Token trait            |
69/// |---------------------|-------------|------------------------|
70/// | `map`               | `Map<K, V>` | [`UniqueKeyValueToken<K, V>`](`UniqueKeyValueToken`) |
71/// | `persistent_map`    | `Map<K, V>` | `KeyValueToken<V> + Copy` |
72///
73/// For the cases where the tokens are not `Copy`, then token is necessarily _unique_
74/// per-instance, per-key; the sub-trait, [`UniqueKeyValueToken<V>`](`UniqueKeyValueToken`), provides
75/// an additional lemma to prove uniqueness.
76///
77/// Each token represents a _single_ key-value pair.
78/// To work with a collection of `KeyValueToken`s, use [`MapToken`].
79
80pub trait KeyValueToken<Key, Value> : Sized {
81    spec fn instance_id(&self) -> InstanceId;
82    spec fn key(&self) -> Key;
83    spec fn value(&self) -> Value;
84
85    /// All tokens, for the same instance and _key_, must agree on the value.
86    proof fn agree(tracked &self, tracked other: &Self)
87        requires self.instance_id() == other.instance_id(),
88                 self.key() == other.key(),
89        ensures self.value() == other.value();
90
91    /// Return an arbitrary token. It's not possible to do anything interesting
92    /// with this token because it doesn't have a specified instance.
93    proof fn arbitrary() -> (tracked s: Self);
94}
95
96/// Interface for VerusSync tokens created for a field marked with the `map` strategy.
97///
98/// See the super-trait [`KeyValueToken`](KeyValueToken) for more information.
99pub trait UniqueKeyValueToken<Key, Value> : KeyValueToken<Key, Value> {
100    /// The token for a given instance and key must be unique; in other words, if we have two
101    /// tokens, they must be for distinct instances or keys.
102    /// Though the first argument is mutable, the value is not really mutated;
103    /// this is only used to ensure unique ownership of the argument.
104    proof fn unique(tracked &mut self, tracked other: &Self)
105        ensures
106            self.instance_id() != other.instance_id() || self.key() != other.key(),
107            *self == *old(self);
108}
109
110/// Interface for VerusSync tokens created for a field marked with the `count` strategy.
111///
112/// | VerusSync Strategy  | Field type  | Token trait            |
113/// |---------------------|-------------|------------------------|
114/// | `count`             | `nat`       | `CountToken`           |
115///
116/// These tokens are "fungible" in the sense that they can be combined and split, numbers
117/// combining additively.
118///
119/// (For the `persistent_count` strategy, see [`MonotonicCountToken`].)
120pub trait CountToken : Sized {
121    spec fn instance_id(&self) -> InstanceId;
122    spec fn count(&self) -> nat;
123
124    proof fn join(tracked &mut self, tracked other: Self)
125        requires
126            old(self).instance_id() == other.instance_id(),
127        ensures
128            self.instance_id() == old(self).instance_id(),
129            self.count() == old(self).count() + other.count();
130
131    proof fn split(tracked &mut self, count: nat) -> (tracked token: Self)
132        requires
133            count <= old(self).count()
134        ensures
135            self.instance_id() == old(self).instance_id(),
136            self.count() == old(self).count() - count,
137            token.instance_id() == old(self).instance_id(),
138            token.count() == count;
139
140    proof fn weaken_shared(tracked &self, count: nat) -> (tracked s: &Self)
141        requires count <= self.count(),
142        ensures s.instance_id() == self.instance_id(),
143            s.count() == count;
144
145    /// Return an arbitrary token. It's not possible to do anything interesting
146    /// with this token because it doesn't have a specified instance.
147    proof fn arbitrary() -> (tracked s: Self);
148}
149
150/// Interface for VerusSync tokens created for a field marked with the `persistent_count` strategy.
151///
152/// | VerusSync Strategy  | Field type  | Token trait                   |
153/// |---------------------|-------------|-------------------------------|
154/// | `persistent_count`  | `nat`       | `MonotonicCountToken + Copy`  |
155///
156/// A token represents a "lower bound" on the field value, which increases monotonically.
157
158pub trait MonotonicCountToken : Sized {
159    spec fn instance_id(&self) -> InstanceId;
160    spec fn count(&self) -> nat;
161
162    proof fn weaken(tracked &self, count: nat) -> (tracked s: Self)
163        requires count <= self.count(),
164        ensures s.instance_id() == self.instance_id(),
165            s.count() == count;
166
167    /// Return an arbitrary token. It's not possible to do anything interesting
168    /// with this token because it doesn't have a specified instance.
169    proof fn arbitrary() -> (tracked s: Self);
170}
171
172/// Interface for VerusSync tokens created for a field marked with the
173/// `set`, `persistent_set` or `multiset` strategies.
174///
175/// | VerusSync Strategy  | Field type  | Token trait            |
176/// |---------------------|-------------|------------------------|
177/// | `set`               | `Set<V>`    | [`UniqueElementToken<V>`](`UniqueElementToken`) |
178/// | `persistent_set`    | `Set<V>`    | `ElementToken<V> + Copy` |
179/// | `multiset`          | `Multiset<V>` | `ElementToken<V>`      |
180///
181/// Each token represents a single element of the set or multiset.
182///
183///  * For the `set` strategy, the token for any given element is unique.
184///  * For the `persistent_set` strategy, the token for any given element is not unique, but is `Copy`.
185///  * For the `multiset` strategy, the tokens are neither unique nor `Copy`, as the specific
186///    multiplicity of each element must be exact.
187///
188/// To work with a collection of `ElementToken`s, use [`SetToken`] or [`MultisetToken`].
189
190pub trait ElementToken<Element> : Sized {
191    spec fn instance_id(&self) -> InstanceId;
192    spec fn element(&self) -> Element;
193
194    /// Return an arbitrary token. It's not possible to do anything interesting
195    /// with this token because it doesn't have a specified instance.
196    proof fn arbitrary() -> (tracked s: Self);
197}
198
199/// Interface for VerusSync tokens created for a field marked with the `set` strategy.
200///
201/// See the super-trait [`ElementToken`](ElementToken) for more information.
202pub trait UniqueElementToken<Element> : ElementToken<Element> {
203    /// The token for a given instance and element must be unique; in other words, if we have two
204    /// tokens, they must be for distinct instances or elements.
205    /// Though the first argument is mutable, the value is not really mutated;
206    /// this is only used to ensure unique ownership of the argument.
207    proof fn unique(tracked &mut self, tracked other: &Self)
208        ensures
209            self.instance_id() == other.instance_id() ==> self.element() != other.element(),
210            *self == *old(self);
211}
212
213/// Interface for VerusSync tokens created for a field marked with the `bool` or
214/// `persistent_bool` strategy.
215///
216/// | VerusSync Strategy  | Field type  | Token trait            |
217/// |---------------------|-------------|------------------------|
218/// | `bool`              | `bool`      | [`UniqueSimpleToken<V>`](`UniqueSimpleToken`) |
219/// | `persistent_bool`   | `bool`      | `SimpleToken<V> + Copy` |
220///
221/// The token contains no additional data; its presence indicates that the boolean field
222/// is `true`.
223pub trait SimpleToken : Sized {
224    spec fn instance_id(&self) -> InstanceId;
225
226    /// Return an arbitrary token. It's not possible to do anything interesting
227    /// with this token because it doesn't have a specified instance.
228    proof fn arbitrary() -> (tracked s: Self);
229}
230
231/// Interface for VerusSync tokens created for a field marked with the `bool` strategy.
232///
233/// See the super-trait [`SimpleToken`](SimpleToken) for more information.
234pub trait UniqueSimpleToken : SimpleToken {
235    /// The token for a given instance must be unique; in other words, if we have two
236    /// tokens, they must be for distinct instances.
237    /// Though the first argument is mutable, the value is not really mutated;
238    /// this is only used to ensure unique ownership of the argument.
239    proof fn unique(tracked &mut self, tracked other: &Self)
240        ensures
241            self.instance_id() != other.instance_id(),
242            *self == *old(self);
243}
244
245#[verifier::reject_recursive_types(Key)]
246pub tracked struct MapToken<Key, Value, Token>
247    where Token: KeyValueToken<Key, Value>
248{
249    ghost _v: PhantomData<Value>,
250    ghost inst: InstanceId,
251    tracked m: Map<Key, Token>,
252}
253
254impl<Key, Value, Token> MapToken<Key, Value, Token>
255    where Token: KeyValueToken<Key, Value>
256{
257    #[verifier::type_invariant]
258    spec fn wf(self) -> bool {
259        forall |k| #[trigger] self.m.dom().contains(k) ==> self.m[k].key() == k
260            && self.m[k].instance_id() == self.inst
261    }
262
263    pub closed spec fn instance_id(self) -> InstanceId {
264        self.inst
265    }
266
267    pub closed spec fn map(self) -> Map<Key, Value> {
268        Map::new(
269            |k: Key| self.m.dom().contains(k),
270            |k: Key| self.m[k].value(),
271        )
272    }
273
274    #[verifier::inline]
275    pub open spec fn dom(self) -> Set<Key> {
276        self.map().dom()
277    }
278
279    #[verifier::inline]
280    pub open spec fn spec_index(self, k: Key) -> Value {
281        self.map()[k]
282    }
283
284    #[verifier::inline]
285    pub open spec fn index(self, k: Key) -> Value {
286        self.map()[k]
287    }
288
289    pub proof fn empty(instance_id: InstanceId) -> (tracked s: Self)
290        ensures
291            s.instance_id() == instance_id,
292            s.map() === Map::empty(),
293    {
294        let tracked s = Self { inst: instance_id, m: Map::tracked_empty(), _v: PhantomData };
295        assert(s.map() =~= Map::empty());
296        return s;
297    }
298
299    pub proof fn insert(tracked &mut self, tracked token: Token)
300        requires
301            old(self).instance_id() == token.instance_id(),
302        ensures
303            self.instance_id() == old(self).instance_id(),
304            self.map() == old(self).map().insert(token.key(), token.value()),
305    {
306        use_type_invariant(&*self);
307        self.m.tracked_insert(token.key(), token);
308        assert(self.map() =~= old(self).map().insert(token.key(), token.value()));
309    }
310
311    pub proof fn remove(tracked &mut self, key: Key) -> (tracked token: Token)
312        requires
313            old(self).map().dom().contains(key)
314        ensures
315            self.instance_id() == old(self).instance_id(),
316            self.map() == old(self).map().remove(key),
317            token.instance_id() == self.instance_id(),
318            token.key() == key,
319            token.value() == old(self).map()[key]
320    {
321        use_type_invariant(&*self);
322        let tracked t = self.m.tracked_remove(key);
323        assert(self.map() =~= old(self).map().remove(key));
324        t
325    }
326
327    pub proof fn into_map(tracked self) -> (tracked map: Map<Key, Token>)
328        ensures
329            map.dom() == self.map().dom(),
330            forall |key|
331                #![trigger(map.dom().contains(key))]
332                #![trigger(map.index(key))]
333              map.dom().contains(key)
334                ==> map[key].instance_id() == self.instance_id()
335                 && map[key].key() == key
336                 && map[key].value() == self.map()[key]
337    {
338        use_type_invariant(&self);
339        let tracked MapToken { inst, m, _v } = self;
340        assert(m.dom() =~= self.map().dom());
341        return m;
342    }
343
344    pub proof fn from_map(instance_id: InstanceId, tracked map: Map<Key, Token>) -> (tracked s: Self)
345        requires
346            forall |key| #[trigger] map.dom().contains(key) ==> map[key].instance_id() == instance_id,
347            forall |key| #[trigger] map.dom().contains(key) ==> map[key].key() == key,
348        ensures
349            s.instance_id() == instance_id,
350            s.map().dom() == map.dom(),
351            forall |key| #[trigger] map.dom().contains(key)
352                ==> s.map()[key] == map[key].value()
353    {
354        let tracked s = MapToken { inst: instance_id, m: map, _v: PhantomData };
355        assert(map.dom() == s.map().dom());
356        s
357    }
358}
359
360#[verifier::reject_recursive_types(Element)]
361pub tracked struct SetToken<Element, Token>
362    where Token: ElementToken<Element>
363{
364    ghost inst: InstanceId,
365    tracked m: Map<Element, Token>,
366}
367
368impl<Element, Token> SetToken<Element, Token>
369    where Token: ElementToken<Element>
370{
371    #[verifier::type_invariant]
372    spec fn wf(self) -> bool {
373        forall |k| #[trigger] self.m.dom().contains(k) ==> self.m[k].element() == k
374            && self.m[k].instance_id() == self.inst
375    }
376
377    pub closed spec fn instance_id(self) -> InstanceId {
378        self.inst
379    }
380
381    pub closed spec fn set(self) -> Set<Element> {
382        Set::new(
383            |e: Element| self.m.dom().contains(e),
384        )
385    }
386
387    #[verifier::inline]
388    pub open spec fn contains(self, element: Element) -> bool {
389        self.set().contains(element)
390    }
391
392    pub proof fn empty(instance_id: InstanceId) -> (tracked s: Self)
393        ensures
394            s.instance_id() == instance_id,
395            s.set() === Set::empty(),
396    {
397        let tracked s = Self { inst: instance_id, m: Map::tracked_empty() };
398        assert(s.set() =~= Set::empty());
399        return s;
400    }
401
402    pub proof fn insert(tracked &mut self, tracked token: Token)
403        requires
404            old(self).instance_id() == token.instance_id(),
405        ensures
406            self.instance_id() == old(self).instance_id(),
407            self.set() == old(self).set().insert(token.element()),
408    {
409        use_type_invariant(&*self);
410        self.m.tracked_insert(token.element(), token);
411        assert(self.set() =~= old(self).set().insert(token.element()));
412    }
413
414    pub proof fn remove(tracked &mut self, element: Element) -> (tracked token: Token)
415        requires
416            old(self).set().contains(element)
417        ensures
418            self.instance_id() == old(self).instance_id(),
419            self.set() == old(self).set().remove(element),
420            token.instance_id() == self.instance_id(),
421            token.element() == element,
422    {
423        use_type_invariant(&*self);
424        let tracked t = self.m.tracked_remove(element);
425        assert(self.set() =~= old(self).set().remove(element));
426        t
427    }
428
429    pub proof fn into_map(tracked self) -> (tracked map: Map<Element, Token>)
430        ensures
431            map.dom() == self.set(),
432            forall |key|
433                #![trigger(map.dom().contains(key))]
434                #![trigger(map.index(key))]
435                map.dom().contains(key)
436                    ==> map[key].instance_id() == self.instance_id()
437                     && map[key].element() == key
438    {
439        use_type_invariant(&self);
440        let tracked SetToken { inst, m } = self;
441        assert(m.dom() =~= self.set());
442        return m;
443    }
444
445    pub proof fn from_map(instance_id: InstanceId, tracked map: Map<Element, Token>) -> (tracked s: Self)
446        requires
447            forall |key| #[trigger] map.dom().contains(key) ==> map[key].instance_id() == instance_id,
448            forall |key| #[trigger] map.dom().contains(key) ==> map[key].element() == key,
449        ensures
450            s.instance_id() == instance_id,
451            s.set() == map.dom(),
452    {
453        let tracked s = SetToken { inst: instance_id, m: map };
454        assert(s.set() =~= map.dom());
455        s
456    }
457}
458
459pub tracked struct MultisetToken<Element, Token>
460    where Token: ElementToken<Element>
461{
462    ghost _v: PhantomData<Element>,
463    ghost inst: InstanceId,
464    tracked m: Map<int, Token>,
465}
466
467spec fn map_values<K, V>(m: Map<K, V>) -> Multiset<V> {
468    m.dom().fold(Multiset::empty(), |multiset: Multiset<V>, k: K| multiset.insert(m[k]))
469}
470
471proof fn map_values_insert_not_in<K, V>(m: Map<K, V>, k: K, v: V)
472    requires
473        !m.dom().contains(k)
474    ensures
475        map_values(m.insert(k, v)) == map_values(m).insert(v)
476{
477    assume(false);
478}
479
480proof fn map_values_remove<K, V>(m: Map<K, V>, k: K)
481    requires
482        m.dom().contains(k)
483    ensures
484        map_values(m.remove(k)) == map_values(m).remove(m[k])
485{
486    assume(false);
487}
488
489//proof fn map_values_empty_empty<K, V>()
490//    ensures map_values(Map::<K, V>::empty()) == Multiset::empty(),
491
492spec fn fresh(m: Set<int>) -> int {
493    m.find_unique_maximal(|a: int, b: int| a <= b) + 1
494}
495
496proof fn fresh_is_fresh(s: Set<int>)
497    requires s.finite(),
498    ensures !s.contains(fresh(s))
499{
500    assume(false);
501}
502
503proof fn get_key_for_value<K, V>(m: Map<K, V>, value: V) -> (k: K)
504    requires map_values(m).contains(value), m.dom().finite(),
505    ensures m.dom().contains(k), m[k] == value,
506{
507    assume(false);
508    arbitrary()
509}
510
511impl<Element, Token> MultisetToken<Element, Token>
512    where Token: ElementToken<Element>
513{
514    #[verifier::type_invariant]
515    spec fn wf(self) -> bool {
516        self.m.dom().finite() &&
517        forall |k| #[trigger] self.m.dom().contains(k)
518            ==> self.m[k].instance_id() == self.inst
519    }
520
521    pub closed spec fn instance_id(self) -> InstanceId {
522        self.inst
523    }
524
525    spec fn map_elems(m: Map<int, Token>) -> Map<int, Element> {
526        m.map_values(|t: Token| t.element())
527    }
528
529    pub closed spec fn multiset(self) -> Multiset<Element> {
530        map_values(Self::map_elems(self.m))
531    }
532
533    pub proof fn empty(instance_id: InstanceId) -> (tracked s: Self)
534        ensures
535            s.instance_id() == instance_id,
536            s.multiset() === Multiset::empty(),
537    {
538        let tracked s = Self { inst: instance_id, m: Map::tracked_empty(), _v: PhantomData, };
539        broadcast use super::set::fold::lemma_fold_empty;
540        assert(Self::map_elems(Map::empty()) =~= Map::empty());
541        return s;
542    }
543
544    pub proof fn insert(tracked &mut self, tracked token: Token)
545        requires
546            old(self).instance_id() == token.instance_id(),
547        ensures
548            self.instance_id() == old(self).instance_id(),
549            self.multiset() == old(self).multiset().insert(token.element()),
550    {
551        use_type_invariant(&*self);
552        let f = fresh(self.m.dom());
553        fresh_is_fresh(self.m.dom());
554        map_values_insert_not_in(
555            Self::map_elems(self.m),
556            f,
557            token.element());
558        self.m.tracked_insert(f, token);
559        assert(Self::map_elems(self.m) =~= Self::map_elems(old(self).m).insert(
560            f, token.element()));
561        assert(self.multiset() =~= old(self).multiset().insert(token.element()));
562    }
563
564    pub proof fn remove(tracked &mut self, element: Element) -> (tracked token: Token)
565        requires
566            old(self).multiset().contains(element)
567        ensures
568            self.instance_id() == old(self).instance_id(),
569            self.multiset() == old(self).multiset().remove(element),
570            token.instance_id() == self.instance_id(),
571            token.element() == element,
572    {
573        use_type_invariant(&*self);
574        assert(Self::map_elems(self.m).dom() =~= self.m.dom());
575        let k = get_key_for_value(Self::map_elems(self.m), element);
576        map_values_remove(Self::map_elems(self.m), k);
577        let tracked t = self.m.tracked_remove(k);
578        assert(Self::map_elems(self.m) =~= Self::map_elems(old(self).m).remove(k));
579        assert(self.multiset() =~= old(self).multiset().remove(element));
580        t
581    }
582}
583
584pub open spec fn option_value_eq_option_token<Value, Token: ValueToken<Value>>(
585    opt_value: Option<Value>,
586    opt_token: Option<Token>,
587    instance_id: InstanceId,
588) -> bool {
589    match opt_value {
590        Some(val) => opt_token.is_some()
591            && opt_token.unwrap().value() == val
592            && opt_token.unwrap().instance_id() == instance_id,
593        None => opt_token.is_none(),
594    }
595}
596
597pub open spec fn option_value_le_option_token<Value, Token: ValueToken<Value>>(
598    opt_value: Option<Value>,
599    opt_token: Option<Token>,
600    instance_id: InstanceId,
601) -> bool {
602    match opt_value {
603        Some(val) => opt_token.is_some()
604            && opt_token.unwrap().value() == val
605            && opt_token.unwrap().instance_id() == instance_id,
606        None => true,
607    }
608}
609
610pub open spec fn bool_value_eq_option_token<Token: SimpleToken>(
611    b: bool,
612    opt_token: Option<Token>,
613    instance_id: InstanceId,
614) -> bool {
615    if b {
616        opt_token.is_some() && opt_token.unwrap().instance_id() == instance_id
617    } else {
618        opt_token.is_none()
619    }
620}
621
622pub open spec fn bool_value_le_option_token<Token: SimpleToken>(
623    b: bool,
624    opt_token: Option<Token>,
625    instance_id: InstanceId,
626) -> bool {
627    b ==>
628        opt_token.is_some() && opt_token.unwrap().instance_id() == instance_id
629}
630
631}