Skip to main content

vstd/resource/impls/
map.rs

1//! Maps that support ownership of keys
2//!
3//! - [`GhostMapAuth<K, V>`] represents authoritative ownership of the entire map;
4//! - [`GhostSubmap<K, V>`] represents client ownership of a submap;
5//! - [`GhostPersistentSubmap<K, V>`] represents duplicable client knowledge of a submap which will never change;
6//! - [`GhostPointsTo<K, V>`] represents client ownership of a single key-value pair.
7//! - [`GhostPersistentPointsTo<K, V>`] represents duplicable client knowledge of a single key-value pair which will never change.
8//!
9//! Updating the authoritative `GhostMapAuth<K, V>` requires a `GhostSubmap<K, V>` containing the keys being updated.
10//!
11//! `GhostSubmap<K, V>`s can be combined or split.
12//! Whenever a `GhostSubmap<K, V>` can be used, we can instead use a `GhostPointsTo<K, V>` (but not vice-versa).
13//!
14//! `GhostPersistentSubmap<K, V>`s can be combined or split.
15//! Whenever a `GhostPersistentSubmap<K, V>` can be used, we can instead use a `GhostPersistentPointsTo<K, V>` (but not vice-versa).
16//!
17//! ### Example
18//!
19//! ```
20//! fn example_use() {
21//!     let tracked (mut auth, mut sub) = GhostMapAuth::new(map![1u8 => 1u64, 2u8 => 2u64, 3u8 => 3u64]);
22//!
23//!     // Allocate some more keys in the auth map, receiving a new submap.
24//!     let tracked sub2 = auth.insert_map(map![4u8 => 4u64, 5u8 => 5u64]);
25//!     proof { sub.combine(sub2); }
26//!
27//!     // Allocate a single key in the auth map, receiving a points to
28//!     let tracked pt1 = auth.insert(6u8, 6u64);
29//!     proof { sub.combine_points_to(pt1); }
30//!
31//!     // Delete some keys in the auth map, by returning corresponding submap.
32//!     let tracked sub3 = sub.split(set![3u8, 4u8]);
33//!     proof { auth.delete(sub3); }
34//!
35//!     // Split the submap into a points to and a submap
36//!     let tracked pt2 = sub.split_points_to(1u8);
37//!     let tracked sub4 = sub.split(set![5u8, 6u8]);
38//!
39//!     // In general, we might need to call agree() to establish the fact that
40//!     // a points-to/submap has the same values as the auth map.  Here, Verus
41//!     // doesn't need agree because it can track where both the auth, points-to
42//!     // and submap came from.
43//!     proof { sub.agree(&auth); }
44//!     proof { pt2.agree(&auth); }
45//!     proof { sub4.agree(&auth); }
46//!
47//!     assert(pt2.key() == 1u8);
48//!     assert(pt2.value() == auth[1u8]);
49//!     assert(sub4[5u8] == auth[5u8]);
50//!     assert(sub4[6u8] == auth[6u8]);
51//!     assert(sub[2u8] == auth[2u8]);
52//!
53//!     // Update keys using ownership of submaps.
54//!     proof { sub.update(&mut auth, map![2u8 => 22u64]); }
55//!     proof { pt2.update(&mut auth, 11u64); }
56//!     proof { sub4.update(&mut auth, map![5u8 => 55u64, 6u8 => 66u8]); }
57//!     assert(auth[1u8] == 11u64);
58//!     assert(auth[2u8] == 22u64);
59//!     assert(auth[5u8] == 55u64);
60//!     assert(auth[6u8] == 66u64);
61//!
62//!     // Persist and duplicate the submap
63//!     let mut psub1 = sub.persist();
64//!     assert(psub1[2u8] == 22u64);
65//!     let psub2 = psub1.duplicate();
66//!     assert(psub2[2u8] == 22u64);
67//!
68//!     // Not shown in this simple example is the main use case of this resource:
69//!     // maintaining an invariant between GhostMapAuth<K, V> and some exec-mode
70//!     // shared state with a map view (e.g., HashMap<K, V>), which states that
71//!     // the Map<K, V> view of GhostMapAuth<K, V> is the same as the view of the
72//!     // HashMap<K, V>, and then handing out a GhostSubmap<K, V> to different
73//!     // clients that might need to operate on different keys in this map.
74//! }
75//! ```
76use super::super::super::map::*;
77use super::super::super::map_lib::*;
78use super::super::super::modes::*;
79use super::super::super::prelude::*;
80use super::super::super::set_lib::*;
81use super::super::Loc;
82use super::super::algebra::ResourceAlgebra;
83#[cfg(verus_keep_ghost)]
84use super::super::incorporate;
85use super::super::pcm::PCM;
86use super::super::pcm::Resource;
87#[cfg(verus_keep_ghost)]
88use super::super::split_mut;
89
90verus! {
91
92broadcast use {super::super::super::group_vstd_default, super::super::super::map::group_map_lemmas};
93
94#[verifier::reject_recursive_types(K)]
95#[verifier::ext_equal]
96enum AuthCarrier<K, V> {
97    Auth(Map<K, V>),
98    Frac,
99    Invalid,
100}
101
102#[verifier::reject_recursive_types(K)]
103#[verifier::ext_equal]
104enum FracCarrier<K, V> {
105    Frac { owning: Map<K, V>, dup: Map<K, V> },
106    Invalid,
107}
108
109impl<K, V> AuthCarrier<K, V> {
110    spec fn valid(self) -> bool {
111        !(self is Invalid)
112    }
113
114    spec fn map(self) -> Map<K, V>
115        recommends
116            self.valid(),
117    {
118        match self {
119            AuthCarrier::Auth(m) => m,
120            AuthCarrier::Frac => Map::empty(),
121            AuthCarrier::Invalid => Map::empty(),
122        }
123    }
124}
125
126impl<K, V> FracCarrier<K, V> {
127    spec fn valid(self) -> bool {
128        match self {
129            FracCarrier::Invalid => false,
130            FracCarrier::Frac { owning, dup } => owning.dom().disjoint(dup.dom()),
131        }
132    }
133
134    spec fn owning_map(self) -> Map<K, V> {
135        match self {
136            FracCarrier::Frac { owning, .. } => owning,
137            FracCarrier::Invalid => Map::empty(),
138        }
139    }
140
141    spec fn dup_map(self) -> Map<K, V> {
142        match self {
143            FracCarrier::Frac { dup, .. } => dup,
144            FracCarrier::Invalid => Map::empty(),
145        }
146    }
147}
148
149#[verifier::reject_recursive_types(K)]
150#[verifier::ext_equal]
151// This struct represents the underlying resource algebra for GhostMaps
152tracked struct MapCarrier<K, V> {
153    auth: AuthCarrier<K, V>,
154    frac: FracCarrier<K, V>,
155}
156
157impl<K, V> ResourceAlgebra for MapCarrier<K, V> {
158    closed spec fn valid(self) -> bool {
159        match (self.auth, self.frac) {
160            (AuthCarrier::Invalid, _) => false,
161            (_, FracCarrier::Invalid) => false,
162            (AuthCarrier::Auth(auth), FracCarrier::Frac { owning, dup }) => {
163                &&& owning <= auth
164                &&& dup <= auth
165                &&& owning.dom().disjoint(dup.dom())
166            },
167            (AuthCarrier::Frac, FracCarrier::Frac { owning, dup }) => owning.dom().disjoint(
168                dup.dom(),
169            ),
170        }
171    }
172
173    closed spec fn op(a: Self, b: Self) -> Self {
174        let auth = match (a.auth, b.auth) {
175            // Invalid carriers absorb
176            (AuthCarrier::Invalid, _) => AuthCarrier::Invalid,
177            (_, AuthCarrier::Invalid) => AuthCarrier::Invalid,
178            // There can't be two auths
179            (AuthCarrier::Auth(_), AuthCarrier::Auth(_)) => AuthCarrier::Invalid,
180            // Fracs remain the same
181            (AuthCarrier::Frac, AuthCarrier::Frac) => AuthCarrier::Frac,
182            // Whoever is the auth has precedence
183            (AuthCarrier::Auth(_), _) => a.auth,
184            (_, AuthCarrier::Auth(_)) => b.auth,
185        };
186
187        let frac = match (a.frac, b.frac) {
188            // Invalid fracs remain invalid
189            (FracCarrier::Invalid, _) => FracCarrier::Invalid,
190            (_, FracCarrier::Invalid) => FracCarrier::Invalid,
191            // We can mix two owning fracs iff they are disjoint -- we get the union
192            // There is a tricky element here:
193            //  - one of the fracs may be invalid due to their maps overlapping
194            //  - there is no real way to express this in the typesystem
195            //  - we need to allow that through (because it does not equal Invalid)
196            (
197                FracCarrier::Frac { owning: a_owning, dup: a_dup },
198                FracCarrier::Frac { owning: b_owning, dup: b_dup },
199            ) => {
200                let non_overlapping = {
201                    &&& a_owning.dom().disjoint(b_dup.dom())
202                    &&& b_owning.dom().disjoint(a_dup.dom())
203                    &&& a_owning.dom().disjoint(b_owning.dom())
204                };
205                let aggreement = a_dup.agrees(b_dup);
206                if non_overlapping && aggreement {
207                    FracCarrier::Frac {
208                        owning: a_owning.union_prefer_right(b_owning),
209                        dup: a_dup.union_prefer_right(b_dup),
210                    }
211                } else {
212                    FracCarrier::Invalid
213                }
214            },
215        };
216
217        MapCarrier { auth, frac }
218    }
219
220    proof fn valid_op(a: Self, b: Self) {
221        broadcast use lemma_submap_of_trans;
222
223        let ab = MapCarrier::op(a, b);
224        lemma_submap_of_op_frac(a, b);
225        // derive contradiction that the items are disjoint
226        if !a.frac.owning_map().dom().disjoint(a.frac.dup_map().dom()) {
227            // The intersection is not empty
228            lemma_set_disjoint_iff_empty_intersection(
229                a.frac.owning_map().dom(),
230                a.frac.dup_map().dom(),
231            );
232            let a_k = choose|k: K|
233                a.frac.owning_map().dom().intersect(a.frac.dup_map().dom()).contains(k);
234            assert(ab.frac.owning_map().dom().intersect(ab.frac.dup_map().dom()).contains(a_k));  // CONTRADICTION
235        };
236    }
237
238    proof fn commutative(a: Self, b: Self) {
239        let ab = Self::op(a, b);
240        let ba = Self::op(b, a);
241        assert(ab == ba);
242    }
243
244    proof fn associative(a: Self, b: Self, c: Self) {
245        let bc = Self::op(b, c);
246        let ab = Self::op(a, b);
247        let a_bc = Self::op(a, bc);
248        let ab_c = Self::op(ab, c);
249        assert(a_bc == ab_c);
250    }
251}
252
253impl<K, V> PCM for MapCarrier<K, V> {
254    closed spec fn unit() -> Self {
255        MapCarrier {
256            auth: AuthCarrier::Frac,
257            frac: FracCarrier::Frac { owning: Map::empty(), dup: Map::empty() },
258        }
259    }
260
261    proof fn op_unit(self) {
262        let x = Self::op(self, Self::unit());
263        assert(self == x);
264    }
265
266    proof fn unit_valid() {
267    }
268}
269
270proof fn lemma_submap_of_op_frac<K, V>(a: MapCarrier<K, V>, b: MapCarrier<K, V>)
271    requires
272        MapCarrier::op(a, b).valid(),
273    ensures
274        a.frac.owning_map() <= MapCarrier::op(a, b).frac.owning_map(),
275        a.frac.dup_map() <= MapCarrier::op(a, b).frac.dup_map(),
276        b.frac.owning_map() <= MapCarrier::op(a, b).frac.owning_map(),
277        b.frac.dup_map() <= MapCarrier::op(a, b).frac.dup_map(),
278{
279    let ab = MapCarrier::op(a, b);
280    assert(ab.frac.owning_map() == a.frac.owning_map().union_prefer_right(b.frac.owning_map()));
281    assert(ab.frac.dup_map() == a.frac.dup_map().union_prefer_right(b.frac.dup_map()));
282    assert(a.frac.owning_map().dom().disjoint(b.frac.owning_map().dom()));
283}
284
285broadcast proof fn lemma_submap_of_op<K, V>(a: MapCarrier<K, V>, b: MapCarrier<K, V>)
286    requires
287        #[trigger] MapCarrier::op(a, b).valid(),
288    ensures
289        a.frac.owning_map() <= MapCarrier::op(a, b).frac.owning_map(),
290        a.frac.dup_map() <= MapCarrier::op(a, b).frac.dup_map(),
291        a.auth.map() <= MapCarrier::op(a, b).auth.map(),
292        b.frac.owning_map() <= MapCarrier::op(a, b).frac.owning_map(),
293        b.frac.dup_map() <= MapCarrier::op(a, b).frac.dup_map(),
294        b.auth.map() <= MapCarrier::op(a, b).auth.map(),
295        a.valid(),
296        b.valid(),
297{
298    lemma_submap_of_op_frac(a, b);
299    MapCarrier::valid_op(a, b);
300    MapCarrier::commutative(a, b);
301    MapCarrier::valid_op(b, a);
302    let ab = MapCarrier::op(a, b);
303    assert(ab.auth.map() == a.auth.map().union_prefer_right(b.auth.map()));
304}
305
306/// A resource that has the authoritative ownership on the entire map
307#[verifier::reject_recursive_types(K)]
308pub tracked struct GhostMapAuth<K, V> {
309    r: Resource<MapCarrier<K, V>>,
310}
311
312/// A resource that asserts client ownership of a submap.
313///
314/// The existence of a [`GhostSubmap`] implies that:
315///  - Those keys will remain in the map (unless the onwer of the [`GhostSubmap`] deletes it using [`GhostMapAuth::delete`]);
316///  - Those keys will remain pointing to the same values (unless the onwer of the [`GhostSubmap`] updates them using [`GhostSubmap::update`])
317///  - All other [`GhostSubmap`]/[`GhostPointsTo`]/[`GhostPersistentSubmap`]/[`GhostPersistentPointsTo`] are disjoint subsets of the domain
318#[verifier::reject_recursive_types(K)]
319pub tracked struct GhostSubmap<K, V> {
320    r: Resource<MapCarrier<K, V>>,
321}
322
323/// A resource representing duplicable client knowledge of a persistent submap.
324///
325/// The existence of a [`GhostPersistentSubmap`] implies that:
326///  - Those keys will remain in the map, pointing to the same values, forever;
327///  - All other [`GhostSubmap`]/[`GhostPointsTo`] are disjoint subsets of the domain
328#[verifier::reject_recursive_types(K)]
329pub tracked struct GhostPersistentSubmap<K, V> {
330    r: Resource<MapCarrier<K, V>>,
331}
332
333/// A resource that asserts client ownership over a single key in the map.
334///
335/// The existence of a [`GhostPointsTo`] implies that:
336///  - Those key will remain in the map (unless the onwer of the [`GhostPointsTo`] deletes it using [`GhostMapAuth::delete_points_to`]);
337///  - Those key will remain pointing to the same value (unless the onwer of the [`GhostPointsTo`] updates them using [`GhostPointsTo::update`])
338///  - All other [`GhostSubmap`]/[`GhostPointsTo`]/[`GhostPersistentSubmap`]/[`GhostPersistentPointsTo`] are disjoint subsets of the domain
339#[verifier::reject_recursive_types(K)]
340pub tracked struct GhostPointsTo<K, V> {
341    submap: GhostSubmap<K, V>,
342}
343
344/// A resource representing duplicable client knowledge of a single key in the map.
345///
346/// The existence of a [`GhostPersistentPointsTo`] implies that:
347///  - The key-value pair will remain in the map, forever;
348///  - All other [`GhostSubmap`]/[`GhostPointsTo`] are disjoint subsets of the domain
349#[verifier::reject_recursive_types(K)]
350pub tracked struct GhostPersistentPointsTo<K, V> {
351    submap: GhostPersistentSubmap<K, V>,
352}
353
354impl<K, V> GhostMapAuth<K, V> {
355    #[verifier::type_invariant]
356    spec fn inv(self) -> bool {
357        &&& self.r.value().auth is Auth
358        &&& self.r.value().frac == FracCarrier::Frac {
359            owning: Map::<K, V>::empty(),
360            dup: Map::<K, V>::empty(),
361        }
362    }
363
364    /// Resource location
365    pub closed spec fn id(self) -> Loc {
366        self.r.loc()
367    }
368
369    /// Logically underlying [`Map`]
370    pub closed spec fn view(self) -> Map<K, V> {
371        self.r.value().auth.map()
372    }
373
374    /// Domain of the [`GhostMapAuth`]
375    pub open spec fn dom(self) -> Set<K> {
376        self@.dom()
377    }
378
379    /// Indexing operation `auth[key]`
380    pub open spec fn spec_index(self, key: K) -> V
381        recommends
382            self.dom().contains(key),
383    {
384        self@[key]
385    }
386
387    /// Instantiate a dummy [`GhostMapAuth`]
388    pub proof fn dummy() -> (tracked result: GhostMapAuth<K, V>) {
389        let tracked (auth, submap) = GhostMapAuth::<K, V>::new(Map::empty());
390        auth
391    }
392
393    /// Extract the [`GhostMapAuth`] from a mutable reference
394    pub proof fn take(tracked &mut self) -> (tracked result: GhostMapAuth<K, V>)
395        ensures
396            result == *old(self),
397    {
398        use_type_invariant(&*self);
399        let tracked mut r = Self::dummy();
400        tracked_swap(self, &mut r);
401        r
402    }
403
404    /// Create an empty [`GhostSubmap`]
405    pub proof fn empty(tracked &self) -> (tracked result: GhostSubmap<K, V>)
406        ensures
407            result.id() == self.id(),
408            result@ == Map::<K, V>::empty(),
409    {
410        use_type_invariant(self);
411        let tracked r = Resource::<MapCarrier<_, _>>::create_unit(self.r.loc());
412        GhostSubmap { r }
413    }
414
415    /// Insert an [`Map`] of values, receiving the [`GhostSubmap`] that asserts ownership over the key
416    /// domain inserted.
417    ///
418    /// ```
419    /// proof fn insert_map_example(tracked mut m: GhostMapAuth<int, int>) -> (tracked r: GhostSubmap<int, int>)
420    ///     requires
421    ///         !m.dom().contains(1int),
422    ///         !m.dom().contains(2int),
423    /// {
424    ///     let tracked submap = m.insert_map(map![1int => 1int, 2int => 4int]);
425    ///     // do something with the submap
426    ///     submap
427    /// }
428    /// ```
429    pub proof fn insert_map(tracked &mut self, m: Map<K, V>) -> (tracked result: GhostSubmap<K, V>)
430        requires
431            old(self)@.dom().disjoint(m.dom()),
432        ensures
433            final(self).id() == old(self).id(),
434            final(self)@ == old(self)@.union_prefer_right(m),
435            result.id() == final(self).id(),
436            result@ == m,
437    {
438        broadcast use lemma_submap_of_trans;
439        broadcast use lemma_submap_of_op;
440
441        let tracked mut mself = Self::dummy();
442        tracked_swap(self, &mut mself);
443
444        use_type_invariant(&mself);
445        assert(mself.inv());
446        let tracked mut self_r = mself.r;
447
448        let full_carrier = MapCarrier {
449            auth: AuthCarrier::Auth(self_r.value().auth.map().union_prefer_right(m)),
450            frac: FracCarrier::Frac { owning: m, dup: Map::empty() },
451        };
452
453        assert(full_carrier.valid());
454        assert forall|c: MapCarrier<K, V>| #[trigger]
455            MapCarrier::op(self_r.value(), c).valid() implies MapCarrier::op(
456            full_carrier,
457            c,
458        ).valid() by {
459            assert(full_carrier.frac.owning_map().dom().disjoint(c.frac.dup_map().dom()));
460        }
461        let tracked updated_r = self_r.update(full_carrier);
462
463        let auth_carrier = MapCarrier {
464            auth: updated_r.value().auth,
465            frac: FracCarrier::Frac { owning: Map::empty(), dup: Map::empty() },
466        };
467        let frac_carrier = MapCarrier { auth: AuthCarrier::Frac, frac: updated_r.value().frac };
468
469        assert(updated_r.value() == MapCarrier::op(auth_carrier, frac_carrier));
470        let tracked (auth_r, frac_r) = updated_r.split(auth_carrier, frac_carrier);
471        self.r = auth_r;
472        GhostSubmap { r: frac_r }
473    }
474
475    /// Insert a key-value pair, receiving the [`GhostPointsTo`] that asserts ownerships over the key.
476    ///
477    /// ```
478    /// proof fn insert_example(tracked mut m: GhostMapAuth<int, int>) -> (tracked r: GhostPointsTo<int, int>)
479    ///     requires
480    ///         !m.dom().contains(1int),
481    /// {
482    ///     let tracked points_to = m.insert(1, 1);
483    ///     // do something with the points_to
484    ///     points_to
485    /// }
486    /// ```
487    pub proof fn insert(tracked &mut self, k: K, v: V) -> (tracked result: GhostPointsTo<K, V>)
488        requires
489            !old(self)@.contains_key(k),
490        ensures
491            final(self).id() == old(self).id(),
492            final(self)@ == old(self)@.insert(k, v),
493            result.id() == final(self).id(),
494            result@ == (k, v),
495    {
496        let tracked submap = self.insert_map(map![k => v]);
497        GhostPointsTo { submap }
498    }
499
500    /// Delete a set of keys
501    /// ```
502    /// proof fn delete(tracked mut auth: GhostMapAuth<int, int>)
503    ///     requires
504    ///         auth.dom().contains(1int),
505    ///         auth.dom().contains(2int),
506    ///     ensures
507    ///         old(auth)@ == auth@
508    /// {
509    ///     let tracked submap = auth.insert_map(map![1int => 1int, 2int => 4int]);
510    ///     // do something with the submap
511    ///     auth.delete(submap)
512    /// }
513    /// ```
514    pub proof fn delete(tracked &mut self, tracked submap: GhostSubmap<K, V>)
515        requires
516            submap.id() == old(self).id(),
517        ensures
518            final(self).id() == old(self).id(),
519            final(self)@ == old(self)@.remove_keys(submap@.dom()),
520    {
521        broadcast use lemma_submap_of_trans;
522        broadcast use lemma_submap_of_op;
523
524        use_type_invariant(&*self);
525        use_type_invariant(&submap);
526
527        let tracked mut mself = Self::dummy();
528        tracked_swap(self, &mut mself);
529        let tracked mut self_r = mself.r;
530
531        // join the resource with the original carrier
532        self_r = self_r.join(submap.r);
533
534        // remove keys from the map
535        let auth_map = self_r.value().auth.map();
536        let new_auth_map = auth_map.remove_keys(submap@.dom());
537
538        let new_r = MapCarrier {
539            auth: AuthCarrier::Auth(new_auth_map),
540            frac: FracCarrier::Frac { owning: Map::empty(), dup: Map::empty() },
541        };
542
543        // update the resource
544        self.r = self_r.update(new_r);
545    }
546
547    /// Delete a single key from the map
548    /// ```
549    /// proof fn delete_key(tracked mut auth: GhostMapAuth<int, int>)
550    ///     requires
551    ///         auth.dom().contains(1int),
552    ///     ensures
553    ///         old(auth)@ == auth@
554    /// {
555    ///     let tracked points_to = auth.insert(1, 1);
556    ///     // do something with the submap
557    ///     auth.delete_points_to(points_to)
558    /// }
559    /// ```
560    pub proof fn delete_points_to(tracked &mut self, tracked p: GhostPointsTo<K, V>)
561        requires
562            p.id() == old(self).id(),
563        ensures
564            final(self).id() == old(self).id(),
565            final(self)@ == old(self)@.remove(p.key()),
566    {
567        use_type_invariant(&p);
568        p.lemma_map_view();
569        self.delete(p.submap);
570    }
571
572    /// Create a new [`GhostMapAuth`] from an [`Map`].
573    /// Gives the other half of ownership in the form of a [`GhostSubmap`].
574    ///
575    /// ```
576    /// fn example() {
577    ///     let m = map![1int => 1int, 2int => 4int, 3int => 9int];
578    ///     let tracked (auth, sub) = GhostMapAuth::new(m);
579    ///     assert(auth@ == m);
580    ///     assert(sub.dom() == m.dom());
581    /// }
582    /// ```
583    pub proof fn new(m: Map<K, V>) -> (tracked result: (GhostMapAuth<K, V>, GhostSubmap<K, V>))
584        ensures
585            result.0.id() == result.1.id(),
586            result.0@ == m,
587            result.1@ == m,
588    {
589        let tracked full_r = Resource::alloc(
590            MapCarrier {
591                auth: AuthCarrier::Auth(m),
592                frac: FracCarrier::Frac { owning: m, dup: Map::empty() },
593            },
594        );
595
596        let auth_carrier = MapCarrier {
597            auth: AuthCarrier::Auth(m),
598            frac: FracCarrier::Frac { owning: Map::empty(), dup: Map::empty() },
599        };
600
601        let frac_carrier = MapCarrier {
602            auth: AuthCarrier::Frac,
603            frac: FracCarrier::Frac { owning: m, dup: Map::empty() },
604        };
605
606        assert(full_r.value() == MapCarrier::op(auth_carrier, frac_carrier));
607        let tracked (auth_r, frac_r) = full_r.split(auth_carrier, frac_carrier);
608        (GhostMapAuth { r: auth_r }, GhostSubmap { r: frac_r })
609    }
610}
611
612impl<K, V> GhostSubmap<K, V> {
613    #[verifier::type_invariant]
614    spec fn inv(self) -> bool {
615        &&& self.r.value().auth is Frac
616        &&& self.r.value().frac is Frac
617        &&& self.r.value().frac.dup_map().is_empty()
618    }
619
620    /// Checks whether the [`GhostSubmap`] refers to a single key (and thus can be converted to a
621    /// [`GhostPointsTo`]).
622    pub open spec fn is_points_to(self) -> bool {
623        &&& self@.len() == 1
624        &&& !self@.is_empty()
625    }
626
627    /// Resource location
628    pub closed spec fn id(self) -> Loc {
629        self.r.loc()
630    }
631
632    /// Logically underlying [`Map`]
633    pub closed spec fn view(self) -> Map<K, V> {
634        self.r.value().frac.owning_map()
635    }
636
637    /// Domain of the [`GhostSubmap`]
638    pub open spec fn dom(self) -> Set<K> {
639        self@.dom()
640    }
641
642    /// Indexing operation `submap[key]`
643    pub open spec fn spec_index(self, key: K) -> V
644        recommends
645            self.dom().contains(key),
646    {
647        self@[key]
648    }
649
650    /// Instantiate a dummy [`GhostSubmap`]
651    pub proof fn dummy() -> (tracked result: GhostSubmap<K, V>) {
652        let tracked (auth, submap) = GhostMapAuth::<K, V>::new(Map::empty());
653        submap
654    }
655
656    /// Create an empty [`GhostSubmap`]
657    pub proof fn empty(tracked &self) -> (tracked result: GhostSubmap<K, V>)
658        ensures
659            result.id() == self.id(),
660            result@ == Map::<K, V>::empty(),
661    {
662        use_type_invariant(self);
663        let tracked r = Resource::<MapCarrier<_, _>>::create_unit(self.r.loc());
664        GhostSubmap { r }
665    }
666
667    /// Extract the [`GhostSubmap`] from a mutable reference, leaving behind an empty map.
668    pub proof fn take(tracked &mut self) -> (tracked result: GhostSubmap<K, V>)
669        ensures
670            old(self).id() == final(self).id(),
671            final(self)@.is_empty(),
672            result == *old(self),
673            result.id() == final(self).id(),
674    {
675        use_type_invariant(&*self);
676
677        let tracked mut r = self.empty();
678        tracked_swap(self, &mut r);
679        r
680    }
681
682    /// Agreement between a [`GhostSubmap`] and a corresponding [`GhostMapAuth`]
683    ///
684    /// Verus might not have full context of the [`GhostMapAuth`] and a corresponding [`GhostSubmap`].
685    /// However, whenever we know that they refer to the same resource (i.e., have matching ids) we
686    /// can assert that the [`GhostSubmap`] is a submap of the [`GhostMapAuth`].
687    /// ```
688    /// proof fn test(tracked &auth: GhostMapAuth<int, int>, tracked &sub: GhostSubmap<int, int>)
689    ///     requires
690    ///         auth.id() == sub.id(),
691    ///         sub.dom().contains(1int),
692    ///         sub[1int] == 1int,
693    ///     ensures
694    ///         auth[1int] == 1int
695    /// {
696    ///     sub.agree(auth);
697    ///     assert(sub@ <= auth@);
698    ///     assert(auth[1int] == 1int);
699    /// }
700    /// ```
701    pub proof fn agree(tracked self: &GhostSubmap<K, V>, tracked auth: &GhostMapAuth<K, V>)
702        requires
703            self.id() == auth.id(),
704        ensures
705            self@ <= auth@,
706    {
707        broadcast use lemma_submap_of_trans;
708
709        use_type_invariant(self);
710        use_type_invariant(auth);
711
712        let tracked joined = self.r.join_shared(&auth.r);
713        joined.validate();
714        assert(self.r.value().frac.owning_map() <= joined.value().frac.owning_map());
715    }
716
717    /// Combining two [`GhostSubmap`]s is possible.
718    /// We consume the input [`GhostSubmap`] and merge it into the first.
719    /// We also learn that they were disjoint.
720    pub proof fn combine(tracked &mut self, tracked other: GhostSubmap<K, V>)
721        requires
722            old(self).id() == other.id(),
723        ensures
724            final(self).id() == old(self).id(),
725            final(self)@ == old(self)@.union_prefer_right(other@),
726            old(self)@.dom().disjoint(other@.dom()),
727    {
728        use_type_invariant(&*self);
729        use_type_invariant(&other);
730
731        self.r.validate_2(&other.r);
732        incorporate(&mut self.r, other.r);
733    }
734
735    /// Combining a [`GhostPointsTo`] into [`GhostSubmap`] is possible, in a similar way to the way to combine
736    /// [`GhostSubmap`]s.
737    pub proof fn combine_points_to(tracked &mut self, tracked other: GhostPointsTo<K, V>)
738        requires
739            old(self).id() == other.id(),
740        ensures
741            final(self).id() == old(self).id(),
742            final(self)@ == old(self)@.insert(other.key(), other.value()),
743            !old(self)@.contains_key(other.key()),
744    {
745        use_type_invariant(&*self);
746        use_type_invariant(&other);
747
748        other.lemma_map_view();
749        self.combine(other.submap);
750    }
751
752    /// When we have two [`GhostSubmap`]s we can prove that they have disjoint domains.
753    pub proof fn disjoint(tracked &mut self, tracked other: &GhostSubmap<K, V>)
754        requires
755            old(self).id() == other.id(),
756        ensures
757            final(self).id() == old(self).id(),
758            final(self)@ == old(self)@,
759            final(self)@.dom().disjoint(other@.dom()),
760    {
761        use_type_invariant(&*self);
762        use_type_invariant(other);
763        self.r.validate_2(&other.r);
764    }
765
766    /// When we have a [`GhostSubmap`] and a [`GhostPersistentSubmap`] we can prove that they are in disjoint
767    /// domains.
768    pub proof fn disjoint_persistent(tracked &mut self, tracked other: &GhostPersistentSubmap<K, V>)
769        requires
770            old(self).id() == other.id(),
771        ensures
772            final(self).id() == old(self).id(),
773            final(self)@ == old(self)@,
774            final(self)@.dom().disjoint(other@.dom()),
775    {
776        use_type_invariant(&*self);
777        use_type_invariant(other);
778        self.r.validate_2(&other.r);
779    }
780
781    /// When we have a [`GhostSubmap`] and a [`GhostPointsTo`] we can prove that they are in disjoint
782    /// domains.
783    pub proof fn disjoint_points_to(tracked &mut self, tracked other: &GhostPointsTo<K, V>)
784        requires
785            old(self).id() == other.id(),
786        ensures
787            final(self).id() == old(self).id(),
788            final(self)@ == old(self)@,
789            !final(self)@.contains_key(other.key()),
790    {
791        use_type_invariant(&*self);
792        use_type_invariant(other);
793        self.disjoint(&other.submap);
794    }
795
796    /// When we have a [`GhostSubmap`] and a [`GhostPersistentPointsTo`] we can prove that they are in disjoint
797    /// domains.
798    pub proof fn disjoint_persistent_points_to(
799        tracked &mut self,
800        tracked other: &GhostPersistentPointsTo<K, V>,
801    )
802        requires
803            old(self).id() == other.id(),
804        ensures
805            final(self).id() == old(self).id(),
806            final(self)@ == old(self)@,
807            !final(self)@.contains_key(other.key()),
808    {
809        use_type_invariant(&*self);
810        use_type_invariant(other);
811        self.disjoint_persistent(&other.submap);
812    }
813
814    /// We can split a [`GhostSubmap`] based on a set of keys in its domain.
815    pub proof fn split(tracked &mut self, s: Set<K>) -> (tracked result: GhostSubmap<K, V>)
816        requires
817            s <= old(self)@.dom(),
818        ensures
819            final(self).id() == old(self).id(),
820            result.id() == final(self).id(),
821            old(self)@ == final(self)@.union_prefer_right(result@),
822            result@.dom() =~= s,
823            final(self)@.dom() =~= old(self)@.dom() - s,
824    {
825        use_type_invariant(&*self);
826
827        let self_carrier = MapCarrier {
828            auth: AuthCarrier::Frac,
829            frac: FracCarrier::Frac {
830                owning: self.r.value().frac.owning_map().remove_keys(s),
831                dup: self.r.value().frac.dup_map(),
832            },
833        };
834
835        let res_carrier = MapCarrier {
836            auth: AuthCarrier::Frac,
837            frac: FracCarrier::Frac {
838                owning: self.r.value().frac.owning_map().restrict(s),
839                dup: self.r.value().frac.dup_map(),
840            },
841        };
842
843        assert(self.r.value().frac == MapCarrier::op(self_carrier, res_carrier).frac);
844        let tracked r = split_mut(&mut self.r, self_carrier, res_carrier);
845        GhostSubmap { r }
846    }
847
848    pub proof fn split_with_olddom(tracked &mut self, s: Set<K>, olddom: Set<K>) -> (tracked result:
849        GhostSubmap<K, V>)
850        requires
851            olddom == old(self)@.dom(),
852            s <= olddom,
853        ensures
854            final(self).id() == old(self).id(),
855            result.id() == final(self).id(),
856            old(self)@ == final(self)@.union_prefer_right(result@),
857            result@.dom() == s,
858            final(self)@.dom() == olddom - s,
859    {
860        let tracked out = self.split(s);
861        assert(olddom == old(self)@.dom());
862        assert(self@.dom() == old(self)@.dom() - s);
863        assert(self@.dom() == olddom - s);
864        assert(out@.dom() == s);
865        out
866    }
867
868    /// We can separate a single key out of a [`GhostSubmap`]
869    pub proof fn split_points_to(tracked &mut self, k: K) -> (tracked result: GhostPointsTo<K, V>)
870        requires
871            old(self)@.contains_key(k),
872        ensures
873            final(self).id() == old(self).id(),
874            result.id() == final(self).id(),
875            old(self)@ == final(self)@.insert(result.key(), result.value()),
876            result.key() == k,
877            final(self)@ == old(self)@.remove(k),
878    {
879        use_type_invariant(&*self);
880
881        let tracked submap = self.split(set![k]);
882        GhostPointsTo { submap }
883    }
884
885    /// When we have both the [`GhostMapAuth`] and a [`GhostSubmap`] we can update the values for a
886    /// subset of keys in our submap.
887    /// ```
888    /// proof fn test(tracked auth: &mut GhostMapAuth<int, int>, tracked sub: &mut GhostSubmap<int, int>)
889    ///     requires
890    ///         auth.id() == sub.id(),
891    ///         sub.dom() == set![1int, 2int, 3int]
892    ///     ensures
893    ///         auth[1int] == 9int
894    ///         auth[2int] == 10int
895    ///         auth[3int] == 11int
896    /// {
897    ///     // need to agree on the subset
898    ///     sub.agree(auth);
899    ///     assert(sub@ <= auth@);
900    ///     sub.update(map![1int => 9int, 2int => 10int, 3int => 11int]);
901    /// }
902    /// ```
903    pub proof fn update(tracked &mut self, tracked auth: &mut GhostMapAuth<K, V>, m: Map<K, V>)
904        requires
905            m.dom() <= old(self)@.dom(),
906            old(self).id() == old(auth).id(),
907        ensures
908            final(self).id() == old(self).id(),
909            final(auth).id() == old(auth).id(),
910            final(self)@ == old(self)@.union_prefer_right(m),
911            final(auth)@ == old(auth)@.union_prefer_right(m),
912    {
913        broadcast use lemma_submap_of_trans;
914        broadcast use lemma_submap_of_op;
915
916        use_type_invariant(&*self);
917        use_type_invariant(&*auth);
918
919        let tracked mut mself = Self::dummy();
920        tracked_swap(self, &mut mself);
921        let tracked mut frac_r = mself.r;
922
923        let tracked mut mauth = GhostMapAuth::<K, V>::dummy();
924        tracked_swap(auth, &mut mauth);
925        let tracked mut auth_r = mauth.r;
926
927        frac_r.validate_2(&auth_r);
928        let tracked mut full_r = frac_r.join(auth_r);
929
930        assert(full_r.value().frac.owning_map() == frac_r.value().frac.owning_map());
931
932        let auth_carrier = AuthCarrier::Auth(full_r.value().auth.map().union_prefer_right(m));
933        let frac_carrier = FracCarrier::Frac {
934            owning: full_r.value().frac.owning_map().union_prefer_right(m),
935            dup: Map::empty(),
936        };
937        let new_full_carrier = MapCarrier { auth: auth_carrier, frac: frac_carrier };
938
939        assert(new_full_carrier.valid());
940        let tracked r_upd = full_r.update(new_full_carrier);
941
942        let new_auth_carrier = MapCarrier {
943            auth: r_upd.value().auth,
944            frac: FracCarrier::Frac { owning: Map::empty(), dup: Map::empty() },
945        };
946        let new_frac_carrier = MapCarrier { auth: AuthCarrier::Frac, frac: r_upd.value().frac };
947        assert(r_upd.value().frac == MapCarrier::op(new_auth_carrier, new_frac_carrier).frac);
948        assert(r_upd.value() == MapCarrier::op(new_auth_carrier, new_frac_carrier));
949
950        let tracked (new_auth_r, new_frac_r) = r_upd.split(new_auth_carrier, new_frac_carrier);
951        auth.r = new_auth_r;
952        self.r = new_frac_r;
953    }
954
955    /// Converting a [`GhostSubmap`] into a [`GhostPointsTo`]
956    pub proof fn points_to(tracked self) -> (tracked r: GhostPointsTo<K, V>)
957        requires
958            self.is_points_to(),
959        ensures
960            self@ == map![r.key() => r.value()],
961            self.id() == r.id(),
962    {
963        let tracked r = GhostPointsTo { submap: self };
964        r.lemma_map_view();
965        r
966    }
967
968    /// Convert a [`GhostSubmap`] into a [`GhostPersistentSubmap`]
969    pub proof fn persist(tracked self) -> (tracked r: GhostPersistentSubmap<K, V>)
970        ensures
971            self@ == r@,
972            self.id() == r.id(),
973    {
974        broadcast use lemma_submap_of_trans;
975        broadcast use lemma_submap_of_op;
976
977        use_type_invariant(&self);
978
979        let tracked mut r = self.r;
980
981        let self_carrier = MapCarrier {
982            auth: AuthCarrier::Frac,
983            frac: FracCarrier::Frac {
984                owning: self.r.value().frac.owning_map(),
985                dup: self.r.value().frac.dup_map(),
986            },
987        };
988
989        let res_carrier = MapCarrier {
990            auth: AuthCarrier::Frac,
991            frac: FracCarrier::Frac {
992                owning: self.r.value().frac.dup_map(),
993                dup: self.r.value().frac.owning_map(),
994            },
995        };
996
997        let tracked r = r.update(res_carrier);
998        GhostPersistentSubmap { r }
999    }
1000}
1001
1002impl<K, V> GhostPersistentSubmap<K, V> {
1003    #[verifier::type_invariant]
1004    spec fn inv(self) -> bool {
1005        &&& self.r.value().auth is Frac
1006        &&& self.r.value().frac is Frac
1007        &&& self.r.value().frac.owning_map().is_empty()
1008    }
1009
1010    /// Checks whether the [`GhostPersistentSubmap`] refers to a single key (and thus can be converted to a
1011    /// [`GhostPersistentPointsTo`]).
1012    pub open spec fn is_points_to(self) -> bool {
1013        &&& self@.len() == 1
1014        &&& !self@.is_empty()
1015    }
1016
1017    /// Resource location
1018    pub closed spec fn id(self) -> Loc {
1019        self.r.loc()
1020    }
1021
1022    /// Logically underlying [`Map`]
1023    pub closed spec fn view(self) -> Map<K, V> {
1024        self.r.value().frac.dup_map()
1025    }
1026
1027    /// Domain of the [`GhostPersistentSubmap`]
1028    pub open spec fn dom(self) -> Set<K> {
1029        self@.dom()
1030    }
1031
1032    /// Indexing operation `submap[key]`
1033    pub open spec fn spec_index(self, key: K) -> V
1034        recommends
1035            self.dom().contains(key),
1036    {
1037        self@[key]
1038    }
1039
1040    /// Instantiate a dummy [`GhostPersistentSubmap`]
1041    pub proof fn dummy() -> (tracked result: GhostPersistentSubmap<K, V>) {
1042        let tracked owned = GhostSubmap::<K, V>::dummy();
1043        owned.persist()
1044    }
1045
1046    /// Create an empty [`GhostPersistentSubmap`]
1047    pub proof fn empty(tracked &self) -> (tracked result: GhostPersistentSubmap<K, V>)
1048        ensures
1049            result.id() == self.id(),
1050            result@ == Map::<K, V>::empty(),
1051    {
1052        use_type_invariant(self);
1053        let tracked r = Resource::<MapCarrier<_, _>>::create_unit(self.r.loc());
1054        GhostSubmap { r }.persist()
1055    }
1056
1057    /// Duplicate the [`GhostPersistentSubmap`]
1058    pub proof fn duplicate(tracked &self) -> (tracked result: GhostPersistentSubmap<K, V>)
1059        ensures
1060            result.id() == self.id(),
1061            result@ == self@,
1062    {
1063        use_type_invariant(&*self);
1064
1065        assert(MapCarrier::op(self.r.value(), self.r.value()) == self.r.value());
1066        let tracked r = super::super::lib::duplicate(&self.r);
1067
1068        GhostPersistentSubmap { r }
1069    }
1070
1071    /// Agreement between a [`GhostPersistentSubmap`] and a corresponding [`GhostMapAuth`]
1072    ///
1073    /// Verus might not have full context of the [`GhostMapAuth`] and a corresponding [`GhostPersistentSubmap`].
1074    /// However, whenever we know that they refer to the same resource (i.e., have matching ids) we
1075    /// can assert that the [`GhostPersistentSubmap`] is a submap of the [`GhostMapAuth`].
1076    /// ```
1077    /// proof fn test(tracked &auth: GhostMapAuth<int, int>, tracked &sub: GhostPersistentSubmap<int, int>)
1078    ///     requires
1079    ///         auth.id() == sub.id(),
1080    ///         sub.dom().contains(1int),
1081    ///         sub[1int] == 1int,
1082    ///     ensures
1083    ///         auth[1int] == 1int
1084    /// {
1085    ///     sub.agree(auth);
1086    ///     assert(sub@ <= auth@);
1087    ///     assert(auth[1int] == 1int);
1088    /// }
1089    /// ```
1090    pub proof fn agree(
1091        tracked self: &GhostPersistentSubmap<K, V>,
1092        tracked auth: &GhostMapAuth<K, V>,
1093    )
1094        requires
1095            self.id() == auth.id(),
1096        ensures
1097            self@ <= auth@,
1098    {
1099        broadcast use lemma_submap_of_trans;
1100
1101        use_type_invariant(self);
1102        use_type_invariant(auth);
1103
1104        let tracked joined = self.r.join_shared(&auth.r);
1105        joined.validate();
1106        assert(self.r.value().frac.dup_map() <= joined.value().frac.dup_map());
1107    }
1108
1109    /// Combining two [`GhostPersistentSubmap`]s is possible.
1110    /// We consume the input [`GhostPersistentSubmap`] and merge it into the first.
1111    /// We also learn that they agreed
1112    pub proof fn combine(tracked &mut self, tracked other: GhostPersistentSubmap<K, V>)
1113        requires
1114            old(self).id() == other.id(),
1115        ensures
1116            final(self).id() == old(self).id(),
1117            final(self)@ == old(self)@.union_prefer_right(other@),
1118            old(self)@.agrees(other@),
1119    {
1120        use_type_invariant(&*self);
1121        use_type_invariant(&other);
1122
1123        self.r.validate_2(&other.r);
1124        incorporate(&mut self.r, other.r);
1125    }
1126
1127    /// Combining a [`GhostPersistentPointsTo`] into [`GhostPersistentSubmap`] is possible, in a similar way to the way to combine
1128    /// [`GhostPersistentSubmap`]s.
1129    pub proof fn combine_points_to(tracked &mut self, tracked other: GhostPersistentPointsTo<K, V>)
1130        requires
1131            old(self).id() == other.id(),
1132        ensures
1133            final(self).id() == old(self).id(),
1134            final(self)@ == old(self)@.insert(other.key(), other.value()),
1135            old(self)@.contains_key(other.key()) ==> old(self)@[other.key()] == other.value(),
1136    {
1137        use_type_invariant(&*self);
1138        use_type_invariant(&other);
1139
1140        other.lemma_map_view();
1141        self.combine(other.submap);
1142    }
1143
1144    /// When we have a [`GhostPersistentSubmap`] and a [`GhostSubmap`] we can prove that they have disjoint domains.
1145    pub proof fn disjoint(tracked &mut self, tracked other: &GhostSubmap<K, V>)
1146        requires
1147            old(self).id() == other.id(),
1148        ensures
1149            final(self).id() == old(self).id(),
1150            final(self)@ == old(self)@,
1151            final(self)@.dom().disjoint(other@.dom()),
1152    {
1153        use_type_invariant(&*self);
1154        use_type_invariant(other);
1155        self.r.validate_2(&other.r);
1156    }
1157
1158    /// When we have two [`GhostPersistentSubmap`]s we can prove that they agree on their intersection.
1159    pub proof fn intersection_agrees(tracked &mut self, tracked other: &GhostPersistentSubmap<K, V>)
1160        requires
1161            old(self).id() == other.id(),
1162        ensures
1163            final(self).id() == old(self).id(),
1164            final(self)@ == old(self)@,
1165            final(self)@.agrees(other@),
1166    {
1167        use_type_invariant(&*self);
1168        use_type_invariant(other);
1169        self.r.validate_2(&other.r);
1170    }
1171
1172    /// When we have a [`GhostPersistentSubmap`] and a [`GhostPointsTo`] we can prove that they are in disjoint
1173    /// domains.
1174    pub proof fn disjoint_points_to(tracked &mut self, tracked other: &GhostPointsTo<K, V>)
1175        requires
1176            old(self).id() == other.id(),
1177        ensures
1178            final(self).id() == old(self).id(),
1179            final(self)@ == old(self)@,
1180            !final(self)@.contains_key(other.key()),
1181    {
1182        use_type_invariant(&*self);
1183        use_type_invariant(other);
1184        self.disjoint(&other.submap);
1185    }
1186
1187    /// When we have a [`GhostPersistentSubmap`] and a [`GhostPersistentPointsTo`],
1188    /// we can prove that either they are disjoint domains or the key-value pair is in the
1189    /// persistent submap.
1190    pub proof fn intersection_agrees_points_to(
1191        tracked &mut self,
1192        tracked other: &GhostPersistentPointsTo<K, V>,
1193    )
1194        requires
1195            old(self).id() == other.id(),
1196        ensures
1197            final(self).id() == old(self).id(),
1198            final(self)@ == old(self)@,
1199            final(self)@.contains_key(other.key()) ==> final(self)@[other.key()] == other.value(),
1200    {
1201        use_type_invariant(&*self);
1202        use_type_invariant(other);
1203        self.intersection_agrees(&other.submap);
1204    }
1205
1206    /// We can split a [`GhostPersistentSubmap`] based on a set of keys in its domain.
1207    pub proof fn split(tracked &mut self, s: Set<K>) -> (tracked result: GhostPersistentSubmap<
1208        K,
1209        V,
1210    >)
1211        requires
1212            s <= old(self)@.dom(),
1213        ensures
1214            final(self).id() == old(self).id(),
1215            result.id() == final(self).id(),
1216            old(self)@ == final(self)@.union_prefer_right(result@),
1217            result@.dom() =~= s,
1218            final(self)@.dom() =~= old(self)@.dom() - s,
1219    {
1220        use_type_invariant(&*self);
1221
1222        let tracked mut r = Resource::alloc(MapCarrier::<K, V>::unit());
1223        tracked_swap(&mut self.r, &mut r);
1224
1225        let self_carrier = MapCarrier {
1226            auth: AuthCarrier::Frac,
1227            frac: FracCarrier::Frac {
1228                owning: r.value().frac.owning_map(),
1229                dup: r.value().frac.dup_map().remove_keys(s),
1230            },
1231        };
1232
1233        let res_carrier = MapCarrier {
1234            auth: AuthCarrier::Frac,
1235            frac: FracCarrier::Frac {
1236                owning: r.value().frac.owning_map(),
1237                dup: r.value().frac.dup_map().restrict(s),
1238            },
1239        };
1240
1241        assert(r.value().frac == MapCarrier::op(self_carrier, res_carrier).frac);
1242        let tracked (self_r, res_r) = r.split(self_carrier, res_carrier);
1243        self.r = self_r;
1244        GhostPersistentSubmap { r: res_r }
1245    }
1246
1247    /// We can separate a single key out of a [`GhostPersistentSubmap`]
1248    pub proof fn split_points_to(tracked &mut self, k: K) -> (tracked result:
1249        GhostPersistentPointsTo<K, V>)
1250        requires
1251            old(self)@.contains_key(k),
1252        ensures
1253            final(self).id() == old(self).id(),
1254            result.id() == final(self).id(),
1255            old(self)@ == final(self)@.insert(result.key(), result.value()),
1256            result.key() == k,
1257            final(self)@ == old(self)@.remove(k),
1258    {
1259        use_type_invariant(&*self);
1260
1261        let tracked submap = self.split(set![k]);
1262        GhostPersistentPointsTo { submap }
1263    }
1264
1265    /// Convert a [`GhostPersistentSubmap`] into a [`GhostPersistentPointsTo`]
1266    pub proof fn points_to(tracked self) -> (tracked r: GhostPersistentPointsTo<K, V>)
1267        requires
1268            self.is_points_to(),
1269        ensures
1270            self@ == map![r.key() => r.value()],
1271            self.id() == r.id(),
1272    {
1273        let tracked r = GhostPersistentPointsTo { submap: self };
1274        r.lemma_map_view();
1275        r
1276    }
1277}
1278
1279impl<K, V> GhostPointsTo<K, V> {
1280    #[verifier::type_invariant]
1281    spec fn inv(self) -> bool {
1282        self.submap.is_points_to()
1283    }
1284
1285    /// Location of the underlying resource
1286    pub closed spec fn id(self) -> Loc {
1287        self.submap.id()
1288    }
1289
1290    /// Key-Value pair underlying the points to relationship
1291    pub open spec fn view(self) -> (K, V) {
1292        (self.key(), self.value())
1293    }
1294
1295    /// Key of the points to
1296    pub closed spec fn key(self) -> K {
1297        self.submap.dom().choose()
1298    }
1299
1300    /// Pointed-to value
1301    pub closed spec fn value(self) -> V {
1302        self.submap[self.key()]
1303    }
1304
1305    /// Agreement between a [`GhostPointsTo`] and a corresponding [`GhostMapAuth`]
1306    ///
1307    /// Verus might not have full context of the [`GhostMapAuth`] and a corresponding [`GhostPointsTo`].
1308    /// However, whenever we know that they refer to the same resource (i.e., have matching ids) we
1309    /// can assert that the [`GhostPointsTo`] is a key-value pair in the [`GhostMapAuth`].
1310    /// ```
1311    /// proof fn test(tracked &auth: GhostMapAuth<int, int>, tracked &pt: GhostPointsTo<int, int>)
1312    ///     requires
1313    ///         auth.id() == sub.id(),
1314    ///         pt@ == (1int, 1int)
1315    ///     ensures
1316    ///         auth[1int] == 1int
1317    /// {
1318    ///     pt.agree(auth);
1319    ///     assert(auth[1int] == 1int);
1320    /// }
1321    /// ```
1322    pub proof fn agree(tracked self: &GhostPointsTo<K, V>, tracked auth: &GhostMapAuth<K, V>)
1323        requires
1324            self.id() == auth.id(),
1325        ensures
1326            auth@.contains_pair(self.key(), self.value()),
1327    {
1328        use_type_invariant(self);
1329        use_type_invariant(auth);
1330
1331        self.lemma_map_view();
1332        self.submap.agree(auth);
1333        assert(self.submap@ <= auth@);
1334        assert(self.submap@.dom().contains(self.key()));
1335        assert(auth@.dom().contains(self.key()));
1336        assert(self.submap@[self.key()] == self.value());
1337        assert(auth@[self.key()] == self.value());
1338    }
1339
1340    /// We can combine two [`GhostPointsTo`]s into a [`GhostSubmap`]
1341    /// We also learn that they were disjoint.
1342    pub proof fn combine(tracked self, tracked other: GhostPointsTo<K, V>) -> (tracked r:
1343        GhostSubmap<K, V>)
1344        requires
1345            self.id() == other.id(),
1346        ensures
1347            r.id() == self.id(),
1348            r@ == map![self.key() => self.value(), other.key() => other.value()],
1349            self.key() != other.key(),
1350    {
1351        use_type_invariant(&self);
1352        use_type_invariant(&other);
1353
1354        let tracked mut submap = self.submap();
1355        submap.combine_points_to(other);
1356
1357        submap
1358    }
1359
1360    /// Shows that if a two [`GhostPointsTo`]s are not owning the same key
1361    pub proof fn disjoint(tracked &mut self, tracked other: &GhostPointsTo<K, V>)
1362        requires
1363            old(self).id() == other.id(),
1364        ensures
1365            final(self).id() == old(self).id(),
1366            final(self)@ == old(self)@,
1367            final(self).key() != other.key(),
1368    {
1369        use_type_invariant(&*self);
1370        use_type_invariant(other);
1371        self.submap.disjoint(&other.submap);
1372    }
1373
1374    /// Shows that if a [`GhostPointsTo`] and a [`GhostSubmap`] are not owning the same key
1375    pub proof fn disjoint_submap(tracked &mut self, tracked other: &GhostSubmap<K, V>)
1376        requires
1377            old(self).id() == other.id(),
1378        ensures
1379            final(self).id() == old(self).id(),
1380            final(self)@ == old(self)@,
1381            !other.dom().contains(final(self).key()),
1382    {
1383        use_type_invariant(&*self);
1384        use_type_invariant(other);
1385        self.submap.disjoint(other);
1386    }
1387
1388    /// Shows that if a [`GhostPointsTo`] and a [`GhostPersistentSubmap`] are not owning the same key
1389    pub proof fn disjoint_persistent_submap(
1390        tracked &mut self,
1391        tracked other: &GhostPersistentSubmap<K, V>,
1392    )
1393        requires
1394            old(self).id() == other.id(),
1395        ensures
1396            final(self).id() == old(self).id(),
1397            final(self)@ == old(self)@,
1398            !other.dom().contains(final(self).key()),
1399    {
1400        use_type_invariant(&*self);
1401        use_type_invariant(other);
1402        self.submap.disjoint_persistent(other);
1403    }
1404
1405    /// Shows that if a [`GhostPointsTo`] and a [`GhostPersistentPointsTo`] are not owning the same key
1406    pub proof fn disjoint_persistent(
1407        tracked &mut self,
1408        tracked other: &GhostPersistentPointsTo<K, V>,
1409    )
1410        requires
1411            old(self).id() == other.id(),
1412        ensures
1413            final(self).id() == old(self).id(),
1414            final(self)@ == old(self)@,
1415            final(self).key() != other.key(),
1416    {
1417        use_type_invariant(&*self);
1418        use_type_invariant(other);
1419        self.submap.disjoint_persistent_points_to(other);
1420    }
1421
1422    /// Update pointed to value
1423    pub proof fn update(tracked &mut self, tracked auth: &mut GhostMapAuth<K, V>, v: V)
1424        requires
1425            old(self).id() == old(auth).id(),
1426        ensures
1427            final(self).id() == old(self).id(),
1428            final(auth).id() == old(auth).id(),
1429            final(self).key() == old(self).key(),
1430            final(self)@ == (final(self).key(), v),
1431            final(auth)@ == old(auth)@.union_prefer_right(map![final(self).key() => v]),
1432    {
1433        broadcast use lemma_submap_of_trans;
1434        broadcast use lemma_submap_of_op;
1435
1436        use_type_invariant(&*self);
1437        use_type_invariant(&*auth);
1438
1439        let ghost old_dom = self.submap.dom();
1440        self.lemma_map_view();
1441        let m = map![self.key() => v];
1442        assert(self.submap@.union_prefer_right(m) == m);
1443        self.submap.update(auth, m);
1444    }
1445
1446    /// Convert the [`GhostPointsTo`] a [`GhostSubmap`]
1447    pub proof fn submap(tracked self) -> (tracked r: GhostSubmap<K, V>)
1448        ensures
1449            r.id() == self.id(),
1450            r@ == map![self.key() => self.value()],
1451    {
1452        self.lemma_map_view();
1453        self.submap
1454    }
1455
1456    proof fn lemma_map_view(tracked &self)
1457        ensures
1458            self.submap@ == map![self.key() => self.value()],
1459    {
1460        use_type_invariant(self);
1461        let key = self.key();
1462        let target_dom = set![key];
1463
1464        assert(self.submap@.dom().len() == 1);
1465        assert(target_dom.len() == 1);
1466
1467        assert(self.submap@.dom().contains(key));
1468        assert(target_dom.contains(key));
1469
1470        assert(self.submap@.dom().remove(key).len() == 0);
1471        assert(target_dom.remove(key).len() == 0);
1472
1473        assert(self.submap@.dom() =~= target_dom);
1474        assert(self.submap@ == map![self.key() => self.value()]);
1475    }
1476
1477    /// Can be used to learn what the key-value pair of [`GhostPointsTo`] is
1478    pub proof fn lemma_view(self)
1479        ensures
1480            self@ == (self.key(), self.value()),
1481    {
1482    }
1483
1484    /// Convert a [`GhostPointsTo`] into a [`GhostPersistentPointsTo`]
1485    pub proof fn persist(tracked self) -> (tracked r: GhostPersistentPointsTo<K, V>)
1486        ensures
1487            self@ == r@,
1488            self.id() == r.id(),
1489    {
1490        use_type_invariant(&self);
1491        self.submap.persist().points_to()
1492    }
1493}
1494
1495impl<K, V> GhostPersistentPointsTo<K, V> {
1496    #[verifier::type_invariant]
1497    spec fn inv(self) -> bool {
1498        self.submap.is_points_to()
1499    }
1500
1501    /// Location of the underlying resource
1502    pub closed spec fn id(self) -> Loc {
1503        self.submap.id()
1504    }
1505
1506    /// Key-Value pair underlying the points to relationship
1507    pub open spec fn view(self) -> (K, V) {
1508        (self.key(), self.value())
1509    }
1510
1511    /// Key of the points to
1512    pub closed spec fn key(self) -> K {
1513        self.submap.dom().choose()
1514    }
1515
1516    /// Pointed-to value
1517    pub closed spec fn value(self) -> V {
1518        self.submap[self.key()]
1519    }
1520
1521    /// Duplicate the [`GhostPersistentPointsTo`]
1522    pub proof fn duplicate(tracked &self) -> (tracked result: GhostPersistentPointsTo<K, V>)
1523        ensures
1524            result.id() == self.id(),
1525            result@ == self@,
1526    {
1527        use_type_invariant(&*self);
1528        let tracked submap = self.submap.duplicate();
1529        GhostPersistentPointsTo { submap }
1530    }
1531
1532    /// Agreement between a [`GhostPersistentPointsTo`] and a corresponding [`GhostMapAuth`]
1533    ///
1534    /// Verus might not have full context of the [`GhostMapAuth`] and a corresponding [`GhostPersistentPointsTo`].
1535    /// However, whenever we know that they refer to the same resource (i.e., have matching ids) we
1536    /// can assert that the [`GhostPersistentPointsTo`] is a key-value pair in the [`GhostMapAuth`].
1537    /// ```
1538    /// proof fn test(tracked &auth: GhostMapAuth<int, int>, tracked &pt: GhostPersistentPointsTo<int, int>)
1539    ///     requires
1540    ///         auth.id() == sub.id(),
1541    ///         pt@ == (1int, 1int)
1542    ///     ensures
1543    ///         auth[1int] == 1int
1544    /// {
1545    ///     pt.agree(auth);
1546    ///     assert(auth[1int] == 1int);
1547    /// }
1548    /// ```
1549    pub proof fn agree(
1550        tracked self: &GhostPersistentPointsTo<K, V>,
1551        tracked auth: &GhostMapAuth<K, V>,
1552    )
1553        requires
1554            self.id() == auth.id(),
1555        ensures
1556            auth@.contains_pair(self.key(), self.value()),
1557    {
1558        use_type_invariant(self);
1559        use_type_invariant(auth);
1560
1561        self.lemma_map_view();
1562        self.submap.agree(auth);
1563        assert(self.submap@ <= auth@);
1564        assert(self.submap@.contains_key(self.key()));
1565    }
1566
1567    /// We can combine two [`GhostPersistentPointsTo`]s into a [`GhostPersistentSubmap`]
1568    pub proof fn combine(
1569        tracked self,
1570        tracked other: GhostPersistentPointsTo<K, V>,
1571    ) -> (tracked submap: GhostPersistentSubmap<K, V>)
1572        requires
1573            self.id() == other.id(),
1574        ensures
1575            submap.id() == self.id(),
1576            submap@ == map![self.key() => self.value(), other.key() => other.value()],
1577            self.key() != other.key() ==> submap@.len() == 2,
1578            self.key() == other.key() ==> submap@.len() == 1,
1579    {
1580        use_type_invariant(&self);
1581        use_type_invariant(&other);
1582
1583        let tracked mut submap = self.submap();
1584        submap.combine_points_to(other);
1585
1586        submap
1587    }
1588
1589    /// When we have a [`GhostPersistentPointsTo`] and a [`GhostPointsTo`], we can prove that they are in disjoint
1590    /// domains.
1591    pub proof fn disjoint(tracked &mut self, tracked other: &GhostPointsTo<K, V>)
1592        requires
1593            old(self).id() == other.id(),
1594        ensures
1595            final(self).id() == old(self).id(),
1596            final(self)@ == old(self)@,
1597            final(self).key() != other.key(),
1598    {
1599        use_type_invariant(&*self);
1600        use_type_invariant(other);
1601        self.disjoint_submap(&other.submap);
1602    }
1603
1604    /// When we have a [`GhostPersistentPointsTo`] and a [`GhostSubmap`], we can prove that they are in disjoint
1605    /// domains.
1606    pub proof fn disjoint_submap(tracked &mut self, tracked other: &GhostSubmap<K, V>)
1607        requires
1608            old(self).id() == other.id(),
1609        ensures
1610            final(self).id() == old(self).id(),
1611            final(self)@ == old(self)@,
1612            !other@.contains_key(final(self).key()),
1613    {
1614        use_type_invariant(&*self);
1615        use_type_invariant(other);
1616        self.submap.disjoint(&other);
1617    }
1618
1619    /// Shows that if a client has two [`GhostPersistentPointsTo`]s they are either disjoint or
1620    /// agreeing in values in the intersection
1621    pub proof fn intersection_agrees(
1622        tracked &mut self,
1623        tracked other: &GhostPersistentPointsTo<K, V>,
1624    )
1625        requires
1626            old(self).id() == other.id(),
1627        ensures
1628            final(self).id() == old(self).id(),
1629            final(self)@ == old(self)@,
1630            final(self).key() == other.key() ==> final(self).value() == other.value(),
1631    {
1632        use_type_invariant(&*self);
1633        use_type_invariant(other);
1634        self.submap.intersection_agrees_points_to(&other);
1635    }
1636
1637    /// Shows that if a [`GhostPersistentPointsTo`] and a [`GhostSubmap`] are not owning the same key
1638    pub proof fn intersection_agrees_submap(
1639        tracked &mut self,
1640        tracked other: &GhostPersistentSubmap<K, V>,
1641    )
1642        requires
1643            old(self).id() == other.id(),
1644        ensures
1645            final(self).id() == old(self).id(),
1646            final(self)@ == old(self)@,
1647            other@.contains_key(final(self).key()) ==> other@[final(self).key()]
1648                == final(self).value(),
1649    {
1650        use_type_invariant(&*self);
1651        use_type_invariant(other);
1652        self.submap.intersection_agrees(other);
1653    }
1654
1655    /// Convert the [`GhostPersistentPointsTo`] a [`GhostPersistentSubmap`]
1656    pub proof fn submap(tracked self) -> (tracked r: GhostPersistentSubmap<K, V>)
1657        ensures
1658            r.id() == self.id(),
1659            r@ == map![self.key() => self.value()],
1660    {
1661        self.lemma_map_view();
1662        self.submap
1663    }
1664
1665    proof fn lemma_map_view(tracked &self)
1666        ensures
1667            self.submap@ == map![self.key() => self.value()],
1668    {
1669        use_type_invariant(self);
1670        let key = self.key();
1671        let target_dom = set![key];
1672
1673        assert(self.submap@.dom().len() == 1);
1674        assert(target_dom.len() == 1);
1675
1676        assert(self.submap@.dom().contains(key));
1677        assert(target_dom.contains(key));
1678
1679        assert(self.submap@.dom().remove(key).len() == 0);
1680        assert(target_dom.remove(key).len() == 0);
1681
1682        assert(self.submap@.dom() =~= target_dom);
1683        assert(self.submap@ == map![self.key() => self.value()]);
1684    }
1685
1686    /// Can be used to learn what the key-value pair of [`GhostPersistentPointsTo`] is
1687    pub proof fn lemma_view(self)
1688        ensures
1689            self@ == (self.key(), self.value()),
1690    {
1691    }
1692}
1693
1694} // verus!