1use vstd::prelude::*;
46use vstd_extra::{cast_ptr::Repr, ownership::*, set_extra::lemma_finite_int_set_has_unused};
47
48use crate::specs::{
49 arch::valid_frame_paddr,
50 mm::frame::{
51 linked_list::linked_list_owners::{
52 CursorOwner, LinkInnerPerms, LinkOwner, LinkedListOwner, MetaSlotSmall,
53 },
54 mapping::{frame_to_index, meta_to_index},
55 meta_owners::PageUsage,
56 meta_region_owners::MetaRegionOwners,
57 unique::UniqueFrameOwner,
58 },
59};
60
61use crate::mm::{
62 Paddr,
63 frame::{
64 AnyFrameMeta, Link,
65 meta::{REF_COUNT_UNIQUE, REF_COUNT_UNUSED},
66 },
67};
68
69verus! {
70
71pub type ListId = int;
73
74pub type LooseId = int;
77
78pub type CursorId = ListId;
83
84pub open spec fn list_registry_ok<M: AnyFrameMeta + Repr<MetaSlotSmall>>(
96 regions: MetaRegionOwners,
97 lo: LinkedListOwner<M>,
98) -> bool {
99 &&& forall|i: int|
100 #![trigger meta_to_index(lo.list[i].paddr)]
101 0 <= i < lo.list.len() ==> regions.slot_owners[meta_to_index(
102 lo.list[i].paddr,
103 )].in_list_perm.value() == lo.list_id
104 &&& lo.list_id != 0 ==> forall|idx: int|
105 #![trigger regions.slot_owners[idx]]
106 regions.contains(idx) && regions.slot_owners[idx].in_list_perm.value() == lo.list_id
107 ==> exists|i: int|
108 0 <= i < lo.list.len() && #[trigger] meta_to_index(lo.list[i].paddr) == idx
109}
110
111pub tracked struct ListStore<M: AnyFrameMeta + Repr<MetaSlotSmall>> {
120 pub regions: MetaRegionOwners,
121 pub lists: Map<ListId, LinkedListOwner<M>>,
122 pub loose: Map<LooseId, UniqueFrameOwner<Link<M>>>,
123 pub cursors: Map<CursorId, CursorOwner<M>>,
124}
125
126impl<M: AnyFrameMeta + Repr<MetaSlotSmall>> ListStore<M> {
127 pub open spec fn inv(self) -> bool {
129 &&& self.regions.inv()
130 &&& forall|id: ListId| #[trigger]
133 self.lists.dom().contains(id) ==> {
134 &&& self.lists[id].inv()
135 &&& self.lists[id].relate_region(self.regions)
136 }
137 &&& forall|lid: LooseId| #[trigger]
138 self.loose.dom().contains(lid) ==> {
139 &&& self.loose[lid].inv()
140 &&& self.loose[lid].global_inv(self.regions)
141 &&& self.loose[lid].frame_link_inv(self.regions)
142 &&& self.regions.slot_owners[self.loose[lid].slot_index].in_list_perm.value() == 0
143 }
144 &&& forall|id1: ListId, id2: ListId|
146 #![trigger self.lists.dom().contains(id1), self.lists.dom().contains(id2)]
147 self.lists.dom().contains(id1) && self.lists.dom().contains(id2)
148 && self.lists[id1].list_id == self.lists[id2].list_id && self.lists[id1].list_id
149 != 0 ==> id1
150 == id2
151 &&& forall|lid1: LooseId, lid2: LooseId|
154 #![trigger self.loose.dom().contains(lid1), self.loose.dom().contains(lid2)]
155 self.loose.dom().contains(lid1) && self.loose.dom().contains(lid2)
156 && self.loose[lid1].slot_index == self.loose[lid2].slot_index ==> lid1
157 == lid2
158 &&& self.lists.dom().disjoint(
162 self.cursors.dom(),
163 )
164 &&& forall|cid: CursorId| #[trigger]
167 self.cursors.dom().contains(cid) ==> {
168 &&& self.cursors[cid].list_own.inv()
169 &&& self.cursors[cid].wf_with_region(self.regions)
170 }
171 &&& forall|id: ListId, cid: CursorId|
174 #![trigger self.lists.dom().contains(id), self.cursors.dom().contains(cid)]
175 self.lists.dom().contains(id) && self.cursors.dom().contains(cid)
176 && self.lists[id].list_id == self.cursors[cid].list_own.list_id
177 && self.lists[id].list_id != 0
178 ==> false
179 &&& forall|cid1: CursorId, cid2: CursorId|
181 #![trigger self.cursors.dom().contains(cid1), self.cursors.dom().contains(cid2)]
182 self.cursors.dom().contains(cid1) && self.cursors.dom().contains(cid2)
183 && self.cursors[cid1].list_own.list_id == self.cursors[cid2].list_own.list_id
184 && self.cursors[cid1].list_own.list_id != 0 ==> cid1
185 == cid2
186 &&& forall|id: ListId| #[trigger]
189 self.lists.dom().contains(id) ==> list_registry_ok(
190 self.regions,
191 self.lists[id],
192 )
193 &&& forall|cid: CursorId| #[trigger]
195 self.cursors.dom().contains(cid) ==> list_registry_ok(
196 self.regions,
197 self.cursors[cid].list_own,
198 )
199 }
200}
201
202pub proof fn tracked_empty_list_owner<M: AnyFrameMeta + Repr<MetaSlotSmall>>() -> (tracked res:
207 LinkedListOwner<M>)
208 ensures
209 res.list =~= Seq::<LinkOwner>::empty(),
210 res.repr_perms =~= Seq::<LinkInnerPerms<M>>::empty(),
211 res.list_id == 0,
212{
213 let tracked list = Seq::<LinkOwner>::tracked_empty();
214 let tracked repr_perms = Seq::<LinkInnerPerms<M>>::tracked_empty();
215 let tracked res = LinkedListOwner::<M> {
216 list,
217 repr_perms,
218 list_id: 0,
219 _marker: core::marker::PhantomData,
220 };
221 res
222}
223
224pub open spec fn fresh_list_id<M: AnyFrameMeta + Repr<MetaSlotSmall>>(
226 lists: Map<ListId, LinkedListOwner<M>>,
227 cursors: Map<CursorId, CursorOwner<M>>,
228) -> ListId {
229 choose|id: ListId| !lists.dom().contains(id) && !cursors.dom().contains(id)
230}
231
232pub proof fn lemma_fresh_list_id_not_in_dom<M: AnyFrameMeta + Repr<MetaSlotSmall>>(
233 lists: Map<ListId, LinkedListOwner<M>>,
234 cursors: Map<CursorId, CursorOwner<M>>,
235)
236 ensures
237 !lists.dom().contains(fresh_list_id(lists, cursors)) && !cursors.dom().contains(
238 fresh_list_id(lists, cursors),
239 ),
240{
241 lemma_finite_int_set_has_unused(lists.dom() + cursors.dom());
242}
243
244pub proof fn push_front_embedded<M: AnyFrameMeta + Repr<MetaSlotSmall>>(
246 tracked regions: &mut MetaRegionOwners,
247 tracked owner: &mut LinkedListOwner<M>,
248 tracked frame_own: &mut UniqueFrameOwner<Link<M>>,
249 used_ids: Set<u64>,
250)
251 requires
252 old(regions).inv(),
253 old(owner).inv(),
254 old(owner).relate_region(*old(regions)),
255 old(frame_own).inv(),
256 old(frame_own).global_inv(*old(regions)),
257 old(frame_own).frame_link_inv(*old(regions)),
258 old(regions).slot_owners[old(frame_own).slot_index].in_list_perm.value() == 0,
259 ensures
260 final(regions).inv(),
261 final(owner).inv(),
262 final(owner).relate_region(*final(regions)),
263 final(owner).list == old(owner).list.insert(0, final(frame_own).meta_own),
264 old(owner).list_id != 0 ==> final(owner).list_id == old(owner).list_id,
265 final(owner).list_id != 0,
266 old(owner).list_id == 0 ==> !used_ids.contains(final(owner).list_id),
267 final(frame_own).meta_own.paddr == old(frame_own).meta_own.paddr,
268 final(frame_own).meta_own.in_list == final(owner).list_id,
269 final(regions).frame_obligations =~= old(regions).frame_obligations.remove(
270 old(frame_own).slot_index,
271 ),
272 forall|k: int|
273 #![trigger final(regions).slots[k]]
274 #![trigger final(regions).slot_owners[k]]
275 k != old(frame_own).slot_index && (old(owner).list.len() > 0 ==> k != meta_to_index(
276 old(owner).list[0].paddr,
277 )) ==> final(regions).slots[k] == old(regions).slots[k] && final(regions).slot_owners[k]
278 == old(regions).slot_owners[k],
279 forall|l: LinkedListOwner<M>|
280 #![trigger l.relate_region(*old(regions))]
281 l.inv() && l.relate_region(*old(regions)) && l.list_id != final(owner).list_id
282 ==> l.relate_region(*final(regions)),
283 list_registry_ok(*final(regions), *final(owner)),
284 forall|l: LinkedListOwner<M>|
285 #![trigger l.relate_region(*old(regions))]
286 l.inv() && l.relate_region(*old(regions)) && list_registry_ok(*old(regions), l)
287 && l.list_id != final(owner).list_id ==> list_registry_ok(*final(regions), l),
288 forall|fo: UniqueFrameOwner<Link<M>>|
289 #![trigger fo.global_inv(*old(regions))]
290 fo.global_inv(*old(regions)) && fo.frame_link_inv(*old(regions)) && old(
291 regions,
292 ).slot_owners[fo.slot_index].in_list_perm.value() == 0 && fo.slot_index != old(
293 frame_own,
294 ).slot_index ==> fo.global_inv(*final(regions)) && fo.frame_link_inv(*final(regions))
295 && final(regions).slot_owners[fo.slot_index].in_list_perm.value() == 0,
296{
297 insert_before_at_embedded(regions, owner, frame_own, 0, used_ids);
298}
299
300pub open spec fn fresh_loose_id<M: AnyFrameMeta + Repr<MetaSlotSmall>>(
302 m: Map<LooseId, UniqueFrameOwner<Link<M>>>,
303) -> LooseId {
304 choose|id: LooseId| !m.dom().contains(id)
305}
306
307pub proof fn lemma_fresh_loose_id_not_in_dom<M: AnyFrameMeta + Repr<MetaSlotSmall>>(
308 m: Map<LooseId, UniqueFrameOwner<Link<M>>>,
309)
310 ensures
311 !m.dom().contains(fresh_loose_id(m)),
312{
313 lemma_finite_int_set_has_unused(m.dom());
314}
315
316pub proof fn tracked_pop_front_embedded<M: AnyFrameMeta + Repr<MetaSlotSmall>>(
319 tracked regions: &mut MetaRegionOwners,
320 tracked owner: &mut LinkedListOwner<M>,
321) -> (tracked frame_own: UniqueFrameOwner<Link<M>>)
322 requires
323 old(regions).inv(),
324 old(owner).inv(),
325 old(owner).relate_region(*old(regions)),
326 old(owner).list.len() > 0,
327 ensures
328 final(regions).inv(),
329 final(owner).inv(),
330 final(owner).relate_region(*final(regions)),
331 final(owner).list == old(owner).list.remove(0),
332 final(owner).list_id == old(owner).list_id,
333 frame_own.inv(),
335 frame_own.global_inv(*final(regions)),
336 frame_own.frame_link_inv(*final(regions)),
337 frame_own.slot_index == meta_to_index(old(owner).list[0].paddr),
338 final(regions).slot_owners[frame_own.slot_index].in_list_perm.value() == 0,
339 final(regions).frame_obligations =~= old(regions).frame_obligations.insert(
341 meta_to_index(old(owner).list[0].paddr),
342 ),
343 forall|j: int|
344 #![trigger final(regions).slots[j]]
345 #![trigger final(regions).slot_owners[j]]
346 j != meta_to_index(old(owner).list[0].paddr) && (old(owner).list.len() > 1 ==> j
347 != meta_to_index(old(owner).list[1].paddr)) ==> final(regions).slots[j] == old(
348 regions,
349 ).slots[j] && final(regions).slot_owners[j] == old(regions).slot_owners[j],
350 forall|l: LinkedListOwner<M>|
352 #![trigger l.relate_region(*old(regions))]
353 l.inv() && l.relate_region(*old(regions)) && l.list_id != final(owner).list_id
354 ==> l.relate_region(*final(regions)),
355 list_registry_ok(*final(regions), *final(owner)),
356 forall|l: LinkedListOwner<M>|
357 #![trigger l.relate_region(*old(regions))]
358 l.inv() && l.relate_region(*old(regions)) && list_registry_ok(*old(regions), l)
359 && l.list_id != final(owner).list_id ==> list_registry_ok(*final(regions), l),
360 forall|fo: UniqueFrameOwner<Link<M>>|
361 #![trigger fo.global_inv(*old(regions))]
362 fo.global_inv(*old(regions)) && fo.frame_link_inv(*old(regions)) && old(
363 regions,
364 ).slot_owners[fo.slot_index].in_list_perm.value() == 0 ==> fo.global_inv(
365 *final(regions),
366 ) && fo.frame_link_inv(*final(regions))
367 && final(regions).slot_owners[fo.slot_index].in_list_perm.value() == 0
368 && fo.slot_index != meta_to_index(old(owner).list[0].paddr),
369{
370 let tracked frame_own = take_at_embedded(regions, owner, 0);
371 frame_own
372}
373
374pub proof fn lemma_push_back_embedded<M: AnyFrameMeta + Repr<MetaSlotSmall>>(
377 tracked regions: &mut MetaRegionOwners,
378 tracked owner: &mut LinkedListOwner<M>,
379 tracked frame_own: &mut UniqueFrameOwner<Link<M>>,
380 used_ids: Set<u64>,
381)
382 requires
383 old(regions).inv(),
384 old(owner).inv(),
385 old(owner).relate_region(*old(regions)),
386 old(frame_own).inv(),
387 old(frame_own).global_inv(*old(regions)),
388 old(frame_own).frame_link_inv(*old(regions)),
389 old(regions).slot_owners[old(frame_own).slot_index].in_list_perm.value() == 0,
390 ensures
391 final(regions).inv(),
392 final(owner).inv(),
393 final(owner).relate_region(*final(regions)),
394 old(owner).list.len() > 0 ==> final(owner).list == old(owner).list.insert(
395 old(owner).list.len() - 1,
396 final(frame_own).meta_own,
397 ),
398 old(owner).list.len() == 0 ==> final(owner).list == old(owner).list.insert(
399 0,
400 final(frame_own).meta_own,
401 ),
402 old(owner).list_id != 0 ==> final(owner).list_id == old(owner).list_id,
403 final(owner).list_id != 0,
404 old(owner).list_id == 0 ==> !used_ids.contains(final(owner).list_id),
405 final(frame_own).meta_own.paddr == old(frame_own).meta_own.paddr,
406 final(frame_own).meta_own.in_list == final(owner).list_id,
407 final(regions).frame_obligations =~= old(regions).frame_obligations.remove(
408 old(frame_own).slot_index,
409 ),
410 forall|k: int|
411 #![trigger final(regions).slots[k]]
412 #![trigger final(regions).slot_owners[k]]
413 k != old(frame_own).slot_index && (old(owner).list.len() > 1 ==> k != meta_to_index(
414 old(owner).list[old(owner).list.len() - 2].paddr,
415 )) && (old(owner).list.len() > 0 ==> k != meta_to_index(
416 old(owner).list[old(owner).list.len() - 1].paddr,
417 )) ==> final(regions).slots[k] == old(regions).slots[k] && final(regions).slot_owners[k]
418 == old(regions).slot_owners[k],
419 forall|l: LinkedListOwner<M>|
420 #![trigger l.relate_region(*old(regions))]
421 l.inv() && l.relate_region(*old(regions)) && l.list_id != final(owner).list_id
422 ==> l.relate_region(*final(regions)),
423 list_registry_ok(*final(regions), *final(owner)),
424 forall|l: LinkedListOwner<M>|
425 #![trigger l.relate_region(*old(regions))]
426 l.inv() && l.relate_region(*old(regions)) && list_registry_ok(*old(regions), l)
427 && l.list_id != final(owner).list_id ==> list_registry_ok(*final(regions), l),
428 forall|fo: UniqueFrameOwner<Link<M>>|
429 #![trigger fo.global_inv(*old(regions))]
430 fo.global_inv(*old(regions)) && fo.frame_link_inv(*old(regions)) && old(
431 regions,
432 ).slot_owners[fo.slot_index].in_list_perm.value() == 0 && fo.slot_index != old(
433 frame_own,
434 ).slot_index ==> fo.global_inv(*final(regions)) && fo.frame_link_inv(*final(regions))
435 && final(regions).slot_owners[fo.slot_index].in_list_perm.value() == 0,
436{
437 let ghost n = if owner.list.len() > 0 {
438 owner.list.len() - 1
439 } else {
440 0
441 };
442 insert_before_at_embedded(regions, owner, frame_own, n, used_ids);
443}
444
445pub proof fn tracked_pop_back_embedded<M: AnyFrameMeta + Repr<MetaSlotSmall>>(
448 tracked regions: &mut MetaRegionOwners,
449 tracked owner: &mut LinkedListOwner<M>,
450) -> (tracked frame_own: UniqueFrameOwner<Link<M>>)
451 requires
452 old(regions).inv(),
453 old(owner).inv(),
454 old(owner).relate_region(*old(regions)),
455 old(owner).list.len() > 0,
456 ensures
457 final(regions).inv(),
458 final(owner).inv(),
459 final(owner).relate_region(*final(regions)),
460 final(owner).list == old(owner).list.remove(old(owner).list.len() - 1),
461 final(owner).list_id == old(owner).list_id,
462 frame_own.inv(),
463 frame_own.global_inv(*final(regions)),
464 frame_own.frame_link_inv(*final(regions)),
465 frame_own.slot_index == meta_to_index(old(owner).list[old(owner).list.len() - 1].paddr),
466 final(regions).slot_owners[frame_own.slot_index].in_list_perm.value() == 0,
467 final(regions).frame_obligations =~= old(regions).frame_obligations.insert(
468 meta_to_index(old(owner).list[old(owner).list.len() - 1].paddr),
469 ),
470 forall|j: int|
471 #![trigger final(regions).slots[j]]
472 #![trigger final(regions).slot_owners[j]]
473 j != meta_to_index(old(owner).list[old(owner).list.len() - 1].paddr) && (old(
474 owner,
475 ).list.len() > 1 ==> j != meta_to_index(
476 old(owner).list[old(owner).list.len() - 2].paddr,
477 )) ==> final(regions).slots[j] == old(regions).slots[j] && final(regions).slot_owners[j]
478 == old(regions).slot_owners[j],
479 forall|l: LinkedListOwner<M>|
480 #![trigger l.relate_region(*old(regions))]
481 l.inv() && l.relate_region(*old(regions)) && l.list_id != final(owner).list_id
482 ==> l.relate_region(*final(regions)),
483 list_registry_ok(*final(regions), *final(owner)),
484 forall|l: LinkedListOwner<M>|
485 #![trigger l.relate_region(*old(regions))]
486 l.inv() && l.relate_region(*old(regions)) && list_registry_ok(*old(regions), l)
487 && l.list_id != final(owner).list_id ==> list_registry_ok(*final(regions), l),
488 forall|fo: UniqueFrameOwner<Link<M>>|
489 #![trigger fo.global_inv(*old(regions))]
490 fo.global_inv(*old(regions)) && fo.frame_link_inv(*old(regions)) && old(
491 regions,
492 ).slot_owners[fo.slot_index].in_list_perm.value() == 0 ==> fo.global_inv(
493 *final(regions),
494 ) && fo.frame_link_inv(*final(regions))
495 && final(regions).slot_owners[fo.slot_index].in_list_perm.value() == 0
496 && fo.slot_index != meta_to_index(old(owner).list[old(owner).list.len() - 1].paddr),
497{
498 let ghost n = owner.list.len() - 1;
499 let tracked frame_own = take_at_embedded(regions, owner, n);
500 frame_own
501}
502
503pub axiom fn insert_before_at_embedded<M: AnyFrameMeta + Repr<MetaSlotSmall>>(
505 tracked regions: &mut MetaRegionOwners,
506 tracked owner: &mut LinkedListOwner<M>,
507 tracked frame_own: &mut UniqueFrameOwner<Link<M>>,
508 n: int,
509 used_ids: Set<u64>,
510)
511 requires
512 old(regions).inv(),
513 old(owner).inv(),
514 old(owner).relate_region(*old(regions)),
515 old(frame_own).inv(),
516 old(frame_own).global_inv(*old(regions)),
517 old(frame_own).frame_link_inv(*old(regions)),
518 old(regions).slot_owners[old(frame_own).slot_index].in_list_perm.value() == 0,
519 0 <= n <= old(owner).list.len(),
520 ensures
521 final(regions).inv(),
522 final(owner).inv(),
523 final(owner).relate_region(*final(regions)),
524 final(owner).list == old(owner).list.insert(n, final(frame_own).meta_own),
525 old(owner).list_id != 0 ==> final(owner).list_id == old(owner).list_id,
526 final(owner).list_id != 0,
527 old(owner).list_id == 0 ==> !used_ids.contains(final(owner).list_id),
528 final(frame_own).meta_own.paddr == old(frame_own).meta_own.paddr,
529 final(frame_own).meta_own.in_list == final(owner).list_id,
530 final(regions).frame_obligations =~= old(regions).frame_obligations.remove(
531 old(frame_own).slot_index,
532 ),
533 forall|k: int|
534 #![trigger final(regions).slots[k]]
535 #![trigger final(regions).slot_owners[k]]
536 k != old(frame_own).slot_index && (n > 0 ==> k != meta_to_index(
537 old(owner).list[n - 1].paddr,
538 )) && (n < old(owner).list.len() ==> k != meta_to_index(old(owner).list[n].paddr))
539 ==> final(regions).slots[k] == old(regions).slots[k]
540 && final(regions).slot_owners[k] == old(regions).slot_owners[k],
541 forall|l: LinkedListOwner<M>|
542 #![trigger l.relate_region(*old(regions))]
543 l.inv() && l.relate_region(*old(regions)) && l.list_id != final(owner).list_id
544 ==> l.relate_region(*final(regions)),
545 list_registry_ok(*final(regions), *final(owner)),
546 forall|l: LinkedListOwner<M>|
547 #![trigger l.relate_region(*old(regions))]
548 l.inv() && l.relate_region(*old(regions)) && list_registry_ok(*old(regions), l)
549 && l.list_id != final(owner).list_id ==> list_registry_ok(*final(regions), l),
550 forall|fo: UniqueFrameOwner<Link<M>>|
551 #![trigger fo.global_inv(*old(regions))]
552 fo.global_inv(*old(regions)) && fo.frame_link_inv(*old(regions)) && old(
553 regions,
554 ).slot_owners[fo.slot_index].in_list_perm.value() == 0 && fo.slot_index != old(
555 frame_own,
556 ).slot_index ==> fo.global_inv(*final(regions)) && fo.frame_link_inv(*final(regions))
557 && final(regions).slot_owners[fo.slot_index].in_list_perm.value() == 0,
558;
559
560pub axiom fn take_at_embedded<M: AnyFrameMeta + Repr<MetaSlotSmall>>(
562 tracked regions: &mut MetaRegionOwners,
563 tracked owner: &mut LinkedListOwner<M>,
564 n: int,
565) -> (tracked frame_own: UniqueFrameOwner<Link<M>>)
566 requires
567 old(regions).inv(),
568 old(owner).inv(),
569 old(owner).relate_region(*old(regions)),
570 0 <= n < old(owner).list.len(),
571 ensures
572 final(regions).inv(),
573 final(owner).inv(),
574 final(owner).relate_region(*final(regions)),
575 final(owner).list == old(owner).list.remove(n),
576 final(owner).list_id == old(owner).list_id,
577 frame_own.inv(),
578 frame_own.global_inv(*final(regions)),
579 frame_own.frame_link_inv(*final(regions)),
580 frame_own.slot_index == meta_to_index(old(owner).list[n].paddr),
581 final(regions).slot_owners[frame_own.slot_index].in_list_perm.value() == 0,
582 final(regions).frame_obligations =~= old(regions).frame_obligations.insert(
583 meta_to_index(old(owner).list[n].paddr),
584 ),
585 forall|j: int|
586 #![trigger final(regions).slots[j]]
587 #![trigger final(regions).slot_owners[j]]
588 j != meta_to_index(old(owner).list[n].paddr) && (n > 0 ==> j != meta_to_index(
589 old(owner).list[n - 1].paddr,
590 )) && (n < old(owner).list.len() - 1 ==> j != meta_to_index(
591 old(owner).list[n + 1].paddr,
592 )) ==> final(regions).slots[j] == old(regions).slots[j] && final(regions).slot_owners[j]
593 == old(regions).slot_owners[j],
594 forall|l: LinkedListOwner<M>|
595 #![trigger l.relate_region(*old(regions))]
596 l.inv() && l.relate_region(*old(regions)) && l.list_id != final(owner).list_id
597 ==> l.relate_region(*final(regions)),
598 list_registry_ok(*final(regions), *final(owner)),
599 forall|l: LinkedListOwner<M>|
600 #![trigger l.relate_region(*old(regions))]
601 l.inv() && l.relate_region(*old(regions)) && list_registry_ok(*old(regions), l)
602 && l.list_id != final(owner).list_id ==> list_registry_ok(*final(regions), l),
603 forall|fo: UniqueFrameOwner<Link<M>>|
604 #![trigger fo.global_inv(*old(regions))]
605 fo.global_inv(*old(regions)) && fo.frame_link_inv(*old(regions)) && old(
606 regions,
607 ).slot_owners[fo.slot_index].in_list_perm.value() == 0 ==> fo.global_inv(
608 *final(regions),
609 ) && fo.frame_link_inv(*final(regions))
610 && final(regions).slot_owners[fo.slot_index].in_list_perm.value() == 0
611 && fo.slot_index != meta_to_index(old(owner).list[n].paddr),
612;
613
614pub axiom fn list_drop_embedded<M: AnyFrameMeta + Repr<MetaSlotSmall>>(
616 tracked regions: &mut MetaRegionOwners,
617 tracked owner: LinkedListOwner<M>,
618)
619 requires
620 old(regions).inv(),
621 owner.inv(),
622 owner.relate_region(*old(regions)),
623 forall|i: int|
624 #![trigger meta_to_index(owner.list[i].paddr)]
625 0 <= i < owner.list.len() ==> old(regions).frame_obligations.count(
626 meta_to_index(owner.list[i].paddr),
627 ) == 0,
628 forall|i: int|
629 #![trigger meta_to_index(owner.list[i].paddr)]
630 0 <= i < owner.list.len() ==> old(regions).slot_owners[meta_to_index(
631 owner.list[i].paddr,
632 )].paths_in_pt.is_empty(),
633 ensures
634 final(regions).inv(),
635 final(regions).slots.dom() =~= old(regions).slots.dom(),
636 owner.list.len() == 0 ==> *final(regions) == *old(regions),
638 forall|i: int|
640 #![trigger meta_to_index(owner.list[i].paddr)]
641 0 <= i < owner.list.len() ==> {
642 let idx = meta_to_index(owner.list[i].paddr);
643 &&& final(regions).slot_owners[idx].ref_count() == REF_COUNT_UNUSED
644 &&& final(regions).slot_owners[idx].in_list_perm.value() == 0
645 },
646 forall|idx: int|
648 #![trigger final(regions).slot_owners[idx]]
649 (forall|i: int|
650 0 <= i < owner.list.len() ==> idx != #[trigger] meta_to_index(owner.list[i].paddr))
651 ==> final(regions).slot_owners[idx] == old(regions).slot_owners[idx]
652 && final(regions).slots[idx] == old(regions).slots[idx]
653 && final(regions).frame_obligations.count(idx) == old(
654 regions,
655 ).frame_obligations.count(idx),
656 forall|l: LinkedListOwner<M>|
658 #![trigger l.relate_region(*old(regions))]
659 l.inv() && l.relate_region(*old(regions)) && l.list_id != owner.list_id
660 ==> l.relate_region(*final(regions)),
661 forall|l: LinkedListOwner<M>|
662 #![trigger l.relate_region(*old(regions))]
663 l.inv() && l.relate_region(*old(regions)) && list_registry_ok(*old(regions), l)
664 && l.list_id != owner.list_id ==> list_registry_ok(*final(regions), l),
665 forall|fo: UniqueFrameOwner<Link<M>>|
668 #![trigger fo.global_inv(*old(regions))]
669 fo.global_inv(*old(regions)) && fo.frame_link_inv(*old(regions)) && old(
670 regions,
671 ).slot_owners[fo.slot_index].in_list_perm.value() == 0 ==> fo.global_inv(
672 *final(regions),
673 ) && fo.frame_link_inv(*final(regions))
674 && final(regions).slot_owners[fo.slot_index].in_list_perm.value() == 0,
675;
676
677impl<M: AnyFrameMeta + Repr<MetaSlotSmall>> ListStore<M> {
681 pub proof fn step_size(tracked &self, id: ListId) -> (res: nat)
684 requires
685 self.inv(),
686 self.lists.dom().contains(id),
687 ensures
688 res == self.lists[id].list.len(),
689 {
690 self.lists[id].list.len()
691 }
692
693 pub proof fn step_is_empty(tracked &self, id: ListId) -> (res: bool)
695 requires
696 self.inv(),
697 self.lists.dom().contains(id),
698 ensures
699 res <==> self.lists[id].list.len() == 0,
700 {
701 self.lists[id].list.len() == 0
702 }
703
704 pub proof fn step_contains(tracked &self, id: ListId, frame: Paddr) -> (res: bool)
706 requires
707 self.inv(),
708 self.lists.dom().contains(id),
709 ensures
710 res <==> (valid_frame_paddr(frame) && exists|i: int|
711 0 <= i < self.lists[id].list.len() && #[trigger] meta_to_index(
712 self.lists[id].list[i].paddr,
713 ) == frame_to_index(frame)),
714 {
715 let idx = frame_to_index(frame);
716 if valid_frame_paddr(frame) {
717 self.regions.lemma_contains_valid_frame_paddr(frame);
719 assert(self.regions.contains(idx));
720 if self.lists[id].list_id != 0 {
721 assert(list_registry_ok(self.regions, self.lists[id]));
723 let res = self.regions.slot_owners[idx].in_list_perm.value()
724 == self.lists[id].list_id;
725 if res {
726 assert(exists|i: int|
728 0 <= i < self.lists[id].list.len() && #[trigger] meta_to_index(
729 self.lists[id].list[i].paddr,
730 ) == idx);
731 } else {
732 assert forall|i: int|
735 0 <= i < self.lists[id].list.len() implies #[trigger] meta_to_index(
736 self.lists[id].list[i].paddr,
737 ) != idx by {
738 assert(self.regions.slot_owners[meta_to_index(
739 self.lists[id].list[i].paddr,
740 )].in_list_perm.value() == self.lists[id].list_id);
741 };
742 }
743 res
744 } else {
745 assert(self.lists[id].list.len() == 0);
746 false
747 }
748 } else {
749 false
750 }
751 }
752
753 pub proof fn step_list_new(tracked &mut self) -> (res: ListId)
755 requires
756 old(self).inv(),
757 ensures
758 final(self).inv(),
759 final(self).regions == old(self).regions,
760 final(self).loose == old(self).loose,
761 !old(self).lists.dom().contains(res),
762 final(self).lists == old(self).lists.insert(res, final(self).lists[res]),
763 final(self).lists[res].list.len() == 0,
764 {
765 let ghost old_self = *self;
766 let ghost id = fresh_list_id(self.lists, self.cursors);
767 lemma_fresh_list_id_not_in_dom(self.lists, self.cursors);
768 let tracked empty = tracked_empty_list_owner::<M>();
769 self.lists.tracked_insert(id, empty);
770 assert(self.lists[id].list.len() == 0);
771 assert(self.lists[id].relate_region(self.regions));
772 assert(self.cursors == old_self.cursors);
773 assert(self.lists.dom().disjoint(self.cursors.dom()));
774 assert(self.lists[id].list_id == 0);
775 id
776 }
777
778 pub proof fn step_list_drop(tracked &mut self, id: ListId)
780 requires
781 old(self).inv(),
782 old(self).lists.dom().contains(id),
783 forall|i: int|
784 0 <= i < old(self).lists[id].list.len() ==> old(
785 self,
786 ).regions.frame_obligations.count(
787 #[trigger] meta_to_index(old(self).lists[id].list[i].paddr),
788 ) == 0,
789 ensures
790 final(self).inv(),
791 !final(self).lists.dom().contains(id),
792 final(self).loose == old(self).loose,
793 final(self).cursors == old(self).cursors,
794 {
795 let ghost old_self = *self;
796 let ghost old_regions = self.regions;
797 let ghost dropped_id = self.lists[id].list_id;
798 let ghost is_empty = self.lists[id].list.len() == 0;
799 assert(self.lists[id].relate_region(self.regions));
800 assert forall|i: int|
801 #![trigger meta_to_index(self.lists[id].list[i].paddr)]
802 0 <= i < self.lists[id].list.len() implies self.regions.slot_owners[meta_to_index(
803 self.lists[id].list[i].paddr,
804 )].paths_in_pt.is_empty() by {
805 let idx = meta_to_index(self.lists[id].list[i].paddr);
806 let _ = self.lists[id].list[i];
807 self.lists[id].relate_region_at_facts(self.regions, i);
808 assert(self.regions.contains(idx));
809 assert(self.regions.slot_owners[idx].ref_count() == REF_COUNT_UNIQUE);
810 assert(self.regions.slot_owners[idx].usage is Frame);
811 };
812
813 let tracked owner = self.lists.tracked_remove(id);
814 list_drop_embedded(&mut self.regions, owner);
815 assert(self.lists =~= old_self.lists.remove(id));
816 if is_empty {
817 assert(self.regions == old_regions);
818 }
819 if !is_empty {
820 assert(dropped_id != 0);
821 }
822 assert forall|i: ListId| #[trigger] self.lists.dom().contains(i) implies {
825 &&& self.lists[i].inv()
826 &&& self.lists[i].relate_region(self.regions)
827 } by {
828 assert(i != id);
829 assert(old_self.lists.dom().contains(i));
830 assert(old_self.lists[i] == self.lists[i]);
831 assert(old_self.lists[i].relate_region(old_regions));
832 if !is_empty {
833 assert(self.lists[i].list_id != dropped_id);
834 }
835 };
836
837 assert forall|lid2: LooseId| #[trigger] self.loose.dom().contains(lid2) implies {
839 &&& self.loose[lid2].inv()
840 &&& self.loose[lid2].global_inv(self.regions)
841 &&& self.loose[lid2].frame_link_inv(self.regions)
842 &&& self.regions.slot_owners[self.loose[lid2].slot_index].in_list_perm.value() == 0
843 } by {
844 assert(old_self.loose.dom().contains(lid2));
845 assert(old_self.loose[lid2].global_inv(old_regions));
846 assert(old_self.loose[lid2].frame_link_inv(old_regions));
847 assert(old_regions.slot_owners[self.loose[lid2].slot_index].in_list_perm.value() == 0);
848 };
849
850 assert forall|cid: CursorId| #[trigger] self.cursors.dom().contains(cid) implies {
852 &&& self.cursors[cid].list_own.inv()
853 &&& self.cursors[cid].wf_with_region(self.regions)
854 } by {
855 assert(old_self.cursors.dom().contains(cid));
856 assert(old_self.cursors[cid].wf_with_region(old_regions));
857 assert(self.cursors[cid].list_own.relate_region(old_regions));
858 if !is_empty {
859 assert(self.cursors[cid].list_own.list_id != dropped_id);
860 }
861 };
862
863 assert forall|i1: ListId, i2: ListId| #[trigger]
865 self.lists.dom().contains(i1) && #[trigger] self.lists.dom().contains(i2)
866 && self.lists[i1].list_id == self.lists[i2].list_id && self.lists[i1].list_id
867 != 0 implies i1 == i2 by {
868 assert(old_self.lists.dom().contains(i1));
869 assert(old_self.lists.dom().contains(i2));
870 };
871
872 assert forall|l1: LooseId, l2: LooseId| #[trigger]
874 self.loose.dom().contains(l1) && #[trigger] self.loose.dom().contains(l2)
875 && self.loose[l1].slot_index == self.loose[l2].slot_index implies l1 == l2 by {
876 assert(old_self.loose.dom().contains(l1));
877 assert(old_self.loose.dom().contains(l2));
878 };
879
880 assert(self.lists.dom().disjoint(self.cursors.dom()));
882 assert forall|id2: ListId, cid: CursorId| #[trigger]
883 self.lists.dom().contains(id2) && #[trigger] self.cursors.dom().contains(cid)
884 && self.lists[id2].list_id == self.cursors[cid].list_own.list_id
885 && self.lists[id2].list_id != 0 implies false by {
886 assert(old_self.lists.dom().contains(id2));
887 assert(old_self.cursors.dom().contains(cid));
888 };
889 assert forall|cid1: CursorId, cid2: CursorId| #[trigger]
890 self.cursors.dom().contains(cid1) && #[trigger] self.cursors.dom().contains(cid2)
891 && self.cursors[cid1].list_own.list_id == self.cursors[cid2].list_own.list_id
892 && self.cursors[cid1].list_own.list_id != 0 implies cid1 == cid2 by {
893 assert(old_self.cursors.dom().contains(cid1));
894 assert(old_self.cursors.dom().contains(cid2));
895 };
896
897 assert forall|i: ListId| #[trigger] self.lists.dom().contains(i) implies list_registry_ok(
899 self.regions,
900 self.lists[i],
901 ) by {
902 assert(old_self.lists.dom().contains(i));
903 assert(old_self.lists[i] == self.lists[i]);
904 assert(old_self.lists[i].relate_region(old_regions));
905 if !is_empty {
906 assert(self.lists[i].list_id != dropped_id);
907 }
908 };
909 assert forall|cid: CursorId| #[trigger]
910 self.cursors.dom().contains(cid) implies list_registry_ok(
911 self.regions,
912 self.cursors[cid].list_own,
913 ) by {
914 assert(old_self.cursors.dom().contains(cid));
915 assert(old_self.cursors[cid].list_own.relate_region(old_regions));
916 if !is_empty {
917 assert(self.cursors[cid].list_own.list_id != dropped_id);
918 }
919 };
920 }
921
922 pub proof fn step_push_front(tracked &mut self, id: ListId, lid: LooseId)
926 requires
927 old(self).inv(),
928 old(self).lists.dom().contains(id),
929 old(self).loose.dom().contains(lid),
930 ensures
931 final(self).inv(),
932 {
933 let ghost old_self = *self;
934 let ghost old_regions = self.regions;
935 let ghost fidx = self.loose[lid].slot_index;
936 let ghost used = Set::<u64>::full().unwrap().filter(
938 |x: u64|
939 (exists|i: ListId| #[trigger]
940 old_self.lists.dom().contains(i) && i != id && old_self.lists[i].list_id == x)
941 || (exists|cid: CursorId| #[trigger]
942 old_self.cursors.dom().contains(cid) && old_self.cursors[cid].list_own.list_id
943 == x),
944 );
945 assert(self.lists[id].relate_region(self.regions));
946 assert(self.loose[lid].global_inv(self.regions));
947 assert(self.loose[lid].frame_link_inv(self.regions));
948 assert(self.regions.slot_owners[fidx].in_list_perm.value() == 0);
949
950 let tracked mut owner = self.lists.tracked_remove(id);
951 let tracked mut frame_own = self.loose.tracked_remove(lid);
952 push_front_embedded(&mut self.regions, &mut owner, &mut frame_own, used);
953 self.lists.tracked_insert(id, owner);
954 assert(self.loose =~= old_self.loose.remove(lid));
955 assert(self.lists =~= old_self.lists.remove(id).insert(id, owner));
956 let ghost new_id = self.lists[id].list_id;
957
958 assert forall|i: ListId| #[trigger]
959 self.lists.dom().contains(i) && i != id && self.lists[i].list_id
960 != 0 implies self.lists[i].list_id != new_id by {
961 assert(old_self.lists.dom().contains(i));
962 assert(old_self.lists[i] == self.lists[i]);
963 if old_self.lists[id].list_id != 0 {
964 assert(new_id == old_self.lists[id].list_id);
965 } else {
966 assert(used.contains(self.lists[i].list_id));
967 }
968 };
969
970 assert forall|i: ListId| #[trigger] self.lists.dom().contains(i) implies {
972 &&& self.lists[i].inv()
973 &&& self.lists[i].relate_region(self.regions)
974 } by {
975 if i != id {
976 assert(old_self.lists.dom().contains(i));
977 assert(old_self.lists[i] == self.lists[i]);
978 assert(old_self.lists[i].relate_region(old_regions));
979 if self.lists[i].list.len() > 0 {
980 assert(self.lists[i].list_id != new_id);
981 }
982 }
983 };
984
985 assert forall|lid2: LooseId| #[trigger] self.loose.dom().contains(lid2) implies {
988 &&& self.loose[lid2].inv()
989 &&& self.loose[lid2].global_inv(self.regions)
990 &&& self.loose[lid2].frame_link_inv(self.regions)
991 &&& self.regions.slot_owners[self.loose[lid2].slot_index].in_list_perm.value() == 0
992 } by {
993 assert(lid2 != lid);
994 assert(old_self.loose.dom().contains(lid2));
995 assert(old_self.loose[lid2] == self.loose[lid2]);
996 assert(old_self.loose[lid2].global_inv(old_regions));
997 assert(old_self.loose[lid2].frame_link_inv(old_regions));
998 assert(old_regions.slot_owners[self.loose[lid2].slot_index].in_list_perm.value() == 0);
999 assert(self.loose[lid2].slot_index != fidx);
1000 };
1001
1002 assert forall|i1: ListId, i2: ListId| #[trigger]
1004 self.lists.dom().contains(i1) && #[trigger] self.lists.dom().contains(i2)
1005 && self.lists[i1].list.len() > 0 && self.lists[i2].list.len() > 0
1006 && self.lists[i1].list_id == self.lists[i2].list_id implies i1 == i2 by {
1007 if i1 != id && i2 != id {
1008 assert(old_self.lists[i1] == self.lists[i1]);
1009 assert(old_self.lists[i2] == self.lists[i2]);
1010 } else if i1 == id && i2 != id {
1011 assert(self.lists[i2].list_id != new_id);
1012 } else if i2 == id && i1 != id {
1013 assert(self.lists[i1].list_id != new_id);
1014 }
1015 };
1016
1017 assert forall|l1: LooseId, l2: LooseId| #[trigger]
1019 self.loose.dom().contains(l1) && #[trigger] self.loose.dom().contains(l2)
1020 && self.loose[l1].slot_index == self.loose[l2].slot_index implies l1 == l2 by {
1021 assert(old_self.loose.dom().contains(l1));
1022 assert(old_self.loose.dom().contains(l2));
1023 };
1024
1025 assert(self.cursors == old_self.cursors);
1033 assert(self.lists.dom() =~= old_self.lists.dom());
1034 assert forall|cid: CursorId| #[trigger] self.cursors.dom().contains(cid) implies {
1035 &&& self.cursors[cid].list_own.inv()
1036 &&& self.cursors[cid].wf_with_region(self.regions)
1037 } by {
1038 assert(old_self.cursors.dom().contains(cid));
1039 assert(old_self.cursors[cid].wf_with_region(old_regions));
1040 assert(self.cursors[cid].list_own.relate_region(old_regions));
1041 if old_self.lists[id].list_id != 0 {
1042 assert(new_id == old_self.lists[id].list_id);
1043 } else {
1044 assert(used.contains(self.cursors[cid].list_own.list_id));
1045 }
1046 assert(self.cursors[cid].list_own.list_id != new_id);
1047 assert(self.cursors[cid].list_own.relate_region(self.regions));
1048 };
1049 assert forall|id2: ListId, cid: CursorId| #[trigger]
1050 self.lists.dom().contains(id2) && #[trigger] self.cursors.dom().contains(cid)
1051 && self.lists[id2].list_id == self.cursors[cid].list_own.list_id
1052 && self.lists[id2].list_id != 0 implies false by {
1053 assert(old_self.cursors.dom().contains(cid));
1054 if id2 == id {
1055 assert(self.lists[id].list_id == new_id);
1056 if old_self.lists[id].list_id != 0 {
1057 assert(new_id == old_self.lists[id].list_id);
1058 } else {
1059 assert(used.contains(self.cursors[cid].list_own.list_id));
1060 }
1061 } else {
1062 assert(old_self.lists.dom().contains(id2));
1063 assert(old_self.lists[id2] == self.lists[id2]);
1064 }
1065 };
1066 assert forall|cid1: CursorId, cid2: CursorId| #[trigger]
1067 self.cursors.dom().contains(cid1) && #[trigger] self.cursors.dom().contains(cid2)
1068 && self.cursors[cid1].list_own.list_id == self.cursors[cid2].list_own.list_id
1069 && self.cursors[cid1].list_own.list_id != 0 implies cid1 == cid2 by {
1070 assert(old_self.cursors.dom().contains(cid1));
1071 assert(old_self.cursors.dom().contains(cid2));
1072 };
1073 }
1074
1075 pub proof fn step_pop_front(tracked &mut self, id: ListId) -> (res: Option<LooseId>)
1079 requires
1080 old(self).inv(),
1081 old(self).lists.dom().contains(id),
1082 ensures
1083 final(self).inv(),
1084 old(self).lists[id].list.len() == 0 ==> res is None && *final(self) == *old(self),
1085 old(self).lists[id].list.len() > 0 ==> res is Some,
1086 {
1087 if self.lists[id].list.len() == 0 {
1088 Option::None
1089 } else {
1090 let ghost old_self = *self;
1091 let ghost old_regions = self.regions;
1092 let ghost popped_idx = meta_to_index(self.lists[id].list[0].paddr);
1093 let ghost old_list_id = self.lists[id].list_id;
1094 assert(self.lists[id].relate_region(self.regions));
1096
1097 let tracked mut owner = self.lists.tracked_remove(id);
1098 let tracked frame_own = tracked_pop_front_embedded(&mut self.regions, &mut owner);
1099 self.lists.tracked_insert(id, owner);
1100 let ghost new_loose = fresh_loose_id(self.loose);
1101 lemma_fresh_loose_id_not_in_dom(self.loose);
1102 self.loose.tracked_insert(new_loose, frame_own);
1103
1104 assert(self.lists =~= old_self.lists.remove(id).insert(id, owner));
1105 assert(self.loose =~= old_self.loose.insert(new_loose, frame_own));
1106 assert(self.lists[id].list_id == old_list_id);
1107 assert(frame_own.slot_index == popped_idx);
1108
1109 assert forall|i: ListId| #[trigger] self.lists.dom().contains(i) implies {
1111 &&& self.lists[i].inv()
1112 &&& self.lists[i].relate_region(self.regions)
1113 } by {
1114 if i != id {
1115 assert(old_self.lists.dom().contains(i));
1116 assert(old_self.lists[i] == self.lists[i]);
1117 assert(old_self.lists[i].relate_region(old_regions));
1118 if self.lists[i].list.len() > 0 {
1119 assert(self.lists[i].list_id != old_list_id);
1120 }
1121 }
1122 };
1123
1124 assert forall|lid2: LooseId| #[trigger] self.loose.dom().contains(lid2) implies {
1126 &&& self.loose[lid2].inv()
1127 &&& self.loose[lid2].global_inv(self.regions)
1128 &&& self.loose[lid2].frame_link_inv(self.regions)
1129 &&& self.regions.slot_owners[self.loose[lid2].slot_index].in_list_perm.value() == 0
1130 } by {
1131 if lid2 != new_loose {
1132 assert(old_self.loose.dom().contains(lid2));
1133 assert(old_self.loose[lid2] == self.loose[lid2]);
1134 assert(old_self.loose[lid2].global_inv(old_regions));
1135 assert(old_self.loose[lid2].frame_link_inv(old_regions));
1136 assert(old_regions.slot_owners[self.loose[lid2].slot_index].in_list_perm.value()
1137 == 0);
1138 }
1139 };
1140
1141 assert forall|i1: ListId, i2: ListId| #[trigger]
1143 self.lists.dom().contains(i1) && #[trigger] self.lists.dom().contains(i2)
1144 && self.lists[i1].list_id == self.lists[i2].list_id && self.lists[i1].list_id
1145 != 0 implies i1 == i2 by {
1146 assert(old_self.lists.dom().contains(i1));
1147 assert(old_self.lists.dom().contains(i2));
1148 assert(self.lists[i1].list_id == old_self.lists[i1].list_id);
1149 assert(self.lists[i2].list_id == old_self.lists[i2].list_id);
1150 };
1151
1152 assert forall|l1: LooseId, l2: LooseId| #[trigger]
1154 self.loose.dom().contains(l1) && #[trigger] self.loose.dom().contains(l2)
1155 && self.loose[l1].slot_index == self.loose[l2].slot_index implies l1 == l2 by {
1156 if l1 == new_loose && l2 != new_loose {
1157 assert(old_self.loose.dom().contains(l2));
1158 assert(self.loose[l2].slot_index != popped_idx);
1159 } else if l2 == new_loose && l1 != new_loose {
1160 assert(old_self.loose.dom().contains(l1));
1161 assert(self.loose[l1].slot_index != popped_idx);
1162 } else if l1 != new_loose && l2 != new_loose {
1163 assert(old_self.loose.dom().contains(l1));
1164 assert(old_self.loose.dom().contains(l2));
1165 }
1166 };
1167
1168 assert(self.cursors == old_self.cursors);
1170 assert(self.lists.dom() =~= old_self.lists.dom());
1171 assert forall|cid: CursorId| #[trigger] self.cursors.dom().contains(cid) implies {
1172 &&& self.cursors[cid].list_own.inv()
1173 &&& self.cursors[cid].wf_with_region(self.regions)
1174 } by {
1175 assert(old_self.cursors.dom().contains(cid));
1176 assert(old_self.cursors[cid].wf_with_region(old_regions));
1177 assert(self.cursors[cid].list_own.relate_region(old_regions));
1178 assert(old_self.lists.dom().contains(id));
1179 assert(old_self.lists[id].list_id == old_list_id);
1180 assert(self.cursors[cid].list_own.list_id != old_list_id);
1181 assert(self.cursors[cid].list_own.relate_region(self.regions));
1182 };
1183 assert forall|id2: ListId, cid: CursorId| #[trigger]
1184 self.lists.dom().contains(id2) && #[trigger] self.cursors.dom().contains(cid)
1185 && self.lists[id2].list_id == self.cursors[cid].list_own.list_id
1186 && self.lists[id2].list_id != 0 implies false by {
1187 assert(old_self.cursors.dom().contains(cid));
1188 assert(old_self.lists.dom().contains(id2));
1189 assert(old_self.lists[id2].list_id == self.lists[id2].list_id);
1190 };
1191 assert forall|cid1: CursorId, cid2: CursorId| #[trigger]
1192 self.cursors.dom().contains(cid1) && #[trigger] self.cursors.dom().contains(cid2)
1193 && self.cursors[cid1].list_own.list_id == self.cursors[cid2].list_own.list_id
1194 && self.cursors[cid1].list_own.list_id != 0 implies cid1 == cid2 by {
1195 assert(old_self.cursors.dom().contains(cid1));
1196 assert(old_self.cursors.dom().contains(cid2));
1197 };
1198 Option::Some(new_loose)
1199 }
1200 }
1201
1202 pub proof fn step_push_back(tracked &mut self, id: ListId, lid: LooseId)
1206 requires
1207 old(self).inv(),
1208 old(self).lists.dom().contains(id),
1209 old(self).loose.dom().contains(lid),
1210 ensures
1211 final(self).inv(),
1212 {
1213 let ghost old_self = *self;
1214 let ghost old_regions = self.regions;
1215 let ghost fidx = self.loose[lid].slot_index;
1216 let ghost used = Set::<u64>::full().unwrap().filter(
1217 |x: u64|
1218 (exists|i: ListId| #[trigger]
1219 old_self.lists.dom().contains(i) && i != id && old_self.lists[i].list_id == x)
1220 || (exists|cid: CursorId| #[trigger]
1221 old_self.cursors.dom().contains(cid) && old_self.cursors[cid].list_own.list_id
1222 == x),
1223 );
1224 assert(self.lists[id].relate_region(self.regions));
1225 assert(self.loose[lid].global_inv(self.regions));
1226 assert(self.loose[lid].frame_link_inv(self.regions));
1227 assert(self.regions.slot_owners[fidx].in_list_perm.value() == 0);
1228
1229 let tracked mut owner = self.lists.tracked_remove(id);
1230 let tracked mut frame_own = self.loose.tracked_remove(lid);
1231 lemma_push_back_embedded(&mut self.regions, &mut owner, &mut frame_own, used);
1232 self.lists.tracked_insert(id, owner);
1233 assert(self.loose =~= old_self.loose.remove(lid));
1234 assert(self.lists =~= old_self.lists.remove(id).insert(id, owner));
1235 let ghost new_id = self.lists[id].list_id;
1236
1237 assert forall|i: ListId| #[trigger]
1238 self.lists.dom().contains(i) && i != id && self.lists[i].list_id
1239 != 0 implies self.lists[i].list_id != new_id by {
1240 assert(old_self.lists.dom().contains(i));
1241 assert(old_self.lists[i] == self.lists[i]);
1242 if old_self.lists[id].list_id != 0 {
1243 assert(new_id == old_self.lists[id].list_id);
1244 } else {
1245 assert(used.contains(self.lists[i].list_id));
1246 }
1247 };
1248
1249 assert forall|i: ListId| #[trigger] self.lists.dom().contains(i) implies {
1250 &&& self.lists[i].inv()
1251 &&& self.lists[i].relate_region(self.regions)
1252 } by {
1253 if i != id {
1254 assert(old_self.lists.dom().contains(i));
1255 assert(old_self.lists[i] == self.lists[i]);
1256 assert(old_self.lists[i].relate_region(old_regions));
1257 if self.lists[i].list.len() > 0 {
1258 assert(self.lists[i].list_id != new_id);
1259 }
1260 }
1261 };
1262
1263 assert forall|lid2: LooseId| #[trigger] self.loose.dom().contains(lid2) implies {
1264 &&& self.loose[lid2].inv()
1265 &&& self.loose[lid2].global_inv(self.regions)
1266 &&& self.loose[lid2].frame_link_inv(self.regions)
1267 &&& self.regions.slot_owners[self.loose[lid2].slot_index].in_list_perm.value() == 0
1268 } by {
1269 assert(lid2 != lid);
1270 assert(old_self.loose.dom().contains(lid2));
1271 assert(old_self.loose[lid2] == self.loose[lid2]);
1272 assert(old_self.loose[lid2].global_inv(old_regions));
1273 assert(old_self.loose[lid2].frame_link_inv(old_regions));
1274 assert(old_regions.slot_owners[self.loose[lid2].slot_index].in_list_perm.value() == 0);
1275 assert(self.loose[lid2].slot_index != fidx);
1276 };
1277
1278 assert forall|i1: ListId, i2: ListId| #[trigger]
1279 self.lists.dom().contains(i1) && #[trigger] self.lists.dom().contains(i2)
1280 && self.lists[i1].list.len() > 0 && self.lists[i2].list.len() > 0
1281 && self.lists[i1].list_id == self.lists[i2].list_id implies i1 == i2 by {
1282 if i1 != id && i2 != id {
1283 assert(old_self.lists[i1] == self.lists[i1]);
1284 assert(old_self.lists[i2] == self.lists[i2]);
1285 } else if i1 == id && i2 != id {
1286 assert(self.lists[i2].list_id != new_id);
1287 } else if i2 == id && i1 != id {
1288 assert(self.lists[i1].list_id != new_id);
1289 }
1290 };
1291
1292 assert forall|l1: LooseId, l2: LooseId| #[trigger]
1293 self.loose.dom().contains(l1) && #[trigger] self.loose.dom().contains(l2)
1294 && self.loose[l1].slot_index == self.loose[l2].slot_index implies l1 == l2 by {
1295 assert(old_self.loose.dom().contains(l1));
1296 assert(old_self.loose.dom().contains(l2));
1297 };
1298
1299 assert(self.cursors == old_self.cursors);
1301 assert(self.lists.dom() =~= old_self.lists.dom());
1302 assert forall|cid: CursorId| #[trigger] self.cursors.dom().contains(cid) implies {
1303 &&& self.cursors[cid].list_own.inv()
1304 &&& self.cursors[cid].wf_with_region(self.regions)
1305 } by {
1306 assert(old_self.cursors.dom().contains(cid));
1307 assert(old_self.cursors[cid].wf_with_region(old_regions));
1308 assert(self.cursors[cid].list_own.relate_region(old_regions));
1309 if old_self.lists[id].list_id != 0 {
1310 assert(new_id == old_self.lists[id].list_id);
1311 } else {
1312 assert(used.contains(self.cursors[cid].list_own.list_id));
1313 }
1314 assert(self.cursors[cid].list_own.list_id != new_id);
1315 assert(self.cursors[cid].list_own.relate_region(self.regions));
1316 };
1317 assert forall|id2: ListId, cid: CursorId| #[trigger]
1318 self.lists.dom().contains(id2) && #[trigger] self.cursors.dom().contains(cid)
1319 && self.lists[id2].list_id == self.cursors[cid].list_own.list_id
1320 && self.lists[id2].list_id != 0 implies false by {
1321 assert(old_self.cursors.dom().contains(cid));
1322 if id2 == id {
1323 assert(self.lists[id].list_id == new_id);
1324 if old_self.lists[id].list_id != 0 {
1325 assert(new_id == old_self.lists[id].list_id);
1326 } else {
1327 assert(used.contains(self.cursors[cid].list_own.list_id));
1328 }
1329 } else {
1330 assert(old_self.lists.dom().contains(id2));
1331 assert(old_self.lists[id2] == self.lists[id2]);
1332 }
1333 };
1334 assert forall|cid1: CursorId, cid2: CursorId| #[trigger]
1335 self.cursors.dom().contains(cid1) && #[trigger] self.cursors.dom().contains(cid2)
1336 && self.cursors[cid1].list_own.list_id == self.cursors[cid2].list_own.list_id
1337 && self.cursors[cid1].list_own.list_id != 0 implies cid1 == cid2 by {
1338 assert(old_self.cursors.dom().contains(cid1));
1339 assert(old_self.cursors.dom().contains(cid2));
1340 };
1341 }
1342
1343 pub proof fn step_pop_back(tracked &mut self, id: ListId) -> (res: Option<LooseId>)
1347 requires
1348 old(self).inv(),
1349 old(self).lists.dom().contains(id),
1350 ensures
1351 final(self).inv(),
1352 old(self).lists[id].list.len() == 0 ==> res is None && *final(self) == *old(self),
1353 old(self).lists[id].list.len() > 0 ==> res is Some,
1354 {
1355 if self.lists[id].list.len() == 0 {
1356 Option::None
1357 } else {
1358 let ghost old_self = *self;
1359 let ghost old_regions = self.regions;
1360 let ghost popped_idx = meta_to_index(
1361 self.lists[id].list[self.lists[id].list.len() - 1].paddr,
1362 );
1363 let ghost old_list_id = self.lists[id].list_id;
1364 assert(self.lists[id].relate_region(self.regions));
1365
1366 let tracked mut owner = self.lists.tracked_remove(id);
1367 let tracked frame_own = tracked_pop_back_embedded(&mut self.regions, &mut owner);
1368 self.lists.tracked_insert(id, owner);
1369 let ghost new_loose = fresh_loose_id(self.loose);
1370 lemma_fresh_loose_id_not_in_dom(self.loose);
1371 self.loose.tracked_insert(new_loose, frame_own);
1372
1373 assert(self.lists =~= old_self.lists.remove(id).insert(id, owner));
1374 assert(self.loose =~= old_self.loose.insert(new_loose, frame_own));
1375 assert(self.lists[id].list_id == old_list_id);
1376 assert(frame_own.slot_index == popped_idx);
1377
1378 assert forall|i: ListId| #[trigger] self.lists.dom().contains(i) implies {
1379 &&& self.lists[i].inv()
1380 &&& self.lists[i].relate_region(self.regions)
1381 } by {
1382 if i != id {
1383 assert(old_self.lists.dom().contains(i));
1384 assert(old_self.lists[i] == self.lists[i]);
1385 assert(old_self.lists[i].relate_region(old_regions));
1386 if self.lists[i].list.len() > 0 {
1387 assert(self.lists[i].list_id != old_list_id);
1388 }
1389 }
1390 };
1391
1392 assert forall|lid2: LooseId| #[trigger] self.loose.dom().contains(lid2) implies {
1393 &&& self.loose[lid2].inv()
1394 &&& self.loose[lid2].global_inv(self.regions)
1395 &&& self.loose[lid2].frame_link_inv(self.regions)
1396 &&& self.regions.slot_owners[self.loose[lid2].slot_index].in_list_perm.value() == 0
1397 } by {
1398 if lid2 != new_loose {
1399 assert(old_self.loose.dom().contains(lid2));
1400 assert(old_self.loose[lid2] == self.loose[lid2]);
1401 assert(old_self.loose[lid2].global_inv(old_regions));
1402 assert(old_self.loose[lid2].frame_link_inv(old_regions));
1403 assert(old_regions.slot_owners[self.loose[lid2].slot_index].in_list_perm.value()
1404 == 0);
1405 }
1406 };
1407
1408 assert forall|i1: ListId, i2: ListId| #[trigger]
1409 self.lists.dom().contains(i1) && #[trigger] self.lists.dom().contains(i2)
1410 && self.lists[i1].list_id == self.lists[i2].list_id && self.lists[i1].list_id
1411 != 0 implies i1 == i2 by {
1412 assert(old_self.lists.dom().contains(i1));
1413 assert(old_self.lists.dom().contains(i2));
1414 assert(self.lists[i1].list_id == old_self.lists[i1].list_id);
1415 assert(self.lists[i2].list_id == old_self.lists[i2].list_id);
1416 };
1417
1418 assert forall|l1: LooseId, l2: LooseId| #[trigger]
1419 self.loose.dom().contains(l1) && #[trigger] self.loose.dom().contains(l2)
1420 && self.loose[l1].slot_index == self.loose[l2].slot_index implies l1 == l2 by {
1421 if l1 == new_loose && l2 != new_loose {
1422 assert(old_self.loose.dom().contains(l2));
1423 assert(self.loose[l2].slot_index != popped_idx);
1424 } else if l2 == new_loose && l1 != new_loose {
1425 assert(old_self.loose.dom().contains(l1));
1426 assert(self.loose[l1].slot_index != popped_idx);
1427 } else if l1 != new_loose && l2 != new_loose {
1428 assert(old_self.loose.dom().contains(l1));
1429 assert(old_self.loose.dom().contains(l2));
1430 }
1431 };
1432
1433 assert(self.cursors == old_self.cursors);
1435 assert(self.lists.dom() =~= old_self.lists.dom());
1436 assert forall|cid: CursorId| #[trigger] self.cursors.dom().contains(cid) implies {
1437 &&& self.cursors[cid].list_own.inv()
1438 &&& self.cursors[cid].wf_with_region(self.regions)
1439 } by {
1440 assert(old_self.cursors.dom().contains(cid));
1441 assert(old_self.cursors[cid].wf_with_region(old_regions));
1442 assert(self.cursors[cid].list_own.relate_region(old_regions));
1443 assert(old_self.lists.dom().contains(id));
1444 assert(old_self.lists[id].list_id == old_list_id);
1445 assert(self.cursors[cid].list_own.list_id != old_list_id);
1446 assert(self.cursors[cid].list_own.relate_region(self.regions));
1447 };
1448 assert forall|id2: ListId, cid: CursorId| #[trigger]
1449 self.lists.dom().contains(id2) && #[trigger] self.cursors.dom().contains(cid)
1450 && self.lists[id2].list_id == self.cursors[cid].list_own.list_id
1451 && self.lists[id2].list_id != 0 implies false by {
1452 assert(old_self.cursors.dom().contains(cid));
1453 assert(old_self.lists.dom().contains(id2));
1454 assert(old_self.lists[id2].list_id == self.lists[id2].list_id);
1455 };
1456 assert forall|cid1: CursorId, cid2: CursorId| #[trigger]
1457 self.cursors.dom().contains(cid1) && #[trigger] self.cursors.dom().contains(cid2)
1458 && self.cursors[cid1].list_own.list_id == self.cursors[cid2].list_own.list_id
1459 && self.cursors[cid1].list_own.list_id != 0 implies cid1 == cid2 by {
1460 assert(old_self.cursors.dom().contains(cid1));
1461 assert(old_self.cursors.dom().contains(cid2));
1462 };
1463 Option::Some(new_loose)
1464 }
1465 }
1466
1467 pub proof fn step_insert_before_at(tracked &mut self, id: ListId, n: int, lid: LooseId)
1470 requires
1471 old(self).inv(),
1472 old(self).lists.dom().contains(id),
1473 old(self).loose.dom().contains(lid),
1474 0 <= n <= old(self).lists[id].list.len(),
1475 ensures
1476 final(self).inv(),
1477 {
1478 let ghost old_self = *self;
1479 let ghost old_regions = self.regions;
1480 let ghost fidx = self.loose[lid].slot_index;
1481 let ghost used = Set::<u64>::full().unwrap().filter(
1482 |x: u64|
1483 (exists|i: ListId| #[trigger]
1484 old_self.lists.dom().contains(i) && i != id && old_self.lists[i].list_id == x)
1485 || (exists|cid: CursorId| #[trigger]
1486 old_self.cursors.dom().contains(cid) && old_self.cursors[cid].list_own.list_id
1487 == x),
1488 );
1489 assert(self.lists[id].relate_region(self.regions));
1490 assert(self.loose[lid].global_inv(self.regions));
1491 assert(self.loose[lid].frame_link_inv(self.regions));
1492 assert(self.regions.slot_owners[fidx].in_list_perm.value() == 0);
1493
1494 let tracked mut owner = self.lists.tracked_remove(id);
1495 let tracked mut frame_own = self.loose.tracked_remove(lid);
1496 insert_before_at_embedded(&mut self.regions, &mut owner, &mut frame_own, n, used);
1497 self.lists.tracked_insert(id, owner);
1498 assert(self.loose =~= old_self.loose.remove(lid));
1499 assert(self.lists =~= old_self.lists.remove(id).insert(id, owner));
1500 let ghost new_id = self.lists[id].list_id;
1501
1502 assert forall|i: ListId| #[trigger]
1503 self.lists.dom().contains(i) && i != id && self.lists[i].list_id
1504 != 0 implies self.lists[i].list_id != new_id by {
1505 assert(old_self.lists.dom().contains(i));
1506 assert(old_self.lists[i] == self.lists[i]);
1507 if old_self.lists[id].list_id != 0 {
1508 assert(new_id == old_self.lists[id].list_id);
1509 } else {
1510 assert(used.contains(self.lists[i].list_id));
1511 }
1512 };
1513
1514 assert forall|i: ListId| #[trigger] self.lists.dom().contains(i) implies {
1515 &&& self.lists[i].inv()
1516 &&& self.lists[i].relate_region(self.regions)
1517 } by {
1518 if i != id {
1519 assert(old_self.lists.dom().contains(i));
1520 assert(old_self.lists[i] == self.lists[i]);
1521 assert(old_self.lists[i].relate_region(old_regions));
1522 if self.lists[i].list.len() > 0 {
1523 assert(self.lists[i].list_id != new_id);
1524 }
1525 }
1526 };
1527
1528 assert forall|lid2: LooseId| #[trigger] self.loose.dom().contains(lid2) implies {
1529 &&& self.loose[lid2].inv()
1530 &&& self.loose[lid2].global_inv(self.regions)
1531 &&& self.loose[lid2].frame_link_inv(self.regions)
1532 &&& self.regions.slot_owners[self.loose[lid2].slot_index].in_list_perm.value() == 0
1533 } by {
1534 assert(lid2 != lid);
1535 assert(old_self.loose.dom().contains(lid2));
1536 assert(old_self.loose[lid2] == self.loose[lid2]);
1537 assert(old_self.loose[lid2].global_inv(old_regions));
1538 assert(old_self.loose[lid2].frame_link_inv(old_regions));
1539 assert(old_regions.slot_owners[self.loose[lid2].slot_index].in_list_perm.value() == 0);
1540 assert(self.loose[lid2].slot_index != fidx);
1541 };
1542
1543 assert forall|i1: ListId, i2: ListId| #[trigger]
1544 self.lists.dom().contains(i1) && #[trigger] self.lists.dom().contains(i2)
1545 && self.lists[i1].list.len() > 0 && self.lists[i2].list.len() > 0
1546 && self.lists[i1].list_id == self.lists[i2].list_id implies i1 == i2 by {
1547 if i1 != id && i2 != id {
1548 assert(old_self.lists[i1] == self.lists[i1]);
1549 assert(old_self.lists[i2] == self.lists[i2]);
1550 } else if i1 == id && i2 != id {
1551 assert(self.lists[i2].list_id != new_id);
1552 } else if i2 == id && i1 != id {
1553 assert(self.lists[i1].list_id != new_id);
1554 }
1555 };
1556
1557 assert forall|l1: LooseId, l2: LooseId| #[trigger]
1558 self.loose.dom().contains(l1) && #[trigger] self.loose.dom().contains(l2)
1559 && self.loose[l1].slot_index == self.loose[l2].slot_index implies l1 == l2 by {
1560 assert(old_self.loose.dom().contains(l1));
1561 assert(old_self.loose.dom().contains(l2));
1562 };
1563
1564 assert(self.cursors == old_self.cursors);
1566 assert(self.lists.dom() =~= old_self.lists.dom());
1567 assert forall|cid: CursorId| #[trigger] self.cursors.dom().contains(cid) implies {
1568 &&& self.cursors[cid].list_own.inv()
1569 &&& self.cursors[cid].wf_with_region(self.regions)
1570 } by {
1571 assert(old_self.cursors.dom().contains(cid));
1572 assert(old_self.cursors[cid].wf_with_region(old_regions));
1573 assert(self.cursors[cid].list_own.relate_region(old_regions));
1574 if old_self.lists[id].list_id != 0 {
1575 assert(new_id == old_self.lists[id].list_id);
1576 } else {
1577 assert(used.contains(self.cursors[cid].list_own.list_id));
1578 }
1579 assert(self.cursors[cid].list_own.list_id != new_id);
1580 assert(self.cursors[cid].list_own.relate_region(self.regions));
1581 };
1582 assert forall|id2: ListId, cid: CursorId| #[trigger]
1583 self.lists.dom().contains(id2) && #[trigger] self.cursors.dom().contains(cid)
1584 && self.lists[id2].list_id == self.cursors[cid].list_own.list_id
1585 && self.lists[id2].list_id != 0 implies false by {
1586 assert(old_self.cursors.dom().contains(cid));
1587 if id2 == id {
1588 assert(self.lists[id].list_id == new_id);
1589 if old_self.lists[id].list_id != 0 {
1590 assert(new_id == old_self.lists[id].list_id);
1591 } else {
1592 assert(used.contains(self.cursors[cid].list_own.list_id));
1593 }
1594 } else {
1595 assert(old_self.lists.dom().contains(id2));
1596 assert(old_self.lists[id2] == self.lists[id2]);
1597 }
1598 };
1599 assert forall|cid1: CursorId, cid2: CursorId| #[trigger]
1600 self.cursors.dom().contains(cid1) && #[trigger] self.cursors.dom().contains(cid2)
1601 && self.cursors[cid1].list_own.list_id == self.cursors[cid2].list_own.list_id
1602 && self.cursors[cid1].list_own.list_id != 0 implies cid1 == cid2 by {
1603 assert(old_self.cursors.dom().contains(cid1));
1604 assert(old_self.cursors.dom().contains(cid2));
1605 };
1606 }
1607
1608 pub proof fn step_take_at(tracked &mut self, id: ListId, n: int) -> (res: Option<LooseId>)
1613 requires
1614 old(self).inv(),
1615 old(self).lists.dom().contains(id),
1616 ensures
1617 final(self).inv(),
1618 !(0 <= n < old(self).lists[id].list.len()) ==> res is None && *final(self) == *old(
1619 self,
1620 ),
1621 0 <= n < old(self).lists[id].list.len() ==> res is Some,
1622 {
1623 if !(0 <= n < self.lists[id].list.len()) {
1624 Option::None
1627 } else {
1628 let ghost old_self = *self;
1629 let ghost old_regions = self.regions;
1630 let ghost popped_idx = meta_to_index(self.lists[id].list[n].paddr);
1631 let ghost old_list_id = self.lists[id].list_id;
1632 assert(self.lists[id].relate_region(self.regions));
1633
1634 let tracked mut owner = self.lists.tracked_remove(id);
1635 let tracked frame_own = take_at_embedded(&mut self.regions, &mut owner, n);
1636 self.lists.tracked_insert(id, owner);
1637 let ghost new_loose = fresh_loose_id(self.loose);
1638 lemma_fresh_loose_id_not_in_dom(self.loose);
1639 self.loose.tracked_insert(new_loose, frame_own);
1640
1641 assert(self.lists =~= old_self.lists.remove(id).insert(id, owner));
1642 assert(self.loose =~= old_self.loose.insert(new_loose, frame_own));
1643 assert(self.lists[id].list_id == old_list_id);
1644 assert(frame_own.slot_index == popped_idx);
1645
1646 assert forall|i: ListId| #[trigger] self.lists.dom().contains(i) implies {
1647 &&& self.lists[i].inv()
1648 &&& self.lists[i].relate_region(self.regions)
1649 } by {
1650 if i != id {
1651 assert(old_self.lists.dom().contains(i));
1652 assert(old_self.lists[i] == self.lists[i]);
1653 assert(old_self.lists[i].relate_region(old_regions));
1654 if self.lists[i].list.len() > 0 {
1655 assert(self.lists[i].list_id != old_list_id);
1656 }
1657 }
1658 };
1659
1660 assert forall|lid2: LooseId| #[trigger] self.loose.dom().contains(lid2) implies {
1661 &&& self.loose[lid2].inv()
1662 &&& self.loose[lid2].global_inv(self.regions)
1663 &&& self.loose[lid2].frame_link_inv(self.regions)
1664 &&& self.regions.slot_owners[self.loose[lid2].slot_index].in_list_perm.value() == 0
1665 } by {
1666 if lid2 != new_loose {
1667 assert(old_self.loose.dom().contains(lid2));
1668 assert(old_self.loose[lid2] == self.loose[lid2]);
1669 assert(old_self.loose[lid2].global_inv(old_regions));
1670 assert(old_self.loose[lid2].frame_link_inv(old_regions));
1671 assert(old_regions.slot_owners[self.loose[lid2].slot_index].in_list_perm.value()
1672 == 0);
1673 }
1674 };
1675
1676 assert forall|i1: ListId, i2: ListId| #[trigger]
1677 self.lists.dom().contains(i1) && #[trigger] self.lists.dom().contains(i2)
1678 && self.lists[i1].list_id == self.lists[i2].list_id && self.lists[i1].list_id
1679 != 0 implies i1 == i2 by {
1680 assert(old_self.lists.dom().contains(i1));
1681 assert(old_self.lists.dom().contains(i2));
1682 assert(self.lists[i1].list_id == old_self.lists[i1].list_id);
1683 assert(self.lists[i2].list_id == old_self.lists[i2].list_id);
1684 };
1685
1686 assert forall|l1: LooseId, l2: LooseId| #[trigger]
1687 self.loose.dom().contains(l1) && #[trigger] self.loose.dom().contains(l2)
1688 && self.loose[l1].slot_index == self.loose[l2].slot_index implies l1 == l2 by {
1689 if l1 == new_loose && l2 != new_loose {
1690 assert(old_self.loose.dom().contains(l2));
1691 assert(self.loose[l2].slot_index != popped_idx);
1692 } else if l2 == new_loose && l1 != new_loose {
1693 assert(old_self.loose.dom().contains(l1));
1694 assert(self.loose[l1].slot_index != popped_idx);
1695 } else if l1 != new_loose && l2 != new_loose {
1696 assert(old_self.loose.dom().contains(l1));
1697 assert(old_self.loose.dom().contains(l2));
1698 }
1699 };
1700
1701 assert(self.cursors == old_self.cursors);
1706 assert(self.lists.dom() =~= old_self.lists.dom());
1707 assert forall|cid: CursorId| #[trigger] self.cursors.dom().contains(cid) implies {
1708 &&& self.cursors[cid].list_own.inv()
1709 &&& self.cursors[cid].wf_with_region(self.regions)
1710 } by {
1711 assert(old_self.cursors.dom().contains(cid));
1712 assert(old_self.cursors[cid].wf_with_region(old_regions));
1713 assert(self.cursors[cid].list_own.relate_region(old_regions));
1714 assert(old_self.lists.dom().contains(id));
1715 assert(old_self.lists[id].list_id == old_list_id);
1716 assert(self.cursors[cid].list_own.list_id != old_list_id);
1717 assert(self.cursors[cid].list_own.relate_region(self.regions));
1718 };
1719 assert forall|id2: ListId, cid: CursorId| #[trigger]
1720 self.lists.dom().contains(id2) && #[trigger] self.cursors.dom().contains(cid)
1721 && self.lists[id2].list_id == self.cursors[cid].list_own.list_id
1722 && self.lists[id2].list_id != 0 implies false by {
1723 assert(old_self.cursors.dom().contains(cid));
1724 assert(old_self.lists.dom().contains(id2));
1725 assert(old_self.lists[id2].list_id == self.lists[id2].list_id);
1726 };
1727 assert forall|cid1: CursorId, cid2: CursorId| #[trigger]
1728 self.cursors.dom().contains(cid1) && #[trigger] self.cursors.dom().contains(cid2)
1729 && self.cursors[cid1].list_own.list_id == self.cursors[cid2].list_own.list_id
1730 && self.cursors[cid1].list_own.list_id != 0 implies cid1 == cid2 by {
1731 assert(old_self.cursors.dom().contains(cid1));
1732 assert(old_self.cursors.dom().contains(cid2));
1733 };
1734 Option::Some(new_loose)
1735 }
1736 }
1737
1738 proof fn lemma_checkout_inv(old_self: Self, new_self: Self, id: ListId, index: int)
1748 requires
1749 old_self.inv(),
1750 old_self.lists.dom().contains(id),
1751 0 <= index <= old_self.lists[id].list.len(),
1752 new_self.regions == old_self.regions,
1753 new_self.loose == old_self.loose,
1754 new_self.lists == old_self.lists.remove(id),
1755 new_self.cursors == old_self.cursors.insert(
1756 id,
1757 CursorOwner::cursor_mut_at_owner(old_self.lists[id], index),
1758 ),
1759 ensures
1760 new_self.inv(),
1761 {
1762 assert forall|i: ListId| #[trigger] new_self.lists.dom().contains(i) implies {
1763 &&& new_self.lists[i].inv()
1764 &&& new_self.lists[i].relate_region(new_self.regions)
1765 } by {
1766 assert(i != id);
1767 assert(old_self.lists.dom().contains(i));
1768 assert(old_self.lists[i] == new_self.lists[i]);
1769 };
1770 assert forall|lid: LooseId| #[trigger] new_self.loose.dom().contains(lid) implies {
1771 &&& new_self.loose[lid].inv()
1772 &&& new_self.loose[lid].global_inv(new_self.regions)
1773 &&& new_self.loose[lid].frame_link_inv(new_self.regions)
1774 &&& new_self.regions.slot_owners[new_self.loose[lid].slot_index].in_list_perm.value()
1775 == 0
1776 } by {
1777 assert(old_self.loose.dom().contains(lid));
1778 };
1779 assert forall|i1: ListId, i2: ListId| #[trigger]
1780 new_self.lists.dom().contains(i1) && #[trigger] new_self.lists.dom().contains(i2)
1781 && new_self.lists[i1].list_id == new_self.lists[i2].list_id
1782 && new_self.lists[i1].list_id != 0 implies i1 == i2 by {
1783 assert(old_self.lists.dom().contains(i1));
1784 assert(old_self.lists.dom().contains(i2));
1785 };
1786 assert forall|l1: LooseId, l2: LooseId| #[trigger]
1787 new_self.loose.dom().contains(l1) && #[trigger] new_self.loose.dom().contains(l2)
1788 && new_self.loose[l1].slot_index == new_self.loose[l2].slot_index implies l1
1789 == l2 by {
1790 assert(old_self.loose.dom().contains(l1));
1791 assert(old_self.loose.dom().contains(l2));
1792 };
1793 assert(new_self.lists.dom().disjoint(new_self.cursors.dom()));
1794 assert forall|cid: CursorId| #[trigger] new_self.cursors.dom().contains(cid) implies {
1795 &&& new_self.cursors[cid].list_own.inv()
1796 &&& new_self.cursors[cid].wf_with_region(new_self.regions)
1797 } by {
1798 if cid != id {
1799 assert(old_self.cursors.dom().contains(cid));
1800 } else {
1801 assert(new_self.cursors[id].list_own == old_self.lists[id]);
1802 assert(old_self.lists[id].relate_region(old_self.regions));
1803 }
1804 };
1805 assert forall|id2: ListId, cid: CursorId| #[trigger]
1806 new_self.lists.dom().contains(id2) && #[trigger] new_self.cursors.dom().contains(cid)
1807 && new_self.lists[id2].list_id == new_self.cursors[cid].list_own.list_id
1808 && new_self.lists[id2].list_id != 0 implies false by {
1809 assert(id2 != id);
1810 assert(old_self.lists.dom().contains(id2));
1811 assert(old_self.lists[id2] == new_self.lists[id2]);
1812 if cid == id {
1813 assert(new_self.cursors[id].list_own == old_self.lists[id]);
1814 assert(old_self.lists.dom().contains(id));
1815 } else {
1816 assert(old_self.cursors.dom().contains(cid));
1817 assert(old_self.cursors[cid] == new_self.cursors[cid]);
1818 }
1819 };
1820 assert forall|cid1: CursorId, cid2: CursorId| #[trigger]
1821 new_self.cursors.dom().contains(cid1) && #[trigger] new_self.cursors.dom().contains(
1822 cid2,
1823 ) && new_self.cursors[cid1].list_own.list_id == new_self.cursors[cid2].list_own.list_id
1824 && new_self.cursors[cid1].list_own.list_id != 0 implies cid1 == cid2 by {
1825 if cid1 == id && cid2 != id {
1826 assert(old_self.cursors.dom().contains(cid2));
1827 assert(new_self.cursors[id].list_own == old_self.lists[id]);
1828 assert(old_self.lists.dom().contains(id));
1829 } else if cid2 == id && cid1 != id {
1830 assert(old_self.cursors.dom().contains(cid1));
1831 assert(new_self.cursors[id].list_own == old_self.lists[id]);
1832 assert(old_self.lists.dom().contains(id));
1833 } else if cid1 != id && cid2 != id {
1834 assert(old_self.cursors.dom().contains(cid1));
1835 assert(old_self.cursors.dom().contains(cid2));
1836 }
1837 };
1838 }
1839
1840 proof fn lemma_checkin_inv(old_self: Self, new_self: Self, id: CursorId)
1844 requires
1845 old_self.inv(),
1846 old_self.cursors.dom().contains(id),
1847 new_self.regions == old_self.regions,
1848 new_self.loose == old_self.loose,
1849 new_self.cursors == old_self.cursors.remove(id),
1850 new_self.lists == old_self.lists.insert(id, old_self.cursors[id].list_own),
1851 ensures
1852 new_self.inv(),
1853 {
1854 assert(!old_self.lists.dom().contains(id));
1855 assert forall|i: ListId| #[trigger] new_self.lists.dom().contains(i) implies {
1856 &&& new_self.lists[i].inv()
1857 &&& new_self.lists[i].relate_region(new_self.regions)
1858 } by {
1859 if i == id {
1860 assert(new_self.lists[id] == old_self.cursors[id].list_own);
1861 assert(old_self.cursors[id].wf_with_region(old_self.regions));
1862 } else {
1863 assert(old_self.lists.dom().contains(i));
1864 assert(old_self.lists[i] == new_self.lists[i]);
1865 }
1866 };
1867 assert forall|lid: LooseId| #[trigger] new_self.loose.dom().contains(lid) implies {
1868 &&& new_self.loose[lid].inv()
1869 &&& new_self.loose[lid].global_inv(new_self.regions)
1870 &&& new_self.loose[lid].frame_link_inv(new_self.regions)
1871 &&& new_self.regions.slot_owners[new_self.loose[lid].slot_index].in_list_perm.value()
1872 == 0
1873 } by {
1874 assert(old_self.loose.dom().contains(lid));
1875 };
1876 assert forall|i1: ListId, i2: ListId| #[trigger]
1877 new_self.lists.dom().contains(i1) && #[trigger] new_self.lists.dom().contains(i2)
1878 && new_self.lists[i1].list_id == new_self.lists[i2].list_id
1879 && new_self.lists[i1].list_id != 0 implies i1 == i2 by {
1880 if i1 == id && i2 != id {
1881 assert(old_self.lists.dom().contains(i2));
1882 assert(new_self.lists[id] == old_self.cursors[id].list_own);
1883 assert(old_self.cursors.dom().contains(id));
1884 } else if i2 == id && i1 != id {
1885 assert(old_self.lists.dom().contains(i1));
1886 assert(new_self.lists[id] == old_self.cursors[id].list_own);
1887 assert(old_self.cursors.dom().contains(id));
1888 } else if i1 != id && i2 != id {
1889 assert(old_self.lists.dom().contains(i1));
1890 assert(old_self.lists.dom().contains(i2));
1891 }
1892 };
1893 assert forall|l1: LooseId, l2: LooseId| #[trigger]
1894 new_self.loose.dom().contains(l1) && #[trigger] new_self.loose.dom().contains(l2)
1895 && new_self.loose[l1].slot_index == new_self.loose[l2].slot_index implies l1
1896 == l2 by {
1897 assert(old_self.loose.dom().contains(l1));
1898 assert(old_self.loose.dom().contains(l2));
1899 };
1900 assert(new_self.lists.dom().disjoint(new_self.cursors.dom()));
1901 assert forall|cid: CursorId| #[trigger] new_self.cursors.dom().contains(cid) implies {
1902 &&& new_self.cursors[cid].list_own.inv()
1903 &&& new_self.cursors[cid].wf_with_region(new_self.regions)
1904 } by {
1905 assert(cid != id);
1906 assert(old_self.cursors.dom().contains(cid));
1907 assert(old_self.cursors[cid] == new_self.cursors[cid]);
1908 };
1909 assert forall|id2: ListId, cid: CursorId| #[trigger]
1910 new_self.lists.dom().contains(id2) && #[trigger] new_self.cursors.dom().contains(cid)
1911 && new_self.lists[id2].list_id == new_self.cursors[cid].list_own.list_id
1912 && new_self.lists[id2].list_id != 0 implies false by {
1913 assert(cid != id);
1914 assert(old_self.cursors.dom().contains(cid));
1915 assert(old_self.cursors[cid] == new_self.cursors[cid]);
1916 if id2 == id {
1917 assert(new_self.lists[id] == old_self.cursors[id].list_own);
1918 assert(old_self.cursors.dom().contains(id));
1919 } else {
1920 assert(old_self.lists.dom().contains(id2));
1921 assert(old_self.lists[id2] == new_self.lists[id2]);
1922 }
1923 };
1924 assert forall|cid1: CursorId, cid2: CursorId| #[trigger]
1925 new_self.cursors.dom().contains(cid1) && #[trigger] new_self.cursors.dom().contains(
1926 cid2,
1927 ) && new_self.cursors[cid1].list_own.list_id == new_self.cursors[cid2].list_own.list_id
1928 && new_self.cursors[cid1].list_own.list_id != 0 implies cid1 == cid2 by {
1929 assert(old_self.cursors.dom().contains(cid1));
1930 assert(old_self.cursors.dom().contains(cid2));
1931 };
1932 }
1933
1934 proof fn lemma_revise_cursor_inv(old_self: Self, new_self: Self, id: CursorId)
1937 requires
1938 old_self.inv(),
1939 old_self.cursors.dom().contains(id),
1940 new_self.regions == old_self.regions,
1941 new_self.lists == old_self.lists,
1942 new_self.loose == old_self.loose,
1943 new_self.cursors.dom() == old_self.cursors.dom(),
1944 new_self.cursors[id].list_own == old_self.cursors[id].list_own,
1945 0 <= new_self.cursors[id].index <= new_self.cursors[id].list_own.list.len(),
1946 forall|c: CursorId| #[trigger]
1947 new_self.cursors.dom().contains(c) && c != id ==> new_self.cursors[c]
1948 == old_self.cursors[c],
1949 ensures
1950 new_self.inv(),
1951 {
1952 assert forall|i: ListId| #[trigger] new_self.lists.dom().contains(i) implies {
1953 &&& new_self.lists[i].inv()
1954 &&& new_self.lists[i].relate_region(new_self.regions)
1955 } by {
1956 assert(old_self.lists.dom().contains(i));
1957 };
1958 assert forall|lid: LooseId| #[trigger] new_self.loose.dom().contains(lid) implies {
1959 &&& new_self.loose[lid].inv()
1960 &&& new_self.loose[lid].global_inv(new_self.regions)
1961 &&& new_self.loose[lid].frame_link_inv(new_self.regions)
1962 &&& new_self.regions.slot_owners[new_self.loose[lid].slot_index].in_list_perm.value()
1963 == 0
1964 } by {
1965 assert(old_self.loose.dom().contains(lid));
1966 };
1967 assert forall|i1: ListId, i2: ListId| #[trigger]
1968 new_self.lists.dom().contains(i1) && #[trigger] new_self.lists.dom().contains(i2)
1969 && new_self.lists[i1].list_id == new_self.lists[i2].list_id
1970 && new_self.lists[i1].list_id != 0 implies i1 == i2 by {
1971 assert(old_self.lists.dom().contains(i1));
1972 assert(old_self.lists.dom().contains(i2));
1973 };
1974 assert forall|l1: LooseId, l2: LooseId| #[trigger]
1975 new_self.loose.dom().contains(l1) && #[trigger] new_self.loose.dom().contains(l2)
1976 && new_self.loose[l1].slot_index == new_self.loose[l2].slot_index implies l1
1977 == l2 by {
1978 assert(old_self.loose.dom().contains(l1));
1979 assert(old_self.loose.dom().contains(l2));
1980 };
1981 assert(new_self.lists.dom().disjoint(new_self.cursors.dom()));
1982 assert forall|cid: CursorId| #[trigger] new_self.cursors.dom().contains(cid) implies {
1983 &&& new_self.cursors[cid].list_own.inv()
1984 &&& new_self.cursors[cid].wf_with_region(new_self.regions)
1985 } by {
1986 assert(old_self.cursors.dom().contains(cid));
1987 if cid != id {
1988 assert(new_self.cursors[cid] == old_self.cursors[cid]);
1989 } else {
1990 assert(new_self.cursors[id].list_own == old_self.cursors[id].list_own);
1991 assert(old_self.cursors[id].wf_with_region(old_self.regions));
1992 }
1993 };
1994 assert forall|id2: ListId, cid: CursorId| #[trigger]
1995 new_self.lists.dom().contains(id2) && #[trigger] new_self.cursors.dom().contains(cid)
1996 && new_self.lists[id2].list_id == new_self.cursors[cid].list_own.list_id
1997 && new_self.lists[id2].list_id != 0 implies false by {
1998 assert(old_self.lists.dom().contains(id2));
1999 assert(old_self.cursors.dom().contains(cid));
2000 assert(new_self.cursors[cid].list_own.list_id
2001 == old_self.cursors[cid].list_own.list_id);
2002 };
2003 assert forall|cid1: CursorId, cid2: CursorId| #[trigger]
2004 new_self.cursors.dom().contains(cid1) && #[trigger] new_self.cursors.dom().contains(
2005 cid2,
2006 ) && new_self.cursors[cid1].list_own.list_id == new_self.cursors[cid2].list_own.list_id
2007 && new_self.cursors[cid1].list_own.list_id != 0 implies cid1 == cid2 by {
2008 assert(old_self.cursors.dom().contains(cid1));
2009 assert(old_self.cursors.dom().contains(cid2));
2010 assert(new_self.cursors[cid1].list_own.list_id
2011 == old_self.cursors[cid1].list_own.list_id);
2012 assert(new_self.cursors[cid2].list_own.list_id
2013 == old_self.cursors[cid2].list_own.list_id);
2014 };
2015 }
2016
2017 pub proof fn step_cursor_front_mut(tracked &mut self, id: ListId)
2021 requires
2022 old(self).inv(),
2023 old(self).lists.dom().contains(id),
2024 ensures
2025 final(self).inv(),
2026 !final(self).lists.dom().contains(id),
2027 final(self).cursors.dom().contains(id),
2028 final(self).cursors[id] == CursorOwner::front_owner(old(self).lists[id]),
2029 {
2030 let ghost old_self = *self;
2031 let tracked owner = self.lists.tracked_remove(id);
2032 let tracked cur = CursorOwner::tracked_front_owner(owner);
2033 self.cursors.tracked_insert(id, cur);
2034 assert(self.lists =~= old_self.lists.remove(id));
2035 assert(self.cursors =~= old_self.cursors.insert(
2036 id,
2037 CursorOwner::cursor_mut_at_owner(old_self.lists[id], 0),
2038 ));
2039 Self::lemma_checkout_inv(old_self, *self, id, 0);
2040 }
2041
2042 pub proof fn step_cursor_back_mut(tracked &mut self, id: ListId)
2045 requires
2046 old(self).inv(),
2047 old(self).lists.dom().contains(id),
2048 ensures
2049 final(self).inv(),
2050 !final(self).lists.dom().contains(id),
2051 final(self).cursors.dom().contains(id),
2052 final(self).cursors[id] == CursorOwner::back_owner(old(self).lists[id]),
2053 {
2054 let ghost old_self = *self;
2055 let tracked owner = self.lists.tracked_remove(id);
2056 let ghost bidx = CursorOwner::back_owner(owner).index;
2057 let tracked cur = CursorOwner::tracked_back_owner(owner);
2058 self.cursors.tracked_insert(id, cur);
2059 assert(self.lists =~= old_self.lists.remove(id));
2060 assert(self.cursors =~= old_self.cursors.insert(
2061 id,
2062 CursorOwner::cursor_mut_at_owner(old_self.lists[id], bidx),
2063 ));
2064 Self::lemma_checkout_inv(old_self, *self, id, bidx);
2065 }
2066
2067 pub proof fn step_cursor_mut_at(tracked &mut self, id: ListId, frame: Paddr) -> (res: bool)
2069 requires
2070 old(self).inv(),
2071 old(self).lists.dom().contains(id),
2072 ensures
2073 final(self).inv(),
2074 res == (exists|i: int|
2076 0 <= i < old(self).lists[id].list.len() && #[trigger] meta_to_index(
2077 old(self).lists[id].list[i].paddr,
2078 ) == frame_to_index(frame)),
2079 res ==> !final(self).lists.dom().contains(id) && final(self).cursors.dom().contains(id)
2082 && exists|i: int|
2083 0 <= i < old(self).lists[id].list.len() && #[trigger] meta_to_index(
2084 old(self).lists[id].list[i].paddr,
2085 ) == #[trigger] frame_to_index(frame) && final(self).cursors[id]
2086 == CursorOwner::cursor_mut_at_owner(old(self).lists[id], i),
2087 !res ==> *final(self) == *old(self),
2089 {
2090 if exists|i: int|
2091 0 <= i < self.lists[id].list.len() && #[trigger] meta_to_index(
2092 self.lists[id].list[i].paddr,
2093 ) == frame_to_index(frame) {
2094 let ghost index = choose|i: int|
2095 0 <= i < self.lists[id].list.len() && #[trigger] meta_to_index(
2096 self.lists[id].list[i].paddr,
2097 ) == frame_to_index(frame);
2098 let ghost old_self = *self;
2099 let tracked owner = self.lists.tracked_remove(id);
2100 let tracked cur = CursorOwner::tracked_cursor_mut_at_owner(owner, index);
2101 self.cursors.tracked_insert(id, cur);
2102 assert(self.lists =~= old_self.lists.remove(id));
2103 assert(self.cursors =~= old_self.cursors.insert(
2104 id,
2105 CursorOwner::cursor_mut_at_owner(old_self.lists[id], index),
2106 ));
2107 Self::lemma_checkout_inv(old_self, *self, id, index);
2108 true
2109 } else {
2110 false
2111 }
2112 }
2113
2114 pub proof fn step_move_next(tracked &mut self, id: CursorId)
2116 requires
2117 old(self).inv(),
2118 old(self).cursors.dom().contains(id),
2119 ensures
2120 final(self).inv(),
2121 final(self).regions == old(self).regions,
2122 final(self).cursors[id] == old(self).cursors[id].move_next_owner_spec(),
2123 {
2124 let ghost old_self = *self;
2125 let tracked cur = self.cursors.tracked_remove(id);
2126 let ghost ni = cur.move_next_owner_spec().index;
2127 let tracked CursorOwner { list_own, index: _ } = cur;
2128 let tracked cur2 = CursorOwner::tracked_cursor_mut_at_owner(list_own, ni);
2129 self.cursors.tracked_insert(id, cur2);
2130 assert(self.cursors[id] == old_self.cursors[id].move_next_owner_spec());
2131 assert(self.cursors.dom() =~= old_self.cursors.dom());
2132 Self::lemma_revise_cursor_inv(old_self, *self, id);
2133 }
2134
2135 pub proof fn step_move_prev(tracked &mut self, id: CursorId)
2137 requires
2138 old(self).inv(),
2139 old(self).cursors.dom().contains(id),
2140 ensures
2141 final(self).inv(),
2142 final(self).regions == old(self).regions,
2143 final(self).cursors[id] == old(self).cursors[id].move_prev_owner_spec(),
2144 {
2145 let ghost old_self = *self;
2146 let tracked cur = self.cursors.tracked_remove(id);
2147 let ghost ni = cur.move_prev_owner_spec().index;
2148 let tracked CursorOwner { list_own, index: _ } = cur;
2149 let tracked cur2 = CursorOwner::tracked_cursor_mut_at_owner(list_own, ni);
2150 self.cursors.tracked_insert(id, cur2);
2151 assert(self.cursors[id] == old_self.cursors[id].move_prev_owner_spec());
2152 assert(self.cursors.dom() =~= old_self.cursors.dom());
2153 Self::lemma_revise_cursor_inv(old_self, *self, id);
2154 }
2155
2156 pub proof fn step_current_meta(tracked &self, id: CursorId) -> (res: Option<LinkOwner>)
2158 requires
2159 self.inv(),
2160 self.cursors.dom().contains(id),
2161 ensures
2162 res == self.cursors[id].current(),
2163 res.is_some() <==> 0 <= self.cursors[id].index < self.cursors[id].length(),
2164 {
2165 self.cursors[id].current()
2166 }
2167
2168 pub proof fn step_as_list(tracked &self, id: CursorId) -> (res: Seq<LinkOwner>)
2171 requires
2172 self.inv(),
2173 self.cursors.dom().contains(id),
2174 ensures
2175 res == self.cursors[id].list_own.list,
2176 res.len() == self.cursors[id].length(),
2177 {
2178 self.cursors[id].list_own.list
2179 }
2180
2181 pub proof fn step_cursor_drop(tracked &mut self, id: CursorId)
2185 requires
2186 old(self).inv(),
2187 old(self).cursors.dom().contains(id),
2188 ensures
2189 final(self).inv(),
2190 !final(self).cursors.dom().contains(id),
2191 final(self).lists.dom().contains(id),
2192 final(self).lists[id] == old(self).cursors[id].list_own,
2193 {
2194 let ghost old_self = *self;
2195 let tracked cur = self.cursors.tracked_remove(id);
2196 let tracked CursorOwner { list_own, index: _ } = cur;
2197 self.lists.tracked_insert(id, list_own);
2198 assert(self.cursors =~= old_self.cursors.remove(id));
2199 assert(self.lists =~= old_self.lists.insert(id, old_self.cursors[id].list_own));
2200 Self::lemma_checkin_inv(old_self, *self, id);
2201 }
2202
2203 pub proof fn step_cursor_insert_before(tracked &mut self, id: CursorId, lid: LooseId)
2205 requires
2206 old(self).inv(),
2207 old(self).cursors.dom().contains(id),
2208 old(self).loose.dom().contains(lid),
2209 ensures
2210 final(self).inv(),
2211 {
2212 let ghost old_self = *self;
2213 let ghost old_regions = self.regions;
2214 let ghost fidx = self.loose[lid].slot_index;
2215 let ghost n = self.cursors[id].index;
2216 let ghost used = Set::<u64>::full().unwrap().filter(
2218 |x: u64|
2219 (exists|i: ListId| #[trigger]
2220 old_self.lists.dom().contains(i) && old_self.lists[i].list_id == x) || (exists|
2221 cid: CursorId,
2222 | #[trigger]
2223 old_self.cursors.dom().contains(cid) && cid != id
2224 && old_self.cursors[cid].list_own.list_id == x),
2225 );
2226 assert(self.cursors[id].wf_with_region(self.regions));
2227 assert(self.cursors[id].list_own.relate_region(self.regions));
2228 assert(self.loose[lid].global_inv(self.regions));
2229 assert(self.loose[lid].frame_link_inv(self.regions));
2230 assert(self.regions.slot_owners[fidx].in_list_perm.value() == 0);
2231
2232 let tracked cur = self.cursors.tracked_remove(id);
2233 let tracked CursorOwner { list_own: mut owner, index: _ } = cur;
2234 let tracked mut frame_own = self.loose.tracked_remove(lid);
2235 insert_before_at_embedded(&mut self.regions, &mut owner, &mut frame_own, n, used);
2236 let tracked cur2 = CursorOwner::tracked_cursor_mut_at_owner(owner, n + 1);
2237 self.cursors.tracked_insert(id, cur2);
2238 assert(self.loose =~= old_self.loose.remove(lid));
2239 assert(self.cursors =~= old_self.cursors.remove(id).insert(id, cur2));
2240 let ghost new_id = self.cursors[id].list_own.list_id;
2241 assert(self.cursors[id].list_own == owner);
2242
2243 assert forall|i: ListId| #[trigger]
2244 old_self.lists.dom().contains(i) && self.lists[i].list_id
2245 != 0 implies self.lists[i].list_id != new_id by {
2246 if old_self.cursors[id].list_own.list_id != 0 {
2247 assert(new_id == old_self.cursors[id].list_own.list_id);
2248 assert(old_self.cursors.dom().contains(id));
2249 } else {
2250 assert(used.contains(self.lists[i].list_id));
2251 }
2252 };
2253 assert forall|cid: CursorId| #[trigger]
2254 old_self.cursors.dom().contains(cid) && cid != id
2255 && old_self.cursors[cid].list_own.list_id
2256 != 0 implies old_self.cursors[cid].list_own.list_id != new_id by {
2257 if old_self.cursors[id].list_own.list_id != 0 {
2258 assert(new_id == old_self.cursors[id].list_own.list_id);
2259 } else {
2260 assert(used.contains(old_self.cursors[cid].list_own.list_id));
2261 }
2262 };
2263
2264 assert forall|i: ListId| #[trigger] self.lists.dom().contains(i) implies {
2266 &&& self.lists[i].inv()
2267 &&& self.lists[i].relate_region(self.regions)
2268 } by {
2269 assert(old_self.lists.dom().contains(i));
2270 assert(old_self.lists[i] == self.lists[i]);
2271 assert(old_self.lists[i].relate_region(old_regions));
2272 assert(self.lists[i].list_id != new_id);
2273 assert(self.lists[i].relate_region(self.regions));
2274 };
2275
2276 assert forall|lid2: LooseId| #[trigger] self.loose.dom().contains(lid2) implies {
2278 &&& self.loose[lid2].inv()
2279 &&& self.loose[lid2].global_inv(self.regions)
2280 &&& self.loose[lid2].frame_link_inv(self.regions)
2281 &&& self.regions.slot_owners[self.loose[lid2].slot_index].in_list_perm.value() == 0
2282 } by {
2283 assert(lid2 != lid);
2284 assert(old_self.loose.dom().contains(lid2));
2285 assert(old_self.loose[lid2] == self.loose[lid2]);
2286 assert(old_self.loose[lid2].global_inv(old_regions));
2287 assert(old_self.loose[lid2].frame_link_inv(old_regions));
2288 assert(old_regions.slot_owners[self.loose[lid2].slot_index].in_list_perm.value() == 0);
2289 assert(self.loose[lid2].slot_index != fidx);
2290 };
2291
2292 assert(self.lists.dom() =~= old_self.lists.dom());
2294 assert(self.cursors.dom() =~= old_self.cursors.dom());
2295 assert(self.lists.dom().disjoint(self.cursors.dom()));
2296
2297 assert forall|cid: CursorId| #[trigger] self.cursors.dom().contains(cid) implies {
2299 &&& self.cursors[cid].list_own.inv()
2300 &&& self.cursors[cid].wf_with_region(self.regions)
2301 } by {
2302 if cid == id {
2303 assert(self.cursors[id].list_own == owner);
2304 assert(self.cursors[id].index == n + 1);
2305 assert(owner.list.len() == old_self.cursors[id].list_own.list.len() + 1);
2306 } else {
2307 assert(old_self.cursors.dom().contains(cid));
2308 assert(old_self.cursors[cid] == self.cursors[cid]);
2309 assert(old_self.cursors[cid].wf_with_region(old_regions));
2310 assert(self.cursors[cid].list_own.relate_region(old_regions));
2311 assert(self.cursors[cid].list_own.list_id != new_id);
2312 assert(self.cursors[cid].list_own.relate_region(self.regions));
2313 }
2314 };
2315
2316 assert forall|id2: ListId, cid: CursorId| #[trigger]
2318 self.lists.dom().contains(id2) && #[trigger] self.cursors.dom().contains(cid)
2319 && self.lists[id2].list_id == self.cursors[cid].list_own.list_id
2320 && self.lists[id2].list_id != 0 implies false by {
2321 assert(old_self.lists.dom().contains(id2));
2322 assert(old_self.lists[id2] == self.lists[id2]);
2323 if cid == id {
2324 assert(self.cursors[id].list_own.list_id == new_id);
2325 assert(self.lists[id2].list_id != new_id);
2326 } else {
2327 assert(old_self.cursors.dom().contains(cid));
2328 assert(old_self.cursors[cid] == self.cursors[cid]);
2329 }
2330 };
2331
2332 assert forall|cid1: CursorId, cid2: CursorId| #[trigger]
2334 self.cursors.dom().contains(cid1) && #[trigger] self.cursors.dom().contains(cid2)
2335 && self.cursors[cid1].list_own.list_id == self.cursors[cid2].list_own.list_id
2336 && self.cursors[cid1].list_own.list_id != 0 implies cid1 == cid2 by {
2337 if cid1 == id && cid2 != id {
2338 assert(self.cursors[id].list_own.list_id == new_id);
2339 assert(old_self.cursors.dom().contains(cid2));
2340 assert(old_self.cursors[cid2] == self.cursors[cid2]);
2341 assert(self.cursors[cid2].list_own.list_id != new_id);
2342 } else if cid2 == id && cid1 != id {
2343 assert(self.cursors[id].list_own.list_id == new_id);
2344 assert(old_self.cursors.dom().contains(cid1));
2345 assert(old_self.cursors[cid1] == self.cursors[cid1]);
2346 assert(self.cursors[cid1].list_own.list_id != new_id);
2347 } else if cid1 != id && cid2 != id {
2348 assert(old_self.cursors.dom().contains(cid1));
2349 assert(old_self.cursors.dom().contains(cid2));
2350 }
2351 };
2352 }
2353
2354 pub proof fn step_cursor_take_current(tracked &mut self, id: CursorId) -> (res: Option<LooseId>)
2356 requires
2357 old(self).inv(),
2358 old(self).cursors.dom().contains(id),
2359 ensures
2360 final(self).inv(),
2361 !(0 <= old(self).cursors[id].index < old(self).cursors[id].length()) ==> res is None
2362 && *final(self) == *old(self),
2363 0 <= old(self).cursors[id].index < old(self).cursors[id].length() ==> res is Some,
2364 {
2365 if !(0 <= self.cursors[id].index < self.cursors[id].length()) {
2366 Option::None
2369 } else {
2370 let ghost old_self = *self;
2371 let ghost old_regions = self.regions;
2372 let ghost n = self.cursors[id].index;
2373 let ghost old_list_id = self.cursors[id].list_own.list_id;
2374 let ghost popped_idx = meta_to_index(self.cursors[id].list_own.list[n].paddr);
2375 assert(self.cursors[id].list_own.relate_region(self.regions));
2376 assert(old_list_id != 0);
2378
2379 let tracked cur = self.cursors.tracked_remove(id);
2380 let tracked CursorOwner { list_own: mut owner, index: _ } = cur;
2381 let tracked frame_own = take_at_embedded(&mut self.regions, &mut owner, n);
2382 let tracked cur2 = CursorOwner::tracked_cursor_mut_at_owner(owner, n);
2383 self.cursors.tracked_insert(id, cur2);
2384 let ghost new_loose = fresh_loose_id(self.loose);
2385 lemma_fresh_loose_id_not_in_dom(self.loose);
2386 self.loose.tracked_insert(new_loose, frame_own);
2387
2388 assert(self.cursors =~= old_self.cursors.remove(id).insert(id, cur2));
2389 assert(self.loose =~= old_self.loose.insert(new_loose, frame_own));
2390 assert(self.cursors[id].list_own.list_id == old_list_id);
2391 assert(self.cursors[id].list_own == owner);
2392 assert(frame_own.slot_index == popped_idx);
2393
2394 assert forall|i: ListId| #[trigger] self.lists.dom().contains(i) implies {
2396 &&& self.lists[i].inv()
2397 &&& self.lists[i].relate_region(self.regions)
2398 } by {
2399 assert(old_self.lists.dom().contains(i));
2400 assert(old_self.lists[i] == self.lists[i]);
2401 assert(old_self.lists[i].relate_region(old_regions));
2402 assert(old_self.cursors.dom().contains(id));
2403 assert(self.lists[i].list_id != old_list_id);
2404 assert(self.lists[i].relate_region(self.regions));
2405 };
2406
2407 assert forall|lid2: LooseId| #[trigger] self.loose.dom().contains(lid2) implies {
2410 &&& self.loose[lid2].inv()
2411 &&& self.loose[lid2].global_inv(self.regions)
2412 &&& self.loose[lid2].frame_link_inv(self.regions)
2413 &&& self.regions.slot_owners[self.loose[lid2].slot_index].in_list_perm.value() == 0
2414 } by {
2415 if lid2 != new_loose {
2416 assert(old_self.loose.dom().contains(lid2));
2417 assert(old_self.loose[lid2] == self.loose[lid2]);
2418 assert(old_self.loose[lid2].global_inv(old_regions));
2419 assert(old_self.loose[lid2].frame_link_inv(old_regions));
2420 assert(old_regions.slot_owners[self.loose[lid2].slot_index].in_list_perm.value()
2421 == 0);
2422 }
2423 };
2424
2425 assert(self.lists.dom() =~= old_self.lists.dom());
2427 assert(self.cursors.dom() =~= old_self.cursors.dom());
2428 assert(self.lists.dom().disjoint(self.cursors.dom()));
2429
2430 assert forall|cid: CursorId| #[trigger] self.cursors.dom().contains(cid) implies {
2432 &&& self.cursors[cid].list_own.inv()
2433 &&& self.cursors[cid].wf_with_region(self.regions)
2434 } by {
2435 if cid == id {
2436 assert(self.cursors[id].list_own == owner);
2437 assert(self.cursors[id].index == n);
2438 assert(owner.list.len() == old_self.cursors[id].list_own.list.len() - 1);
2439 } else {
2440 assert(old_self.cursors.dom().contains(cid));
2441 assert(old_self.cursors[cid] == self.cursors[cid]);
2442 assert(old_self.cursors[cid].wf_with_region(old_regions));
2443 assert(self.cursors[cid].list_own.relate_region(old_regions));
2444 assert(self.cursors[cid].list_own.list_id != old_list_id);
2445 assert(self.cursors[cid].list_own.relate_region(self.regions));
2446 }
2447 };
2448
2449 assert forall|id2: ListId, cid: CursorId| #[trigger]
2451 self.lists.dom().contains(id2) && #[trigger] self.cursors.dom().contains(cid)
2452 && self.lists[id2].list_id == self.cursors[cid].list_own.list_id
2453 && self.lists[id2].list_id != 0 implies false by {
2454 assert(old_self.lists.dom().contains(id2));
2455 assert(old_self.lists[id2] == self.lists[id2]);
2456 if cid == id {
2457 assert(self.cursors[id].list_own.list_id == old_list_id);
2458 assert(self.lists[id2].list_id != old_list_id);
2459 } else {
2460 assert(old_self.cursors.dom().contains(cid));
2461 assert(old_self.cursors[cid] == self.cursors[cid]);
2462 }
2463 };
2464
2465 assert forall|cid1: CursorId, cid2: CursorId| #[trigger]
2467 self.cursors.dom().contains(cid1) && #[trigger] self.cursors.dom().contains(cid2)
2468 && self.cursors[cid1].list_own.list_id == self.cursors[cid2].list_own.list_id
2469 && self.cursors[cid1].list_own.list_id != 0 implies cid1 == cid2 by {
2470 assert(old_self.cursors.dom().contains(cid1));
2471 assert(old_self.cursors.dom().contains(cid2));
2472 assert(self.cursors[cid1].list_own.list_id
2473 == old_self.cursors[cid1].list_own.list_id);
2474 assert(self.cursors[cid2].list_own.list_id
2475 == old_self.cursors[cid2].list_own.list_id);
2476 };
2477
2478 assert forall|l1: LooseId, l2: LooseId|
2480 #![trigger self.loose.dom().contains(l1), self.loose.dom().contains(l2)]
2481 self.loose.dom().contains(l1) && self.loose.dom().contains(l2)
2482 && self.loose[l1].slot_index == self.loose[l2].slot_index implies l1 == l2 by {
2483 if l1 == new_loose && l2 != new_loose {
2484 assert(old_self.loose.dom().contains(l2));
2485 assert(self.loose[l2].slot_index != popped_idx);
2486 } else if l2 == new_loose && l1 != new_loose {
2487 assert(old_self.loose.dom().contains(l1));
2488 assert(self.loose[l1].slot_index != popped_idx);
2489 } else if l1 != new_loose && l2 != new_loose {
2490 assert(old_self.loose.dom().contains(l1));
2491 assert(old_self.loose.dom().contains(l2));
2492 }
2493 };
2494 Option::Some(new_loose)
2495 }
2496 }
2497}
2498
2499}