vstd/
tokens.rs

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