1use vstd::atomic::*;
2use vstd::cell;
3use vstd::prelude::*;
4use vstd::seq_lib::*;
5use vstd::simple_pptr::*;
6
7use vstd::std_specs::convert::FromSpecImpl;
8use vstd_extra::cast_ptr::{Repr, ReprPtr};
9use vstd_extra::ownership::*;
10
11use core::marker::PhantomData;
12
13use super::*;
14use crate::mm::frame::{AnyFrameMeta, CursorMut, Link, LinkedList, MetaSlot};
15use crate::mm::Paddr;
16use crate::specs::arch::kspace::FRAME_METADATA_RANGE;
17use crate::specs::arch::mm::MAX_NR_PAGES;
18use crate::specs::mm::frame::mapping::META_SLOT_SIZE;
19use crate::specs::mm::frame::meta_owners::*;
20use crate::specs::mm::frame::meta_owners::*;
21use crate::specs::mm::frame::unique::UniqueFrameOwner;
22
23verus! {
24
25pub struct MetaSlotSmall;
26
27pub struct StoredLink {
29 pub next: Option<Paddr>,
30 pub prev: Option<Paddr>,
31 pub slot: MetaSlotSmall,
32}
33
34pub struct LinkInnerPerms {
35 pub storage: cell::PointsTo<MetaSlotSmall>,
36}
37
38impl<M: AnyFrameMeta + Repr<MetaSlotSmall>> AnyFrameMeta for Link<M> {
39 fn on_drop(&mut self) {
40 }
41
42 fn is_untyped(&self) -> bool {
43 false
44 }
45
46 uninterp spec fn vtable_ptr(&self) -> usize;
47}
48
49impl<M: AnyFrameMeta + Repr<MetaSlotSmall>> Repr<MetaSlotStorage> for Link<M> {
50 type Perm = LinkInnerPerms;
51
52 uninterp spec fn wf(r: MetaSlotStorage, perm: LinkInnerPerms) -> bool;
53
54 uninterp spec fn to_repr_spec(self, perm: LinkInnerPerms) -> (MetaSlotStorage, LinkInnerPerms);
55
56 #[verifier::external_body]
57 fn to_repr(self, Tracked(perm): Tracked<&mut LinkInnerPerms>) -> MetaSlotStorage {
58 unimplemented!()
59 }
60
61 uninterp spec fn from_repr_spec(r: MetaSlotStorage, perm: LinkInnerPerms) -> Self;
62
63 #[verifier::external_body]
64 fn from_repr(r: MetaSlotStorage, Tracked(perm): Tracked<&LinkInnerPerms>) -> Self {
65 unimplemented!()
66 }
67
68 #[verifier::external_body]
69 fn from_borrowed<'a>(r: &'a MetaSlotStorage, Tracked(perm): Tracked<&'a LinkInnerPerms>) -> &'a Self {
70 unimplemented!()
71 }
72
73 proof fn from_to_repr(self, perm: LinkInnerPerms) {
74 admit();
75 }
76
77 proof fn to_from_repr(r: MetaSlotStorage, perm: LinkInnerPerms) {
78 admit();
79 }
80
81 proof fn to_repr_wf(self, perm: LinkInnerPerms) {
82 admit();
83 }
84}
85
86pub ghost struct LinkModel {
87 pub paddr: Paddr,
88}
89
90impl Inv for LinkModel {
91 open spec fn inv(self) -> bool {
92 true
93 }
94}
95
96pub tracked struct LinkOwner {
97 pub paddr: Paddr,
98 pub in_list: u64,
99}
100
101impl Inv for LinkOwner {
102 open spec fn inv(self) -> bool {
103 true
104 }
105}
106
107impl View for LinkOwner {
108 type V = LinkModel;
109
110 open spec fn view(&self) -> Self::V {
111 LinkModel { paddr: self.paddr }
112 }
113}
114
115impl InvView for LinkOwner {
116 proof fn view_preserves_inv(self) {
117 }
118}
119
120impl<M: AnyFrameMeta + Repr<MetaSlotSmall>> OwnerOf for Link<M> {
121 type Owner = LinkOwner;
122
123 open spec fn wf(self, owner: Self::Owner) -> bool {
124 true
125 }
130}
131
132impl<M: AnyFrameMeta + Repr<MetaSlotSmall>> ModelOf for Link<M> {
133
134}
135
136pub ghost struct LinkedListModel {
137 pub list: Seq<LinkModel>,
138}
139
140impl LinkedListModel {
141 pub open spec fn front(self) -> Option<LinkModel> {
142 if self.list.len() > 0 {
143 Some(self.list[0])
144 } else {
145 None
146 }
147 }
148
149 pub open spec fn back(self) -> Option<LinkModel> {
150 if self.list.len() > 0 {
151 Some(self.list[self.list.len() - 1])
152 } else {
153 None
154 }
155 }
156}
157
158impl Inv for LinkedListModel {
159 open spec fn inv(self) -> bool {
160 true
161 }
162}
163
164pub tracked struct LinkedListOwner<M: AnyFrameMeta + Repr<MetaSlotSmall>> {
165 pub list: Seq<LinkOwner>,
166 pub perms: Map<int, vstd_extra::cast_ptr::PointsTo<MetaSlot, Metadata<Link<M>>>>,
167 pub list_id: u64,
168}
169
170impl<M: AnyFrameMeta + Repr<MetaSlotSmall>> Inv for LinkedListOwner<M> {
171 open spec fn inv(self) -> bool {
172 forall|i: int| 0 <= i < self.list.len() ==> self.inv_at(i)
173 }
174}
175
176impl<M: AnyFrameMeta + Repr<MetaSlotSmall>> LinkedListOwner<M> {
177 pub open spec fn inv_at(self, i: int) -> bool {
178 &&& self.perms.contains_key(i)
179 &&& self.perms[i].addr() == self.list[i].paddr
180 &&& self.perms[i].points_to.addr() == self.list[i].paddr
181 &&& self.perms[i].wf(&self.perms[i].inner_perms)
182 &&& self.perms[i].addr() % META_SLOT_SIZE == 0
183 &&& FRAME_METADATA_RANGE.start <= self.perms[i].addr() < FRAME_METADATA_RANGE.start
184 + MAX_NR_PAGES * META_SLOT_SIZE
185 &&& self.perms[i].is_init()
186 &&& self.perms[i].value().metadata.wf(self.list[i])
187 &&& i == 0 <==> self.perms[i].value().metadata.prev is None
188 &&& i == self.list.len() - 1 <==> self.perms[i].value().metadata.next is None
189 &&& 0 < i ==> {
190 &&& self.perms[i].value().metadata.prev is Some
191 &&& self.perms[i].value().metadata.prev.unwrap().addr() == self.perms[i - 1].addr()
192 &&& self.perms[i].value().metadata.prev.unwrap().ptr == self.perms[i - 1].points_to.pptr()
193 }
194 &&& i < self.list.len() - 1 ==> {
195 &&& self.perms[i].value().metadata.next is Some
196 &&& self.perms[i].value().metadata.next.unwrap().addr() == self.perms[i + 1].addr()
197 &&& self.perms[i].value().metadata.next.unwrap().ptr == self.perms[i + 1].points_to.pptr()
198 }
199 &&& self.list[i].inv()
200 &&& self.list[i].in_list == self.list_id
201 }
202
203 pub open spec fn view_helper(owners: Seq<LinkOwner>) -> Seq<LinkModel>
204 decreases owners.len(),
205 {
206 if owners.len() == 0 {
207 Seq::<LinkModel>::empty()
208 } else {
209 seq![owners[0].view()].add(Self::view_helper(owners.remove(0)))
210 }
211 }
212
213 pub proof fn view_preserves_len(owners: Seq<LinkOwner>)
214 ensures
215 Self::view_helper(owners).len() == owners.len(),
216 decreases owners.len(),
217 {
218 if owners.len() == 0 {
219 } else {
220 Self::view_preserves_len(owners.remove(0))
221 }
222 }
223
224 pub proof fn view_helper_index(owners: Seq<LinkOwner>, i: int)
226 requires
227 0 <= i < owners.len(),
228 ensures
229 Self::view_helper(owners)[i] == owners[i].view(),
230 decreases owners.len(),
231 {
232 Self::view_preserves_len(owners);
233 if i > 0 {
234 Self::view_helper_index(owners.remove(0), i - 1);
235 }
236 }
237
238 pub proof fn view_helper_remove(owners: Seq<LinkOwner>, i: int)
241 requires
242 0 <= i < owners.len(),
243 ensures
244 Self::view_helper(owners.remove(i)) =~= Self::view_helper(owners).remove(i),
245 {
246 Self::view_preserves_len(owners);
247 Self::view_preserves_len(owners.remove(i));
248 assert forall |j: int| 0 <= j < Self::view_helper(owners.remove(i)).len() implies
249 Self::view_helper(owners.remove(i))[j] == Self::view_helper(owners).remove(i)[j]
250 by {
251 Self::view_helper_index(owners.remove(i), j);
252 if j < i {
253 Self::view_helper_index(owners, j);
254 } else {
255 Self::view_helper_index(owners, j + 1);
256 }
257 };
258 }
259
260 pub proof fn view_helper_insert(owners: Seq<LinkOwner>, i: int, v: LinkOwner)
263 requires
264 0 <= i <= owners.len(),
265 ensures
266 Self::view_helper(owners.insert(i, v)) =~= Self::view_helper(owners).insert(i, v.view()),
267 {
268 Self::view_preserves_len(owners);
269 Self::view_preserves_len(owners.insert(i, v));
270 assert forall |j: int| 0 <= j < Self::view_helper(owners.insert(i, v)).len() implies
271 #[trigger] Self::view_helper(owners.insert(i, v))[j] == Self::view_helper(owners).insert(i, v.view())[j]
272 by {
273 Self::view_helper_index(owners.insert(i, v), j);
274 if j < i {
275 Self::view_helper_index(owners, j);
276 } else if j == i {
277 } else {
279 Self::view_helper_index(owners, j - 1);
280 }
281 };
282 }
283}
284
285impl<M: AnyFrameMeta + Repr<MetaSlotSmall>> View for LinkedListOwner<M> {
286 type V = LinkedListModel;
287
288 open spec fn view(&self) -> Self::V {
289 LinkedListModel { list: Self::view_helper(self.list) }
290 }
291}
292
293impl<M: AnyFrameMeta + Repr<MetaSlotSmall>> InvView for LinkedListOwner<M> {
294 proof fn view_preserves_inv(self) {
295 }
296}
297
298impl<M: AnyFrameMeta + Repr<MetaSlotSmall>> OwnerOf for LinkedList<M> {
299 type Owner = LinkedListOwner<M>;
300
301 open spec fn wf(self, owner: Self::Owner) -> bool {
302 &&& self.front is None <==> owner.list.len() == 0
303 &&& self.back is None <==> owner.list.len() == 0
304 &&& owner.list.len() > 0 ==> self.front is Some && self.front.unwrap().addr()
305 == owner.list[0].paddr && owner.perms[0].pptr().addr() == self.front.unwrap().addr()
306 && self.front.unwrap().ptr == owner.perms[0].points_to.pptr()
307 && self.back is Some && self.back.unwrap().addr() == owner.list[owner.list.len()
308 - 1].paddr && owner.perms[owner.list.len() - 1].pptr().addr() == self.back.unwrap().addr()
309 && self.back.unwrap().ptr == owner.perms[owner.list.len() - 1].points_to.pptr()
310 &&& self.size == owner.list.len()
311 &&& self.list_id == owner.list_id
312 }
313}
314
315impl<M: AnyFrameMeta + Repr<MetaSlotSmall>> ModelOf for LinkedList<M> {
316
317}
318
319pub ghost struct CursorModel {
320 pub ghost fore: Seq<LinkModel>,
321 pub ghost rear: Seq<LinkModel>,
322 pub ghost list_model: LinkedListModel,
323}
324
325impl Inv for CursorModel {
326 open spec fn inv(self) -> bool {
327 self.list_model.inv()
328 }
329}
330
331pub tracked struct CursorOwner<M: AnyFrameMeta + Repr<MetaSlotSmall>> {
332 pub list_own: LinkedListOwner<M>,
333 pub list_perm: PointsTo<LinkedList<M>>,
334 pub index: int,
335}
336
337impl<M: AnyFrameMeta + Repr<MetaSlotSmall>> Inv for CursorOwner<M> {
338 open spec fn inv(self) -> bool {
339 &&& 0 <= self.index <= self.length()
340 &&& self.list_own.inv()
341 }
342}
343
344impl<M: AnyFrameMeta + Repr<MetaSlotSmall>> View for CursorOwner<M> {
345 type V = CursorModel;
346
347 open spec fn view(&self) -> Self::V {
348 let list = self.list_own.view();
349 CursorModel {
350 fore: list.list.take(self.index),
351 rear: list.list.skip(self.index),
352 list_model: list,
353 }
354 }
355}
356
357impl<M: AnyFrameMeta + Repr<MetaSlotSmall>> InvView for CursorOwner<M> {
358 proof fn view_preserves_inv(self) {
359 }
360}
361
362impl<M: AnyFrameMeta + Repr<MetaSlotSmall>> OwnerOf for CursorMut<M> {
363 type Owner = CursorOwner<M>;
364
365 open spec fn wf(self, owner: Self::Owner) -> bool {
366 &&& 0 <= owner.index < owner.length() ==> self.current.is_some()
367 && self.current.unwrap().addr() == owner.list_own.list[owner.index].paddr
368 && owner.list_own.perms[owner.index].pptr().addr() == self.current.unwrap().addr()
369 && self.current.unwrap().ptr == owner.list_own.perms[owner.index].points_to.pptr()
370 &&& owner.index == owner.list_own.list.len() ==> self.current.is_none()
371 &&& owner.list_perm.pptr() == self.list
372 &&& owner.list_perm.is_init()
373 &&& owner.list_perm.mem_contents().value().wf(owner.list_own)
374 }
375}
376
377impl<M: AnyFrameMeta + Repr<MetaSlotSmall>> ModelOf for CursorMut<M> {
378
379}
380
381impl CursorModel {
382 pub open spec fn current(self) -> Option<LinkModel> {
383 if self.rear.len() > 0 {
384 Some(self.rear[0])
385 } else {
386 None
387 }
388 }
389}
390
391impl<M: AnyFrameMeta + Repr<MetaSlotSmall>> CursorOwner<M> {
392 pub open spec fn length(self) -> int {
393 self.list_own.list.len() as int
394 }
395
396 pub open spec fn current(self) -> Option<LinkOwner> {
397 if 0 <= self.index < self.length() {
398 Some(self.list_own.list[self.index])
399 } else {
400 None
401 }
402 }
403
404 pub axiom fn list_insert(
405 tracked cursor: &mut Self,
406 tracked link: &mut LinkOwner,
407 tracked perm: &vstd_extra::cast_ptr::PointsTo<MetaSlot, Metadata<Link<M>>>,
408 )
409 ensures
410 link.paddr == old(link).paddr,
411 link.in_list == cursor.list_own.list_id,
412 cursor.list_own.list == old(cursor).list_own.list.insert(old(cursor).index, *link),
413 cursor.list_own.list_id == old(cursor).list_own.list_id,
414 forall|idx: int| 0 <= idx < cursor.length() ==> cursor.list_own.perms.contains_key(idx),
415 forall|idx: int|
416 0 <= idx < cursor.index ==> cursor.list_own.perms[idx] == old(
417 cursor,
418 ).list_own.perms[idx],
419 forall|idx: int|
420 old(cursor).index < idx <= old(cursor).length() ==> cursor.list_own.perms[idx]
421 == old(cursor).list_own.perms[idx - 1],
422 cursor.list_own.perms[old(cursor).index] == perm,
423 cursor.index == old(cursor).index + 1,
424 cursor.list_perm == old(cursor).list_perm;
425
426 pub open spec fn front_owner_spec(
427 list_own: LinkedListOwner<M>,
428 list_perm: PointsTo<LinkedList<M>>,
429 ) -> Self {
430 CursorOwner::<M> { list_own: list_own, list_perm: list_perm, index: 0 }
431 }
432
433 pub open spec fn cursor_mut_at_owner_spec(
434 list_own: LinkedListOwner<M>,
435 list_perm: PointsTo<LinkedList<M>>,
436 index: int,
437 ) -> Self {
438 CursorOwner::<M> { list_own: list_own, list_perm: list_perm, index: index }
439 }
440
441 #[verifier::returns(proof)]
442 pub axiom fn cursor_mut_at_owner(list_own: LinkedListOwner<M>, list_perm: PointsTo<LinkedList<M>>, index: int) -> Self
443 returns Self::cursor_mut_at_owner_spec(list_own, list_perm, index);
444
445 #[verifier::returns(proof)]
446 pub axiom fn front_owner(
447 list_own: LinkedListOwner<M>,
448 list_perm: PointsTo<LinkedList<M>>,
449 ) -> (res: Self)
450 ensures
451 res == Self::front_owner_spec(list_own, list_perm);
452 pub open spec fn back_owner_spec(
453 list_own: LinkedListOwner<M>,
454 list_perm: PointsTo<LinkedList<M>>,
455 ) -> Self {
456 CursorOwner::<M> {
457 list_own: list_own,
458 list_perm: list_perm,
459 index: if list_own.list.len() > 0 {
460 list_own.list.len() as int - 1
461 } else {
462 0
463 },
464 }
465 }
466
467 #[verifier::returns(proof)]
468 #[verifier::external_body]
469 pub proof fn back_owner(
470 list_own: LinkedListOwner<M>,
471 list_perm: PointsTo<LinkedList<M>>,
472 ) -> (res: Self)
473 ensures
474 res == Self::back_owner_spec(list_own, list_perm),
475 {
476 CursorOwner::<M> {
477 list_own: list_own,
478 list_perm: list_perm,
479 index: if list_own.list.len() > 0 {
480 list_own.list.len() as int - 1
481 } else {
482 0
483 },
484 }
485 }
486
487 pub open spec fn ghost_owner_spec(
488 list_own: LinkedListOwner<M>,
489 list_perm: PointsTo<LinkedList<M>>,
490 ) -> Self {
491 CursorOwner::<M> {
492 list_own: list_own,
493 list_perm: list_perm,
494 index: list_own.list.len() as int,
495 }
496 }
497
498 #[verifier::returns(proof)]
499 #[verifier::external_body]
500 pub proof fn ghost_owner(
501 list_own: LinkedListOwner<M>,
502 list_perm: PointsTo<LinkedList<M>>,
503 ) -> (res: Self)
504 ensures
505 res == Self::ghost_owner_spec(list_own, list_perm),
506 {
507 CursorOwner::<M> {
508 list_own: list_own,
509 list_perm: list_perm,
510 index: list_own.list.len() as int,
511 }
512 }
513}
514
515impl<M: AnyFrameMeta + Repr<MetaSlotSmall>> UniqueFrameOwner<Link<M>> {
516 pub open spec fn frame_link_inv(&self) -> bool {
517 &&& self.meta_perm.value().metadata.prev is None
518 &&& self.meta_perm.value().metadata.next is None
519 &&& self.meta_own.paddr == self.meta_perm.addr()
520 }
521}
522
523pub struct MetadataAsLink<M: AnyFrameMeta> {
524 pub metadata: M,
525 pub next: Option<PPtr<MetaSlot>>,
526 pub prev: Option<PPtr<MetaSlot>>,
527 pub ref_count: u64,
528 pub vtable_ptr: MemContents<usize>,
529 pub in_list: u64,
530}
531
532impl<M: AnyFrameMeta + Repr<MetaSlotSmall>> Repr<MetaSlot> for MetadataAsLink<M> {
533 type Perm = MetadataInnerPerms;
534
535 uninterp spec fn wf(r: MetaSlot, perm: MetadataInnerPerms) -> bool;
536
537 uninterp spec fn to_repr_spec(self, perm: MetadataInnerPerms) -> (MetaSlot, MetadataInnerPerms);
538 #[verifier::external_body]
539 fn to_repr(self, Tracked(perm): Tracked<&mut MetadataInnerPerms>) -> MetaSlot {
540 unimplemented!()
541 }
542
543 uninterp spec fn from_repr_spec(r: MetaSlot, perm: MetadataInnerPerms) -> Self;
544
545 #[verifier::external_body]
546 fn from_repr(r: MetaSlot, Tracked(perm): Tracked<&MetadataInnerPerms>) -> Self {
547 unimplemented!()
548 }
549
550 #[verifier::external_body]
551 fn from_borrowed<'a>(r: &'a MetaSlot, Tracked(perm): Tracked<&'a MetadataInnerPerms>) -> &'a Self {
552 unimplemented!()
553 }
554
555 proof fn from_to_repr(self, perm: MetadataInnerPerms) {
556 admit();
557 }
558
559 proof fn to_from_repr(r: MetaSlot, perm: MetadataInnerPerms) {
560 admit();
561 }
562
563 proof fn to_repr_wf(self, perm: MetadataInnerPerms) {
564 admit();
565 }
566
567}
568
569impl<M: AnyFrameMeta + Repr<MetaSlotSmall>> FromSpecImpl<Metadata<Link<M>>> for MetadataAsLink<M> {
570 open spec fn obeys_from_spec() -> bool {
571 true
572 }
573
574 open spec fn from_spec(m: Metadata<Link<M>>) -> MetadataAsLink<M> {
575 MetadataAsLink {
576 metadata: m.metadata.meta,
577 next: match m.metadata.next {
578 Some(repr_ptr) => Some(repr_ptr.ptr),
579 None => None,
580 },
581 prev: match m.metadata.prev {
582 Some(repr_ptr) => Some(repr_ptr.ptr),
583 None => None,
584 },
585 ref_count: m.ref_count,
586 vtable_ptr: m.vtable_ptr,
587 in_list: m.in_list,
588 }
589 }
590}
591
592impl<M: AnyFrameMeta + Repr<MetaSlotSmall>> From<Metadata<Link<M>>> for MetadataAsLink<M> {
593 fn from(m: Metadata<Link<M>>) -> Self {
594 let next = match m.metadata.next {
595 Some(repr_ptr) => Some(repr_ptr.ptr),
596 None => None,
597 };
598 let prev = match m.metadata.prev {
599 Some(repr_ptr) => Some(repr_ptr.ptr),
600 None => None,
601 };
602 MetadataAsLink {
603 metadata: m.metadata.meta,
604 next,
605 prev,
606 ref_count: m.ref_count,
607 vtable_ptr: m.vtable_ptr,
608 in_list: m.in_list,
609 }
610 }
611}
612
613impl<M: AnyFrameMeta + Repr<MetaSlotSmall>> FromSpecImpl<MetadataAsLink<M>> for Metadata<Link<M>> {
614 open spec fn obeys_from_spec() -> bool {
615 true
616 }
617
618 open spec fn from_spec(m: MetadataAsLink<M>) -> Metadata<Link<M>> {
619 Metadata {
620 metadata: Link {
621 next: match m.next {
622 Some(pptr) => Some(ReprPtr::new_spec(pptr)),
623 None => None,
624 },
625 prev: match m.prev {
626 Some(pptr) => Some(ReprPtr::new_spec(pptr)),
627 None => None,
628 },
629 meta: m.metadata,
630 },
631 ref_count: m.ref_count,
632 vtable_ptr: m.vtable_ptr,
633 in_list: m.in_list,
634 }
635 }
636}
637
638impl<M: AnyFrameMeta + Repr<MetaSlotSmall>> From<MetadataAsLink<M>> for Metadata<Link<M>> {
639 fn from(m: MetadataAsLink<M>) -> Self {
640 let next = match m.next {
641 Some(pptr) => Some(ReprPtr::from_pptr(pptr)),
642 None => None,
643 };
644 let prev = match m.prev {
645 Some(pptr) => Some(ReprPtr::from_pptr(pptr)),
646 None => None,
647 };
648 Metadata {
649 metadata: Link { next, prev, meta: m.metadata },
650 ref_count: m.ref_count,
651 vtable_ptr: m.vtable_ptr,
652 in_list: m.in_list,
653 }
654 }
655}
656
657impl<M: AnyFrameMeta + Repr<MetaSlotSmall>> MetadataAsLink<M> {
658 pub fn cast_to_metadata(ptr: ReprPtr<MetaSlot, Self>) -> (res: ReprPtr<MetaSlot, Metadata<Link<M>>>)
659 ensures
660 res.addr() == ptr.addr(),
661 res.ptr == ptr.ptr,
662 {
663 ReprPtr { addr: ptr.addr, ptr: ptr.ptr, _T: PhantomData }
664 }
665
666 pub fn cast_from_metadata(ptr: ReprPtr<MetaSlot, Metadata<Link<M>>>) -> (res: ReprPtr<MetaSlot, Self>)
667 ensures
668 res.addr() == ptr.addr(),
669 res.ptr == ptr.ptr,
670 {
671 ReprPtr { addr: ptr.addr, ptr: ptr.ptr, _T: PhantomData }
672 }
673
674 #[verifier::external_body]
675 pub proof fn cast_points_to_metadata(tracked perm: vstd_extra::cast_ptr::PointsTo<MetaSlot, MetadataAsLink<M>>) -> (tracked result: vstd_extra::cast_ptr::PointsTo<MetaSlot, Metadata<Link<M>>>)
676 ensures
677 result.addr() == perm.addr(),
678 result.is_init() == perm.is_init(),
679 result.points_to.pptr() == perm.points_to.pptr(),
680 {
681 unimplemented!()
682 }
683
684 #[verifier::external_body]
685 pub proof fn cast_points_to_as_link(tracked perm: vstd_extra::cast_ptr::PointsTo<MetaSlot, Metadata<Link<M>>>) -> (tracked result: vstd_extra::cast_ptr::PointsTo<MetaSlot, MetadataAsLink<M>>)
686 ensures
687 result.addr() == perm.addr(),
688 result.is_init() == perm.is_init(),
689 result.points_to.pptr() == perm.points_to.pptr(),
690 {
691 unimplemented!()
692 }
693}
694
695}