Skip to main content

vstd/resource/
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::imap::*;
77use super::super::imap_lib::*;
78use super::super::iset_lib::*;
79use super::super::modes::*;
80use super::super::prelude::*;
81use super::Loc;
82use super::algebra::ResourceAlgebra;
83#[cfg(verus_keep_ghost)]
84use super::incorporate;
85use super::pcm::PCM;
86use super::pcm::Resource;
87#[cfg(verus_keep_ghost)]
88use super::split_mut;
89
90verus! {
91
92broadcast use {super::super::group_vstd_default, super::super::imap::group_imap_lemmas};
93
94#[verifier::reject_recursive_types(K)]
95#[verifier::ext_equal]
96enum AuthCarrier<K, V> {
97    Auth(IMap<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: IMap<K, V>, dup: IMap<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) -> IMap<K, V>
115        recommends
116            self.valid(),
117    {
118        match self {
119            AuthCarrier::Auth(m) => m,
120            AuthCarrier::Frac => IMap::empty(),
121            AuthCarrier::Invalid => IMap::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) -> IMap<K, V> {
135        match self {
136            FracCarrier::Frac { owning, .. } => owning,
137            FracCarrier::Invalid => IMap::empty(),
138        }
139    }
140
141    spec fn dup_map(self) -> IMap<K, V> {
142        match self {
143            FracCarrier::Frac { dup, .. } => dup,
144            FracCarrier::Invalid => IMap::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_iset_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: IMap::empty(), dup: IMap::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: IMap::<K, V>::empty(),
360            dup: IMap::<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 [`IMap`]
370    pub closed spec fn view(self) -> IMap<K, V> {
371        self.r.value().auth.map()
372    }
373
374    /// Domain of the [`GhostMapAuth`]
375    pub open spec fn dom(self) -> ISet<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(IMap::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@ == IMap::<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 [`IMap`] 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: IMap<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: IMap::empty() },
451        };
452
453        assert(full_carrier.valid());
454        let tracked updated_r = self_r.update(full_carrier);
455
456        let auth_carrier = MapCarrier {
457            auth: updated_r.value().auth,
458            frac: FracCarrier::Frac { owning: IMap::empty(), dup: IMap::empty() },
459        };
460        let frac_carrier = MapCarrier { auth: AuthCarrier::Frac, frac: updated_r.value().frac };
461
462        assert(updated_r.value() == MapCarrier::op(auth_carrier, frac_carrier));
463        let tracked (auth_r, frac_r) = updated_r.split(auth_carrier, frac_carrier);
464        self.r = auth_r;
465        GhostSubmap { r: frac_r }
466    }
467
468    /// Insert a key-value pair, receiving the [`GhostPointsTo`] that asserts ownerships over the key.
469    ///
470    /// ```
471    /// proof fn insert_example(tracked mut m: GhostMapAuth<int, int>) -> (tracked r: GhostPointsTo<int, int>)
472    ///     requires
473    ///         !m.dom().contains(1int),
474    /// {
475    ///     let tracked points_to = m.insert(1, 1);
476    ///     // do something with the points_to
477    ///     points_to
478    /// }
479    /// ```
480    pub proof fn insert(tracked &mut self, k: K, v: V) -> (tracked result: GhostPointsTo<K, V>)
481        requires
482            !old(self)@.contains_key(k),
483        ensures
484            final(self).id() == old(self).id(),
485            final(self)@ == old(self)@.insert(k, v),
486            result.id() == final(self).id(),
487            result@ == (k, v),
488    {
489        let tracked submap = self.insert_map(imap![k => v]);
490        GhostPointsTo { submap }
491    }
492
493    /// Delete a set of keys
494    /// ```
495    /// proof fn delete(tracked mut auth: GhostMapAuth<int, int>)
496    ///     requires
497    ///         auth.dom().contains(1int),
498    ///         auth.dom().contains(2int),
499    ///     ensures
500    ///         old(auth)@ == auth@
501    /// {
502    ///     let tracked submap = auth.insert_map(map![1int => 1int, 2int => 4int]);
503    ///     // do something with the submap
504    ///     auth.delete(submap)
505    /// }
506    /// ```
507    pub proof fn delete(tracked &mut self, tracked submap: GhostSubmap<K, V>)
508        requires
509            submap.id() == old(self).id(),
510        ensures
511            final(self).id() == old(self).id(),
512            final(self)@ == old(self)@.remove_keys(submap@.dom()),
513    {
514        broadcast use lemma_submap_of_trans;
515        broadcast use lemma_submap_of_op;
516
517        use_type_invariant(&*self);
518        use_type_invariant(&submap);
519
520        let tracked mut mself = Self::dummy();
521        tracked_swap(self, &mut mself);
522        let tracked mut self_r = mself.r;
523
524        // join the resource with the original carrier
525        self_r = self_r.join(submap.r);
526
527        // remove keys from the map
528        let auth_map = self_r.value().auth.map();
529        let new_auth_map = auth_map.remove_keys(submap@.dom());
530
531        let new_r = MapCarrier {
532            auth: AuthCarrier::Auth(new_auth_map),
533            frac: FracCarrier::Frac { owning: IMap::empty(), dup: IMap::empty() },
534        };
535
536        // update the resource
537        self.r = self_r.update(new_r);
538    }
539
540    /// Delete a single key from the map
541    /// ```
542    /// proof fn delete_key(tracked mut auth: GhostMapAuth<int, int>)
543    ///     requires
544    ///         auth.dom().contains(1int),
545    ///     ensures
546    ///         old(auth)@ == auth@
547    /// {
548    ///     let tracked points_to = auth.insert(1, 1);
549    ///     // do something with the submap
550    ///     auth.delete_points_to(points_to)
551    /// }
552    /// ```
553    pub proof fn delete_points_to(tracked &mut self, tracked p: GhostPointsTo<K, V>)
554        requires
555            p.id() == old(self).id(),
556        ensures
557            final(self).id() == old(self).id(),
558            final(self)@ == old(self)@.remove(p.key()),
559    {
560        use_type_invariant(&p);
561        p.lemma_map_view();
562        self.delete(p.submap);
563    }
564
565    /// Create a new [`GhostMapAuth`] from an [`IMap`].
566    /// Gives the other half of ownership in the form of a [`GhostSubmap`].
567    ///
568    /// ```
569    /// fn example() {
570    ///     let m = map![1int => 1int, 2int => 4int, 3int => 9int];
571    ///     let tracked (auth, sub) = GhostMapAuth::new(m);
572    ///     assert(auth@ == m);
573    ///     assert(sub.dom() == m.dom());
574    /// }
575    /// ```
576    pub proof fn new(m: IMap<K, V>) -> (tracked result: (GhostMapAuth<K, V>, GhostSubmap<K, V>))
577        ensures
578            result.0.id() == result.1.id(),
579            result.0@ == m,
580            result.1@ == m,
581    {
582        let tracked full_r = Resource::alloc(
583            MapCarrier {
584                auth: AuthCarrier::Auth(m),
585                frac: FracCarrier::Frac { owning: m, dup: IMap::empty() },
586            },
587        );
588
589        let auth_carrier = MapCarrier {
590            auth: AuthCarrier::Auth(m),
591            frac: FracCarrier::Frac { owning: IMap::empty(), dup: IMap::empty() },
592        };
593
594        let frac_carrier = MapCarrier {
595            auth: AuthCarrier::Frac,
596            frac: FracCarrier::Frac { owning: m, dup: IMap::empty() },
597        };
598
599        assert(full_r.value() == MapCarrier::op(auth_carrier, frac_carrier));
600        let tracked (auth_r, frac_r) = full_r.split(auth_carrier, frac_carrier);
601        (GhostMapAuth { r: auth_r }, GhostSubmap { r: frac_r })
602    }
603}
604
605impl<K, V> GhostSubmap<K, V> {
606    #[verifier::type_invariant]
607    spec fn inv(self) -> bool {
608        &&& self.r.value().auth is Frac
609        &&& self.r.value().frac is Frac
610        &&& self.r.value().frac.dup_map().is_empty()
611    }
612
613    /// Checks whether the [`GhostSubmap`] refers to a single key (and thus can be converted to a
614    /// [`GhostPointsTo`]).
615    pub open spec fn is_points_to(self) -> bool {
616        &&& self@.len() == 1
617        &&& self.dom().finite()
618        &&& !self@.is_empty()
619    }
620
621    /// Resource location
622    pub closed spec fn id(self) -> Loc {
623        self.r.loc()
624    }
625
626    /// Logically underlying [`IMap`]
627    pub closed spec fn view(self) -> IMap<K, V> {
628        self.r.value().frac.owning_map()
629    }
630
631    /// Domain of the [`GhostSubmap`]
632    pub open spec fn dom(self) -> ISet<K> {
633        self@.dom()
634    }
635
636    /// Indexing operation `submap[key]`
637    pub open spec fn spec_index(self, key: K) -> V
638        recommends
639            self.dom().contains(key),
640    {
641        self@[key]
642    }
643
644    /// Instantiate a dummy [`GhostSubmap`]
645    pub proof fn dummy() -> (tracked result: GhostSubmap<K, V>) {
646        let tracked (auth, submap) = GhostMapAuth::<K, V>::new(IMap::empty());
647        submap
648    }
649
650    /// Create an empty [`GhostSubmap`]
651    pub proof fn empty(tracked &self) -> (tracked result: GhostSubmap<K, V>)
652        ensures
653            result.id() == self.id(),
654            result@ == IMap::<K, V>::empty(),
655    {
656        use_type_invariant(self);
657        let tracked r = Resource::<MapCarrier<_, _>>::create_unit(self.r.loc());
658        GhostSubmap { r }
659    }
660
661    /// Extract the [`GhostSubmap`] from a mutable reference, leaving behind an empty map.
662    pub proof fn take(tracked &mut self) -> (tracked result: GhostSubmap<K, V>)
663        ensures
664            old(self).id() == final(self).id(),
665            final(self)@.is_empty(),
666            result == *old(self),
667            result.id() == final(self).id(),
668    {
669        use_type_invariant(&*self);
670
671        let tracked mut r = self.empty();
672        tracked_swap(self, &mut r);
673        r
674    }
675
676    /// Agreement between a [`GhostSubmap`] and a corresponding [`GhostMapAuth`]
677    ///
678    /// Verus might not have full context of the [`GhostMapAuth`] and a corresponding [`GhostSubmap`].
679    /// However, whenever we know that they refer to the same resource (i.e., have matching ids) we
680    /// can assert that the [`GhostSubmap`] is a submap of the [`GhostMapAuth`].
681    /// ```
682    /// proof fn test(tracked &auth: GhostMapAuth<int, int>, tracked &sub: GhostSubmap<int, int>)
683    ///     requires
684    ///         auth.id() == sub.id(),
685    ///         sub.dom().contains(1int),
686    ///         sub[1int] == 1int,
687    ///     ensures
688    ///         auth[1int] == 1int
689    /// {
690    ///     sub.agree(auth);
691    ///     assert(sub@ <= auth@);
692    ///     assert(auth[1int] == 1int);
693    /// }
694    /// ```
695    pub proof fn agree(tracked self: &GhostSubmap<K, V>, tracked auth: &GhostMapAuth<K, V>)
696        requires
697            self.id() == auth.id(),
698        ensures
699            self@ <= auth@,
700    {
701        broadcast use lemma_submap_of_trans;
702
703        use_type_invariant(self);
704        use_type_invariant(auth);
705
706        let tracked joined = self.r.join_shared(&auth.r);
707        joined.validate();
708        assert(self.r.value().frac.owning_map() <= joined.value().frac.owning_map());
709    }
710
711    /// Combining two [`GhostSubmap`]s is possible.
712    /// We consume the input [`GhostSubmap`] and merge it into the first.
713    /// We also learn that they were disjoint.
714    pub proof fn combine(tracked &mut self, tracked other: GhostSubmap<K, V>)
715        requires
716            old(self).id() == other.id(),
717        ensures
718            final(self).id() == old(self).id(),
719            final(self)@ == old(self)@.union_prefer_right(other@),
720            old(self)@.dom().disjoint(other@.dom()),
721    {
722        use_type_invariant(&*self);
723        use_type_invariant(&other);
724
725        self.r.validate_2(&other.r);
726        incorporate(&mut self.r, other.r);
727    }
728
729    /// Combining a [`GhostPointsTo`] into [`GhostSubmap`] is possible, in a similar way to the way to combine
730    /// [`GhostSubmap`]s.
731    pub proof fn combine_points_to(tracked &mut self, tracked other: GhostPointsTo<K, V>)
732        requires
733            old(self).id() == other.id(),
734        ensures
735            final(self).id() == old(self).id(),
736            final(self)@ == old(self)@.insert(other.key(), other.value()),
737            !old(self)@.contains_key(other.key()),
738    {
739        use_type_invariant(&*self);
740        use_type_invariant(&other);
741
742        other.lemma_map_view();
743        self.combine(other.submap);
744    }
745
746    /// When we have two [`GhostSubmap`]s we can prove that they have disjoint domains.
747    pub proof fn disjoint(tracked &mut self, tracked other: &GhostSubmap<K, V>)
748        requires
749            old(self).id() == other.id(),
750        ensures
751            final(self).id() == old(self).id(),
752            final(self)@ == old(self)@,
753            final(self)@.dom().disjoint(other@.dom()),
754    {
755        use_type_invariant(&*self);
756        use_type_invariant(other);
757        self.r.validate_2(&other.r);
758    }
759
760    /// When we have a [`GhostSubmap`] and a [`GhostPersistentSubmap`] we can prove that they are in disjoint
761    /// domains.
762    pub proof fn disjoint_persistent(tracked &mut self, tracked other: &GhostPersistentSubmap<K, V>)
763        requires
764            old(self).id() == other.id(),
765        ensures
766            final(self).id() == old(self).id(),
767            final(self)@ == old(self)@,
768            final(self)@.dom().disjoint(other@.dom()),
769    {
770        use_type_invariant(&*self);
771        use_type_invariant(other);
772        self.r.validate_2(&other.r);
773    }
774
775    /// When we have a [`GhostSubmap`] and a [`GhostPointsTo`] we can prove that they are in disjoint
776    /// domains.
777    pub proof fn disjoint_points_to(tracked &mut self, tracked other: &GhostPointsTo<K, V>)
778        requires
779            old(self).id() == other.id(),
780        ensures
781            final(self).id() == old(self).id(),
782            final(self)@ == old(self)@,
783            !final(self)@.contains_key(other.key()),
784    {
785        use_type_invariant(&*self);
786        use_type_invariant(other);
787        self.disjoint(&other.submap);
788    }
789
790    /// When we have a [`GhostSubmap`] and a [`GhostPersistentPointsTo`] we can prove that they are in disjoint
791    /// domains.
792    pub proof fn disjoint_persistent_points_to(
793        tracked &mut self,
794        tracked other: &GhostPersistentPointsTo<K, V>,
795    )
796        requires
797            old(self).id() == other.id(),
798        ensures
799            final(self).id() == old(self).id(),
800            final(self)@ == old(self)@,
801            !final(self)@.contains_key(other.key()),
802    {
803        use_type_invariant(&*self);
804        use_type_invariant(other);
805        self.disjoint_persistent(&other.submap);
806    }
807
808    /// We can split a [`GhostSubmap`] based on a set of keys in its domain.
809    pub proof fn split(tracked &mut self, s: ISet<K>) -> (tracked result: GhostSubmap<K, V>)
810        requires
811            s <= old(self)@.dom(),
812        ensures
813            final(self).id() == old(self).id(),
814            result.id() == final(self).id(),
815            old(self)@ == final(self)@.union_prefer_right(result@),
816            result@.dom() =~= s,
817            final(self)@.dom() =~= old(self)@.dom() - s,
818    {
819        use_type_invariant(&*self);
820
821        let self_carrier = MapCarrier {
822            auth: AuthCarrier::Frac,
823            frac: FracCarrier::Frac {
824                owning: self.r.value().frac.owning_map().remove_keys(s),
825                dup: self.r.value().frac.dup_map(),
826            },
827        };
828
829        let res_carrier = MapCarrier {
830            auth: AuthCarrier::Frac,
831            frac: FracCarrier::Frac {
832                owning: self.r.value().frac.owning_map().restrict(s),
833                dup: self.r.value().frac.dup_map(),
834            },
835        };
836
837        assert(self.r.value().frac == MapCarrier::op(self_carrier, res_carrier).frac);
838        let tracked r = split_mut(&mut self.r, self_carrier, res_carrier);
839        GhostSubmap { r }
840    }
841
842    pub proof fn split_with_olddom(
843        tracked &mut self,
844        s: ISet<K>,
845        olddom: ISet<K>,
846    ) -> (tracked result: GhostSubmap<K, V>)
847        requires
848            olddom == old(self)@.dom(),
849            s <= olddom,
850        ensures
851            final(self).id() == old(self).id(),
852            result.id() == final(self).id(),
853            old(self)@ == final(self)@.union_prefer_right(result@),
854            result@.dom() == s,
855            final(self)@.dom() == olddom - s,
856    {
857        let tracked out = self.split(s);
858        assert(olddom == old(self)@.dom());
859        assert(self@.dom() == old(self)@.dom() - s);
860        assert(self@.dom() == olddom - s);
861        assert(out@.dom() == s);
862        out
863    }
864
865    /// We can separate a single key out of a [`GhostSubmap`]
866    pub proof fn split_points_to(tracked &mut self, k: K) -> (tracked result: GhostPointsTo<K, V>)
867        requires
868            old(self)@.contains_key(k),
869        ensures
870            final(self).id() == old(self).id(),
871            result.id() == final(self).id(),
872            old(self)@ == final(self)@.insert(result.key(), result.value()),
873            result.key() == k,
874            final(self)@ == old(self)@.remove(k),
875    {
876        use_type_invariant(&*self);
877
878        let tracked submap = self.split(iset![k]);
879        GhostPointsTo { submap }
880    }
881
882    /// When we have both the [`GhostMapAuth`] and a [`GhostSubmap`] we can update the values for a
883    /// subset of keys in our submap.
884    /// ```
885    /// proof fn test(tracked auth: &mut GhostMapAuth<int, int>, tracked sub: &mut GhostSubmap<int, int>)
886    ///     requires
887    ///         auth.id() == sub.id(),
888    ///         sub.dom() == set![1int, 2int, 3int]
889    ///     ensures
890    ///         auth[1int] == 9int
891    ///         auth[2int] == 10int
892    ///         auth[3int] == 11int
893    /// {
894    ///     // need to agree on the subset
895    ///     sub.agree(auth);
896    ///     assert(sub@ <= auth@);
897    ///     sub.update(map![1int => 9int, 2int => 10int, 3int => 11int]);
898    /// }
899    /// ```
900    pub proof fn update(tracked &mut self, tracked auth: &mut GhostMapAuth<K, V>, m: IMap<K, V>)
901        requires
902            m.dom() <= old(self)@.dom(),
903            old(self).id() == old(auth).id(),
904        ensures
905            final(self).id() == old(self).id(),
906            final(auth).id() == old(auth).id(),
907            final(self)@ == old(self)@.union_prefer_right(m),
908            final(auth)@ == old(auth)@.union_prefer_right(m),
909    {
910        broadcast use lemma_submap_of_trans;
911        broadcast use lemma_submap_of_op;
912
913        use_type_invariant(&*self);
914        use_type_invariant(&*auth);
915
916        let tracked mut mself = Self::dummy();
917        tracked_swap(self, &mut mself);
918        let tracked mut frac_r = mself.r;
919
920        let tracked mut mauth = GhostMapAuth::<K, V>::dummy();
921        tracked_swap(auth, &mut mauth);
922        let tracked mut auth_r = mauth.r;
923
924        frac_r.validate_2(&auth_r);
925        let tracked mut full_r = frac_r.join(auth_r);
926
927        assert(full_r.value().frac.owning_map() == frac_r.value().frac.owning_map());
928
929        let auth_carrier = AuthCarrier::Auth(full_r.value().auth.map().union_prefer_right(m));
930        let frac_carrier = FracCarrier::Frac {
931            owning: full_r.value().frac.owning_map().union_prefer_right(m),
932            dup: IMap::empty(),
933        };
934        let new_full_carrier = MapCarrier { auth: auth_carrier, frac: frac_carrier };
935
936        assert(new_full_carrier.valid());
937        let tracked r_upd = full_r.update(new_full_carrier);
938
939        let new_auth_carrier = MapCarrier {
940            auth: r_upd.value().auth,
941            frac: FracCarrier::Frac { owning: IMap::empty(), dup: IMap::empty() },
942        };
943        let new_frac_carrier = MapCarrier { auth: AuthCarrier::Frac, frac: r_upd.value().frac };
944        assert(r_upd.value().frac == MapCarrier::op(new_auth_carrier, new_frac_carrier).frac);
945        assert(r_upd.value() == MapCarrier::op(new_auth_carrier, new_frac_carrier));
946
947        let tracked (new_auth_r, new_frac_r) = r_upd.split(new_auth_carrier, new_frac_carrier);
948        auth.r = new_auth_r;
949        self.r = new_frac_r;
950    }
951
952    /// Converting a [`GhostSubmap`] into a [`GhostPointsTo`]
953    pub proof fn points_to(tracked self) -> (tracked r: GhostPointsTo<K, V>)
954        requires
955            self.is_points_to(),
956        ensures
957            self@ == imap![r.key() => r.value()],
958            self.id() == r.id(),
959    {
960        let tracked r = GhostPointsTo { submap: self };
961        r.lemma_map_view();
962        r
963    }
964
965    /// Convert a [`GhostSubmap`] into a [`GhostPersistentSubmap`]
966    pub proof fn persist(tracked self) -> (tracked r: GhostPersistentSubmap<K, V>)
967        ensures
968            self@ == r@,
969            self.id() == r.id(),
970    {
971        broadcast use lemma_submap_of_trans;
972        broadcast use lemma_submap_of_op;
973
974        use_type_invariant(&self);
975
976        let tracked mut r = self.r;
977
978        let self_carrier = MapCarrier {
979            auth: AuthCarrier::Frac,
980            frac: FracCarrier::Frac {
981                owning: self.r.value().frac.owning_map(),
982                dup: self.r.value().frac.dup_map(),
983            },
984        };
985
986        let res_carrier = MapCarrier {
987            auth: AuthCarrier::Frac,
988            frac: FracCarrier::Frac {
989                owning: self.r.value().frac.dup_map(),
990                dup: self.r.value().frac.owning_map(),
991            },
992        };
993
994        let tracked r = r.update(res_carrier);
995        GhostPersistentSubmap { r }
996    }
997}
998
999impl<K, V> GhostPersistentSubmap<K, V> {
1000    #[verifier::type_invariant]
1001    spec fn inv(self) -> bool {
1002        &&& self.r.value().auth is Frac
1003        &&& self.r.value().frac is Frac
1004        &&& self.r.value().frac.owning_map().is_empty()
1005    }
1006
1007    /// Checks whether the [`GhostPersistentSubmap`] refers to a single key (and thus can be converted to a
1008    /// [`GhostPersistentPointsTo`]).
1009    pub open spec fn is_points_to(self) -> bool {
1010        &&& self@.len() == 1
1011        &&& self.dom().finite()
1012        &&& !self@.is_empty()
1013    }
1014
1015    /// Resource location
1016    pub closed spec fn id(self) -> Loc {
1017        self.r.loc()
1018    }
1019
1020    /// Logically underlying [`IMap`]
1021    pub closed spec fn view(self) -> IMap<K, V> {
1022        self.r.value().frac.dup_map()
1023    }
1024
1025    /// Domain of the [`GhostPersistentSubmap`]
1026    pub open spec fn dom(self) -> ISet<K> {
1027        self@.dom()
1028    }
1029
1030    /// Indexing operation `submap[key]`
1031    pub open spec fn spec_index(self, key: K) -> V
1032        recommends
1033            self.dom().contains(key),
1034    {
1035        self@[key]
1036    }
1037
1038    /// Instantiate a dummy [`GhostPersistentSubmap`]
1039    pub proof fn dummy() -> (tracked result: GhostPersistentSubmap<K, V>) {
1040        let tracked owned = GhostSubmap::<K, V>::dummy();
1041        owned.persist()
1042    }
1043
1044    /// Create an empty [`GhostPersistentSubmap`]
1045    pub proof fn empty(tracked &self) -> (tracked result: GhostPersistentSubmap<K, V>)
1046        ensures
1047            result.id() == self.id(),
1048            result@ == IMap::<K, V>::empty(),
1049    {
1050        use_type_invariant(self);
1051        let tracked r = Resource::<MapCarrier<_, _>>::create_unit(self.r.loc());
1052        GhostSubmap { r }.persist()
1053    }
1054
1055    /// Duplicate the [`GhostPersistentSubmap`]
1056    pub proof fn duplicate(tracked &self) -> (tracked result: GhostPersistentSubmap<K, V>)
1057        ensures
1058            result.id() == self.id(),
1059            result@ == self@,
1060    {
1061        use_type_invariant(&*self);
1062
1063        assert(MapCarrier::op(self.r.value(), self.r.value()) == self.r.value());
1064        let tracked r = super::lib::duplicate(&self.r);
1065
1066        GhostPersistentSubmap { r }
1067    }
1068
1069    /// Agreement between a [`GhostPersistentSubmap`] and a corresponding [`GhostMapAuth`]
1070    ///
1071    /// Verus might not have full context of the [`GhostMapAuth`] and a corresponding [`GhostPersistentSubmap`].
1072    /// However, whenever we know that they refer to the same resource (i.e., have matching ids) we
1073    /// can assert that the [`GhostPersistentSubmap`] is a submap of the [`GhostMapAuth`].
1074    /// ```
1075    /// proof fn test(tracked &auth: GhostMapAuth<int, int>, tracked &sub: GhostPersistentSubmap<int, int>)
1076    ///     requires
1077    ///         auth.id() == sub.id(),
1078    ///         sub.dom().contains(1int),
1079    ///         sub[1int] == 1int,
1080    ///     ensures
1081    ///         auth[1int] == 1int
1082    /// {
1083    ///     sub.agree(auth);
1084    ///     assert(sub@ <= auth@);
1085    ///     assert(auth[1int] == 1int);
1086    /// }
1087    /// ```
1088    pub proof fn agree(
1089        tracked self: &GhostPersistentSubmap<K, V>,
1090        tracked auth: &GhostMapAuth<K, V>,
1091    )
1092        requires
1093            self.id() == auth.id(),
1094        ensures
1095            self@ <= auth@,
1096    {
1097        broadcast use lemma_submap_of_trans;
1098
1099        use_type_invariant(self);
1100        use_type_invariant(auth);
1101
1102        let tracked joined = self.r.join_shared(&auth.r);
1103        joined.validate();
1104        assert(self.r.value().frac.dup_map() <= joined.value().frac.dup_map());
1105    }
1106
1107    /// Combining two [`GhostPersistentSubmap`]s is possible.
1108    /// We consume the input [`GhostPersistentSubmap`] and merge it into the first.
1109    /// We also learn that they agreed
1110    pub proof fn combine(tracked &mut self, tracked other: GhostPersistentSubmap<K, V>)
1111        requires
1112            old(self).id() == other.id(),
1113        ensures
1114            final(self).id() == old(self).id(),
1115            final(self)@ == old(self)@.union_prefer_right(other@),
1116            old(self)@.agrees(other@),
1117    {
1118        use_type_invariant(&*self);
1119        use_type_invariant(&other);
1120
1121        self.r.validate_2(&other.r);
1122        incorporate(&mut self.r, other.r);
1123    }
1124
1125    /// Combining a [`GhostPersistentPointsTo`] into [`GhostPersistentSubmap`] is possible, in a similar way to the way to combine
1126    /// [`GhostPersistentSubmap`]s.
1127    pub proof fn combine_points_to(tracked &mut self, tracked other: GhostPersistentPointsTo<K, V>)
1128        requires
1129            old(self).id() == other.id(),
1130        ensures
1131            final(self).id() == old(self).id(),
1132            final(self)@ == old(self)@.insert(other.key(), other.value()),
1133            old(self)@.contains_key(other.key()) ==> old(self)@[other.key()] == other.value(),
1134    {
1135        use_type_invariant(&*self);
1136        use_type_invariant(&other);
1137
1138        other.lemma_map_view();
1139        self.combine(other.submap);
1140    }
1141
1142    /// When we have a [`GhostPersistentSubmap`] and a [`GhostSubmap`] we can prove that they have disjoint domains.
1143    pub proof fn disjoint(tracked &mut self, tracked other: &GhostSubmap<K, V>)
1144        requires
1145            old(self).id() == other.id(),
1146        ensures
1147            final(self).id() == old(self).id(),
1148            final(self)@ == old(self)@,
1149            final(self)@.dom().disjoint(other@.dom()),
1150    {
1151        use_type_invariant(&*self);
1152        use_type_invariant(other);
1153        self.r.validate_2(&other.r);
1154    }
1155
1156    /// When we have two [`GhostPersistentSubmap`]s we can prove that they agree on their intersection.
1157    pub proof fn intersection_agrees(tracked &mut self, tracked other: &GhostPersistentSubmap<K, V>)
1158        requires
1159            old(self).id() == other.id(),
1160        ensures
1161            final(self).id() == old(self).id(),
1162            final(self)@ == old(self)@,
1163            final(self)@.agrees(other@),
1164    {
1165        use_type_invariant(&*self);
1166        use_type_invariant(other);
1167        self.r.validate_2(&other.r);
1168    }
1169
1170    /// When we have a [`GhostPersistentSubmap`] and a [`GhostPointsTo`] we can prove that they are in disjoint
1171    /// domains.
1172    pub proof fn disjoint_points_to(tracked &mut self, tracked other: &GhostPointsTo<K, V>)
1173        requires
1174            old(self).id() == other.id(),
1175        ensures
1176            final(self).id() == old(self).id(),
1177            final(self)@ == old(self)@,
1178            !final(self)@.contains_key(other.key()),
1179    {
1180        use_type_invariant(&*self);
1181        use_type_invariant(other);
1182        self.disjoint(&other.submap);
1183    }
1184
1185    /// When we have a [`GhostPersistentSubmap`] and a [`GhostPersistentPointsTo`],
1186    /// we can prove that either they are disjoint domains or the key-value pair is in the
1187    /// persistent submap.
1188    pub proof fn intersection_agrees_points_to(
1189        tracked &mut self,
1190        tracked other: &GhostPersistentPointsTo<K, V>,
1191    )
1192        requires
1193            old(self).id() == other.id(),
1194        ensures
1195            final(self).id() == old(self).id(),
1196            final(self)@ == old(self)@,
1197            final(self)@.contains_key(other.key()) ==> final(self)@[other.key()] == other.value(),
1198    {
1199        use_type_invariant(&*self);
1200        use_type_invariant(other);
1201        self.intersection_agrees(&other.submap);
1202    }
1203
1204    /// We can split a [`GhostPersistentSubmap`] based on a set of keys in its domain.
1205    pub proof fn split(tracked &mut self, s: ISet<K>) -> (tracked result: GhostPersistentSubmap<
1206        K,
1207        V,
1208    >)
1209        requires
1210            s <= old(self)@.dom(),
1211        ensures
1212            final(self).id() == old(self).id(),
1213            result.id() == final(self).id(),
1214            old(self)@ == final(self)@.union_prefer_right(result@),
1215            result@.dom() =~= s,
1216            final(self)@.dom() =~= old(self)@.dom() - s,
1217    {
1218        use_type_invariant(&*self);
1219
1220        let tracked mut r = Resource::alloc(MapCarrier::<K, V>::unit());
1221        tracked_swap(&mut self.r, &mut r);
1222
1223        let self_carrier = MapCarrier {
1224            auth: AuthCarrier::Frac,
1225            frac: FracCarrier::Frac {
1226                owning: r.value().frac.owning_map(),
1227                dup: r.value().frac.dup_map().remove_keys(s),
1228            },
1229        };
1230
1231        let res_carrier = MapCarrier {
1232            auth: AuthCarrier::Frac,
1233            frac: FracCarrier::Frac {
1234                owning: r.value().frac.owning_map(),
1235                dup: r.value().frac.dup_map().restrict(s),
1236            },
1237        };
1238
1239        assert(r.value().frac == MapCarrier::op(self_carrier, res_carrier).frac);
1240        let tracked (self_r, res_r) = r.split(self_carrier, res_carrier);
1241        self.r = self_r;
1242        GhostPersistentSubmap { r: res_r }
1243    }
1244
1245    /// We can separate a single key out of a [`GhostPersistentSubmap`]
1246    pub proof fn split_points_to(tracked &mut self, k: K) -> (tracked result:
1247        GhostPersistentPointsTo<K, V>)
1248        requires
1249            old(self)@.contains_key(k),
1250        ensures
1251            final(self).id() == old(self).id(),
1252            result.id() == final(self).id(),
1253            old(self)@ == final(self)@.insert(result.key(), result.value()),
1254            result.key() == k,
1255            final(self)@ == old(self)@.remove(k),
1256    {
1257        use_type_invariant(&*self);
1258
1259        let tracked submap = self.split(iset![k]);
1260        GhostPersistentPointsTo { submap }
1261    }
1262
1263    /// Convert a [`GhostPersistentSubmap`] into a [`GhostPersistentPointsTo`]
1264    pub proof fn points_to(tracked self) -> (tracked r: GhostPersistentPointsTo<K, V>)
1265        requires
1266            self.is_points_to(),
1267        ensures
1268            self@ == imap![r.key() => r.value()],
1269            self.id() == r.id(),
1270    {
1271        let tracked r = GhostPersistentPointsTo { submap: self };
1272        r.lemma_map_view();
1273        r
1274    }
1275}
1276
1277impl<K, V> GhostPointsTo<K, V> {
1278    #[verifier::type_invariant]
1279    spec fn inv(self) -> bool {
1280        self.submap.is_points_to()
1281    }
1282
1283    /// Location of the underlying resource
1284    pub closed spec fn id(self) -> Loc {
1285        self.submap.id()
1286    }
1287
1288    /// Key-Value pair underlying the points to relationship
1289    pub open spec fn view(self) -> (K, V) {
1290        (self.key(), self.value())
1291    }
1292
1293    /// Key of the points to
1294    pub closed spec fn key(self) -> K {
1295        self.submap.dom().choose()
1296    }
1297
1298    /// Pointed-to value
1299    pub closed spec fn value(self) -> V {
1300        self.submap[self.key()]
1301    }
1302
1303    /// Agreement between a [`GhostPointsTo`] and a corresponding [`GhostMapAuth`]
1304    ///
1305    /// Verus might not have full context of the [`GhostMapAuth`] and a corresponding [`GhostPointsTo`].
1306    /// However, whenever we know that they refer to the same resource (i.e., have matching ids) we
1307    /// can assert that the [`GhostPointsTo`] is a key-value pair in the [`GhostMapAuth`].
1308    /// ```
1309    /// proof fn test(tracked &auth: GhostMapAuth<int, int>, tracked &pt: GhostPointsTo<int, int>)
1310    ///     requires
1311    ///         auth.id() == sub.id(),
1312    ///         pt@ == (1int, 1int)
1313    ///     ensures
1314    ///         auth[1int] == 1int
1315    /// {
1316    ///     pt.agree(auth);
1317    ///     assert(auth[1int] == 1int);
1318    /// }
1319    /// ```
1320    pub proof fn agree(tracked self: &GhostPointsTo<K, V>, tracked auth: &GhostMapAuth<K, V>)
1321        requires
1322            self.id() == auth.id(),
1323        ensures
1324            auth@.contains_pair(self.key(), self.value()),
1325    {
1326        use_type_invariant(self);
1327        use_type_invariant(auth);
1328
1329        self.lemma_map_view();
1330        self.submap.agree(auth);
1331        assert(self.submap@ <= auth@);
1332        assert(self.submap@.dom().contains(self.key()));
1333        assert(auth@.dom().contains(self.key()));
1334        assert(self.submap@[self.key()] == self.value());
1335        assert(auth@[self.key()] == self.value());
1336    }
1337
1338    /// We can combine two [`GhostPointsTo`]s into a [`GhostSubmap`]
1339    /// We also learn that they were disjoint.
1340    pub proof fn combine(tracked self, tracked other: GhostPointsTo<K, V>) -> (tracked r:
1341        GhostSubmap<K, V>)
1342        requires
1343            self.id() == other.id(),
1344        ensures
1345            r.id() == self.id(),
1346            r@ == imap![self.key() => self.value(), other.key() => other.value()],
1347            self.key() != other.key(),
1348    {
1349        use_type_invariant(&self);
1350        use_type_invariant(&other);
1351
1352        let tracked mut submap = self.submap();
1353        submap.combine_points_to(other);
1354
1355        submap
1356    }
1357
1358    /// Shows that if a two [`GhostPointsTo`]s are not owning the same key
1359    pub proof fn disjoint(tracked &mut self, tracked other: &GhostPointsTo<K, V>)
1360        requires
1361            old(self).id() == other.id(),
1362        ensures
1363            final(self).id() == old(self).id(),
1364            final(self)@ == old(self)@,
1365            final(self).key() != other.key(),
1366    {
1367        use_type_invariant(&*self);
1368        use_type_invariant(other);
1369        self.submap.disjoint(&other.submap);
1370    }
1371
1372    /// Shows that if a [`GhostPointsTo`] and a [`GhostSubmap`] are not owning the same key
1373    pub proof fn disjoint_submap(tracked &mut self, tracked other: &GhostSubmap<K, V>)
1374        requires
1375            old(self).id() == other.id(),
1376        ensures
1377            final(self).id() == old(self).id(),
1378            final(self)@ == old(self)@,
1379            !other.dom().contains(final(self).key()),
1380    {
1381        use_type_invariant(&*self);
1382        use_type_invariant(other);
1383        self.submap.disjoint(other);
1384    }
1385
1386    /// Shows that if a [`GhostPointsTo`] and a [`GhostPersistentSubmap`] are not owning the same key
1387    pub proof fn disjoint_persistent_submap(
1388        tracked &mut self,
1389        tracked other: &GhostPersistentSubmap<K, V>,
1390    )
1391        requires
1392            old(self).id() == other.id(),
1393        ensures
1394            final(self).id() == old(self).id(),
1395            final(self)@ == old(self)@,
1396            !other.dom().contains(final(self).key()),
1397    {
1398        use_type_invariant(&*self);
1399        use_type_invariant(other);
1400        self.submap.disjoint_persistent(other);
1401    }
1402
1403    /// Shows that if a [`GhostPointsTo`] and a [`GhostPersistentPointsTo`] are not owning the same key
1404    pub proof fn disjoint_persistent(
1405        tracked &mut self,
1406        tracked other: &GhostPersistentPointsTo<K, V>,
1407    )
1408        requires
1409            old(self).id() == other.id(),
1410        ensures
1411            final(self).id() == old(self).id(),
1412            final(self)@ == old(self)@,
1413            final(self).key() != other.key(),
1414    {
1415        use_type_invariant(&*self);
1416        use_type_invariant(other);
1417        self.submap.disjoint_persistent_points_to(other);
1418    }
1419
1420    /// Update pointed to value
1421    pub proof fn update(tracked &mut self, tracked auth: &mut GhostMapAuth<K, V>, v: V)
1422        requires
1423            old(self).id() == old(auth).id(),
1424        ensures
1425            final(self).id() == old(self).id(),
1426            final(auth).id() == old(auth).id(),
1427            final(self).key() == old(self).key(),
1428            final(self)@ == (final(self).key(), v),
1429            final(auth)@ == old(auth)@.union_prefer_right(imap![final(self).key() => v]),
1430    {
1431        broadcast use lemma_submap_of_trans;
1432        broadcast use lemma_submap_of_op;
1433
1434        use_type_invariant(&*self);
1435        use_type_invariant(&*auth);
1436
1437        let ghost old_dom = self.submap.dom();
1438        self.lemma_map_view();
1439        let m = imap![self.key() => v];
1440        assert(self.submap@.union_prefer_right(m) == m);
1441        self.submap.update(auth, m);
1442    }
1443
1444    /// Convert the [`GhostPointsTo`] a [`GhostSubmap`]
1445    pub proof fn submap(tracked self) -> (tracked r: GhostSubmap<K, V>)
1446        ensures
1447            r.id() == self.id(),
1448            r@ == imap![self.key() => self.value()],
1449    {
1450        self.lemma_map_view();
1451        self.submap
1452    }
1453
1454    proof fn lemma_map_view(tracked &self)
1455        ensures
1456            self.submap@ == imap![self.key() => self.value()],
1457    {
1458        use_type_invariant(self);
1459        let key = self.key();
1460        let target_dom = iset![key];
1461
1462        assert(self.submap@.dom().len() == 1);
1463        assert(target_dom.len() == 1);
1464
1465        assert(self.submap@.dom().finite());
1466        assert(target_dom.finite());
1467
1468        assert(self.submap@.dom().contains(key));
1469        assert(target_dom.contains(key));
1470
1471        assert(self.submap@.dom().remove(key).len() == 0);
1472        assert(target_dom.remove(key).len() == 0);
1473
1474        assert(self.submap@.dom() =~= target_dom);
1475        assert(self.submap@ == imap![self.key() => self.value()]);
1476    }
1477
1478    /// Can be used to learn what the key-value pair of [`GhostPointsTo`] is
1479    pub proof fn lemma_view(self)
1480        ensures
1481            self@ == (self.key(), self.value()),
1482    {
1483    }
1484
1485    /// Convert a [`GhostPointsTo`] into a [`GhostPersistentPointsTo`]
1486    pub proof fn persist(tracked self) -> (tracked r: GhostPersistentPointsTo<K, V>)
1487        ensures
1488            self@ == r@,
1489            self.id() == r.id(),
1490    {
1491        use_type_invariant(&self);
1492        self.submap.persist().points_to()
1493    }
1494}
1495
1496impl<K, V> GhostPersistentPointsTo<K, V> {
1497    #[verifier::type_invariant]
1498    spec fn inv(self) -> bool {
1499        self.submap.is_points_to()
1500    }
1501
1502    /// Location of the underlying resource
1503    pub closed spec fn id(self) -> Loc {
1504        self.submap.id()
1505    }
1506
1507    /// Key-Value pair underlying the points to relationship
1508    pub open spec fn view(self) -> (K, V) {
1509        (self.key(), self.value())
1510    }
1511
1512    /// Key of the points to
1513    pub closed spec fn key(self) -> K {
1514        self.submap.dom().choose()
1515    }
1516
1517    /// Pointed-to value
1518    pub closed spec fn value(self) -> V {
1519        self.submap[self.key()]
1520    }
1521
1522    /// Duplicate the [`GhostPersistentPointsTo`]
1523    pub proof fn duplicate(tracked &self) -> (tracked result: GhostPersistentPointsTo<K, V>)
1524        ensures
1525            result.id() == self.id(),
1526            result@ == self@,
1527    {
1528        use_type_invariant(&*self);
1529        let tracked submap = self.submap.duplicate();
1530        GhostPersistentPointsTo { submap }
1531    }
1532
1533    /// Agreement between a [`GhostPersistentPointsTo`] and a corresponding [`GhostMapAuth`]
1534    ///
1535    /// Verus might not have full context of the [`GhostMapAuth`] and a corresponding [`GhostPersistentPointsTo`].
1536    /// However, whenever we know that they refer to the same resource (i.e., have matching ids) we
1537    /// can assert that the [`GhostPersistentPointsTo`] is a key-value pair in the [`GhostMapAuth`].
1538    /// ```
1539    /// proof fn test(tracked &auth: GhostMapAuth<int, int>, tracked &pt: GhostPersistentPointsTo<int, int>)
1540    ///     requires
1541    ///         auth.id() == sub.id(),
1542    ///         pt@ == (1int, 1int)
1543    ///     ensures
1544    ///         auth[1int] == 1int
1545    /// {
1546    ///     pt.agree(auth);
1547    ///     assert(auth[1int] == 1int);
1548    /// }
1549    /// ```
1550    pub proof fn agree(
1551        tracked self: &GhostPersistentPointsTo<K, V>,
1552        tracked auth: &GhostMapAuth<K, V>,
1553    )
1554        requires
1555            self.id() == auth.id(),
1556        ensures
1557            auth@.contains_pair(self.key(), self.value()),
1558    {
1559        use_type_invariant(self);
1560        use_type_invariant(auth);
1561
1562        self.lemma_map_view();
1563        self.submap.agree(auth);
1564        assert(self.submap@ <= auth@);
1565        assert(self.submap@.contains_key(self.key()));
1566    }
1567
1568    /// We can combine two [`GhostPersistentPointsTo`]s into a [`GhostPersistentSubmap`]
1569    pub proof fn combine(
1570        tracked self,
1571        tracked other: GhostPersistentPointsTo<K, V>,
1572    ) -> (tracked submap: GhostPersistentSubmap<K, V>)
1573        requires
1574            self.id() == other.id(),
1575        ensures
1576            submap.id() == self.id(),
1577            submap@ == imap![self.key() => self.value(), other.key() => other.value()],
1578            self.key() != other.key() ==> submap@.len() == 2,
1579            self.key() == other.key() ==> submap@.len() == 1,
1580    {
1581        use_type_invariant(&self);
1582        use_type_invariant(&other);
1583
1584        let tracked mut submap = self.submap();
1585        submap.combine_points_to(other);
1586
1587        submap
1588    }
1589
1590    /// When we have a [`GhostPersistentPointsTo`] and a [`GhostPointsTo`], we can prove that they are in disjoint
1591    /// domains.
1592    pub proof fn disjoint(tracked &mut self, tracked other: &GhostPointsTo<K, V>)
1593        requires
1594            old(self).id() == other.id(),
1595        ensures
1596            final(self).id() == old(self).id(),
1597            final(self)@ == old(self)@,
1598            final(self).key() != other.key(),
1599    {
1600        use_type_invariant(&*self);
1601        use_type_invariant(other);
1602        self.disjoint_submap(&other.submap);
1603    }
1604
1605    /// When we have a [`GhostPersistentPointsTo`] and a [`GhostSubmap`], we can prove that they are in disjoint
1606    /// domains.
1607    pub proof fn disjoint_submap(tracked &mut self, tracked other: &GhostSubmap<K, V>)
1608        requires
1609            old(self).id() == other.id(),
1610        ensures
1611            final(self).id() == old(self).id(),
1612            final(self)@ == old(self)@,
1613            !other@.contains_key(final(self).key()),
1614    {
1615        use_type_invariant(&*self);
1616        use_type_invariant(other);
1617        self.submap.disjoint(&other);
1618    }
1619
1620    /// Shows that if a client has two [`GhostPersistentPointsTo`]s they are either disjoint or
1621    /// agreeing in values in the intersection
1622    pub proof fn intersection_agrees(
1623        tracked &mut self,
1624        tracked other: &GhostPersistentPointsTo<K, V>,
1625    )
1626        requires
1627            old(self).id() == other.id(),
1628        ensures
1629            final(self).id() == old(self).id(),
1630            final(self)@ == old(self)@,
1631            final(self).key() == other.key() ==> final(self).value() == other.value(),
1632    {
1633        use_type_invariant(&*self);
1634        use_type_invariant(other);
1635        self.submap.intersection_agrees_points_to(&other);
1636    }
1637
1638    /// Shows that if a [`GhostPersistentPointsTo`] and a [`GhostSubmap`] are not owning the same key
1639    pub proof fn intersection_agrees_submap(
1640        tracked &mut self,
1641        tracked other: &GhostPersistentSubmap<K, V>,
1642    )
1643        requires
1644            old(self).id() == other.id(),
1645        ensures
1646            final(self).id() == old(self).id(),
1647            final(self)@ == old(self)@,
1648            other@.contains_key(final(self).key()) ==> other@[final(self).key()]
1649                == final(self).value(),
1650    {
1651        use_type_invariant(&*self);
1652        use_type_invariant(other);
1653        self.submap.intersection_agrees(other);
1654    }
1655
1656    /// Convert the [`GhostPersistentPointsTo`] a [`GhostPersistentSubmap`]
1657    pub proof fn submap(tracked self) -> (tracked r: GhostPersistentSubmap<K, V>)
1658        ensures
1659            r.id() == self.id(),
1660            r@ == imap![self.key() => self.value()],
1661    {
1662        self.lemma_map_view();
1663        self.submap
1664    }
1665
1666    proof fn lemma_map_view(tracked &self)
1667        ensures
1668            self.submap@ == imap![self.key() => self.value()],
1669    {
1670        use_type_invariant(self);
1671        let key = self.key();
1672        let target_dom = iset![key];
1673
1674        assert(self.submap@.dom().len() == 1);
1675        assert(target_dom.len() == 1);
1676
1677        assert(self.submap@.dom().finite());
1678        assert(target_dom.finite());
1679
1680        assert(self.submap@.dom().contains(key));
1681        assert(target_dom.contains(key));
1682
1683        assert(self.submap@.dom().remove(key).len() == 0);
1684        assert(target_dom.remove(key).len() == 0);
1685
1686        assert(self.submap@.dom() =~= target_dom);
1687        assert(self.submap@ == imap![self.key() => self.value()]);
1688    }
1689
1690    /// Can be used to learn what the key-value pair of [`GhostPersistentPointsTo`] is
1691    pub proof fn lemma_view(self)
1692        ensures
1693            self@ == (self.key(), self.value()),
1694    {
1695    }
1696}
1697
1698} // verus!