1mod nonnull;
2
3pub use self::nonnull::NonNullExt;
4#[cfg(creusot)]
5use crate::std::mem::{align_of_logic, size_of_logic, size_of_val_logic};
6use crate::{
7 ghost::{NotObjective, Perm, perm::PermTarget},
8 invariant::Guarded,
9 prelude::*,
10};
11use core::marker::PhantomData;
12#[cfg(creusot)]
13use core::ptr::Pointee;
14
15#[logic(opaque)]
19pub fn metadata_logic<T: ?Sized>(_: *const T) -> <T as Pointee>::Metadata {
20 dead
21}
22
23#[logic(open, inline)]
43#[intrinsic("metadata_matches")]
44pub fn metadata_matches<T: ?Sized>(_value: T, _metadata: <T as Pointee>::Metadata) -> bool {
45 dead
46}
47
48#[allow(unused)]
50#[logic]
51#[intrinsic("metadata_matches_slice")]
52fn metadata_matches_slice<T>(value: [T], len: usize) -> bool {
53 pearlite! { value@.len() == len@ }
54}
55
56#[allow(unused)]
58#[logic]
59#[intrinsic("metadata_matches_str")]
60fn metadata_matches_str(value: str, len: usize) -> bool {
61 pearlite! { value@.to_bytes().len() == len@ }
62}
63
64#[allow(unused_variables)]
76#[logic(open, inline)]
77#[intrinsic("is_aligned_logic")]
78pub fn is_aligned_logic<T: ?Sized>(ptr: *const T) -> bool {
79 dead
80}
81
82#[allow(unused)]
84#[logic]
85#[intrinsic("is_aligned_logic_sized")]
86fn is_aligned_logic_sized<T>(ptr: *const T) -> bool {
87 ptr.is_aligned_to_logic(align_of_logic::<T>())
88}
89
90#[allow(unused)]
92#[logic]
93#[intrinsic("is_aligned_logic_slice")]
94fn is_aligned_logic_slice<T>(ptr: *const [T]) -> bool {
95 ptr.is_aligned_to_logic(align_of_logic::<T>())
96}
97
98#[allow(dead_code)]
109pub struct PtrDeepModel {
110 pub addr: usize,
111 runtime_metadata: usize,
112}
113
114impl<T: ?Sized> DeepModel for *mut T {
115 type DeepModelTy = PtrDeepModel;
116 #[trusted]
117 #[logic(opaque)]
118 #[ensures(result.addr == self.addr_logic())]
119 fn deep_model(self) -> Self::DeepModelTy {
120 dead
121 }
122}
123
124impl<T: ?Sized> DeepModel for *const T {
125 type DeepModelTy = PtrDeepModel;
126 #[trusted]
127 #[logic(opaque)]
128 #[ensures(result.addr == self.addr_logic())]
129 fn deep_model(self) -> Self::DeepModelTy {
130 dead
131 }
132}
133
134pub trait PointerExt<T: ?Sized>: Sized {
136 #[logic]
138 fn addr_logic(self) -> usize;
139
140 #[logic(open, sealed)]
142 fn is_null_logic(self) -> bool {
143 self.addr_logic() == 0usize
144 }
145
146 #[logic(open, sealed)]
150 fn is_aligned_to_logic(self, align: usize) -> bool {
151 pearlite! { self.addr_logic() & (align - 1usize) == 0usize }
152 }
153
154 #[logic]
160 fn is_aligned_logic(self) -> bool;
161}
162
163impl<T: ?Sized> PointerExt<T> for *const T {
164 #[logic]
165 #[cfg_attr(target_pointer_width = "16", builtin("creusot.prelude.Ptr$BW$.addr_logic_u16"))]
166 #[cfg_attr(target_pointer_width = "32", builtin("creusot.prelude.Ptr$BW$.addr_logic_u32"))]
167 #[cfg_attr(target_pointer_width = "64", builtin("creusot.prelude.Ptr$BW$.addr_logic_u64"))]
168 fn addr_logic(self) -> usize {
169 dead
170 }
171
172 #[logic(open, inline)]
173 fn is_aligned_logic(self) -> bool {
174 is_aligned_logic(self)
175 }
176}
177
178impl<T: ?Sized> PointerExt<T> for *mut T {
179 #[logic]
180 #[cfg_attr(target_pointer_width = "16", builtin("creusot.prelude.Ptr$BW$.addr_logic_u16"))]
181 #[cfg_attr(target_pointer_width = "32", builtin("creusot.prelude.Ptr$BW$.addr_logic_u32"))]
182 #[cfg_attr(target_pointer_width = "64", builtin("creusot.prelude.Ptr$BW$.addr_logic_u64"))]
183 fn addr_logic(self) -> usize {
184 dead
185 }
186
187 #[logic(open, inline)]
188 fn is_aligned_logic(self) -> bool {
189 is_aligned_logic(self)
190 }
191}
192
193pub trait SizedPointerExt<T>: PointerExt<T> {
195 #[logic]
199 #[requires(0 <= self.addr_logic()@ + offset * size_of_logic::<T>())]
200 #[requires(self.addr_logic()@ + offset * size_of_logic::<T>() <= usize::MAX@)]
201 #[ensures(result.addr_logic()@ == self.addr_logic()@ + offset * size_of_logic::<T>())]
202 fn offset_logic(self, offset: Int) -> Self;
203
204 #[logic(law)]
206 #[ensures(self.offset_logic(0) == self)]
207 fn offset_logic_zero(self);
208
209 #[logic(law)]
211 #[ensures(self.offset_logic(offset1).offset_logic(offset2) == self.offset_logic(offset1 + offset2))]
212 fn offset_logic_assoc(self, offset1: Int, offset2: Int);
213
214 #[logic]
218 fn sub_logic(self, rhs: Self) -> Int;
219
220 #[logic(law)]
221 #[ensures(self.sub_logic(self) == 0)]
222 fn sub_logic_refl(self);
223
224 #[logic(law)]
225 #[ensures(self.offset_logic(offset).sub_logic(self) == offset)]
226 #[ensures(self.sub_logic(self.offset_logic(offset)) == - offset)]
227 fn sub_offset_logic(self, offset: Int);
228}
229
230impl<T> SizedPointerExt<T> for *const T {
231 #[trusted]
232 #[logic(opaque)]
233 #[requires(0 <= self.addr_logic()@ + offset * size_of_logic::<T>())]
234 #[requires(self.addr_logic()@ + offset * size_of_logic::<T>() <= usize::MAX@)]
235 #[ensures(result.addr_logic()@ == self.addr_logic()@ + offset * size_of_logic::<T>())]
236 fn offset_logic(self, offset: Int) -> Self {
237 dead
238 }
239
240 #[trusted]
241 #[logic(law)]
242 #[ensures(self.offset_logic(0) == self)]
243 fn offset_logic_zero(self) {}
244
245 #[trusted]
246 #[logic(law)]
247 #[ensures(self.offset_logic(offset1).offset_logic(offset2) == self.offset_logic(offset1 + offset2))]
248 fn offset_logic_assoc(self, offset1: Int, offset2: Int) {}
249
250 #[allow(unused)]
251 #[trusted]
252 #[logic(opaque)]
253 fn sub_logic(self, rhs: Self) -> Int {
254 dead
255 }
256
257 #[trusted]
258 #[logic(law)]
259 #[ensures(self.sub_logic(self) == 0)]
260 fn sub_logic_refl(self) {}
261
262 #[trusted]
263 #[logic(law)]
264 #[ensures(self.offset_logic(offset).sub_logic(self) == offset)]
265 #[ensures(self.sub_logic(self.offset_logic(offset)) == - offset)]
266 fn sub_offset_logic(self, offset: Int) {}
267}
268
269impl<T> SizedPointerExt<T> for *mut T {
271 #[logic(open, inline)]
272 #[requires(0 <= self.addr_logic()@ + offset * size_of_logic::<T>())]
273 #[requires(self.addr_logic()@ + offset * size_of_logic::<T>() <= usize::MAX@)]
274 #[ensures(result.addr_logic()@ == self.addr_logic()@ + offset * size_of_logic::<T>())]
275 fn offset_logic(self, offset: Int) -> Self {
276 pearlite! { (self as *const T).offset_logic(offset) as *mut T }
277 }
278
279 #[logic(law)]
280 #[ensures(self.offset_logic(0) == self)]
281 fn offset_logic_zero(self) {}
282
283 #[logic(law)]
284 #[ensures(self.offset_logic(offset1).offset_logic(offset2) == self.offset_logic(offset1 + offset2))]
285 fn offset_logic_assoc(self, offset1: Int, offset2: Int) {}
286
287 #[logic(open, inline)]
288 fn sub_logic(self, rhs: Self) -> Int {
289 pearlite! { (self as *const T).sub_logic(rhs as *const T) }
290 }
291
292 #[logic(law)]
293 #[ensures(self.sub_logic(self) == 0)]
294 fn sub_logic_refl(self) {}
295
296 #[logic(law)]
297 #[ensures(self.offset_logic(offset).sub_logic(self) == offset)]
298 #[ensures(self.sub_logic(self.offset_logic(offset)) == - offset)]
299 fn sub_offset_logic(self, offset: Int) {}
300}
301
302pub trait SlicePointerExt<T>: PointerExt<[T]> {
307 #[logic]
309 fn thin(self) -> *const T;
310
311 #[logic]
313 fn len_logic(self) -> usize;
314
315 #[logic(law)]
317 #[ensures(self.thin() == other.thin() && self.len_logic() == other.len_logic() ==> self == other)]
318 fn slice_ptr_ext(self, other: Self);
319}
320
321impl<T> SlicePointerExt<T> for *const [T] {
322 #[logic(open, inline)]
324 fn thin(self) -> *const T {
325 self as *const T
326 }
327
328 #[logic(open, inline)]
330 fn len_logic(self) -> usize {
331 pearlite! { metadata_logic(self) }
332 }
333
334 #[trusted]
336 #[logic(law)]
337 #[ensures(self.thin() == other.thin() && self.len_logic() == other.len_logic() ==> self == other)]
338 fn slice_ptr_ext(self, other: Self) {}
339}
340
341impl<T> SlicePointerExt<T> for *mut [T] {
342 #[logic(open, inline)]
344 fn thin(self) -> *const T {
345 self as *const T
346 }
347
348 #[logic(open, inline)]
350 fn len_logic(self) -> usize {
351 pearlite! { metadata_logic(self as *const [T]) }
352 }
353
354 #[logic(law)]
356 #[ensures(self.thin() == other.thin() && self.len_logic() == other.len_logic() ==> self == other)]
357 fn slice_ptr_ext(self, other: Self) {
358 (self as *const [T]).slice_ptr_ext(other as *const [T])
359 }
360}
361
362extern_spec! {
363 impl<T: ?Sized> *const T {
364 #[check(ghost)]
365 #[logic_alias(<*const T>::addr_logic)]
366 fn addr(self) -> usize;
367
368 #[check(ghost)]
369 #[logic_alias(<*const T>::is_null_logic)]
370 fn is_null(self) -> bool;
371
372 #[check(ghost)]
373 #[erasure]
374 #[ensures(result == self as _)]
375 fn cast<U>(self) -> *const U {
376 self as _
377 }
378
379 #[check(ghost)]
380 #[erasure]
381 #[ensures(result == self as _)]
382 const fn cast_mut(self) -> *mut T {
383 self as _
384 }
385
386 #[check(terminates)]
387 #[erasure]
388 #[ensures(result == self.is_aligned_logic())]
389 fn is_aligned(self) -> bool
390 where T: Sized,
391 {
392 self.is_aligned_to(core::mem::align_of::<T>())
393 }
394
395 #[check(ghost)]
396 #[erasure]
397 #[bitwise_proof]
398 #[requires(align != 0usize && align & (align - 1usize) == 0usize)]
399 #[ensures(result == self.is_aligned_to_logic(align))]
400 fn is_aligned_to(self, align: usize) -> bool
401 {
402 if !align.is_power_of_two() {
403 ::core::panic::panic_2021!("is_aligned_to: align is not a power-of-two");
404 }
405 self.addr() & (align - 1) == 0
406 }
407 }
408
409 impl<T: ?Sized> *mut T {
410 #[check(ghost)]
411 #[logic_alias(<*mut T>::addr_logic)]
412 fn addr(self) -> usize;
413
414 #[check(ghost)]
415 #[logic_alias(<*mut T>::is_null_logic)]
416 fn is_null(self) -> bool;
417
418 #[check(ghost)]
419 #[erasure]
420 #[ensures(result == self as _)]
421 fn cast<U>(self) -> *mut U {
422 self as _
423 }
424
425 #[check(ghost)]
426 #[erasure]
427 #[ensures(result == self as _)]
428 fn cast_const(self) -> *const T {
429 self as _
430 }
431
432 #[check(terminates)]
433 #[erasure]
434 #[ensures(result == self.is_aligned_logic())]
435 fn is_aligned(self) -> bool
436 where T: Sized,
437 {
438 self.is_aligned_to(core::mem::align_of::<T>())
439 }
440
441 #[check(ghost)]
442 #[erasure]
443 #[bitwise_proof]
444 #[requires(align != 0usize && align & (align - 1usize) == 0usize)]
445 #[ensures(result == self.is_aligned_to_logic(align))]
446 fn is_aligned_to(self, align: usize) -> bool
447 {
448 if !align.is_power_of_two() {
449 ::core::panic::panic_2021!("is_aligned_to: align is not a power-of-two");
450 }
451 self.addr() & (align - 1) == 0
452 }
453 }
454
455 impl<T> *const [T] {
456 #[ensures(result == metadata_logic(self))]
457 fn len(self) -> usize;
458 }
459
460 impl<T> *mut [T] {
461 #[ensures(result == metadata_logic(self))]
462 fn len(self) -> usize;
463 }
464
465 mod core {
466 mod ptr {
467 #[check(ghost)]
468 #[ensures(result.is_null_logic())]
469 fn null<T: core::ptr::Thin + ?Sized>() -> *const T;
470
471 #[check(ghost)]
472 #[ensures(result.is_null_logic())]
473 fn null_mut<T: core::ptr::Thin + ?Sized>() -> *mut T;
474
475 #[check(ghost)]
476 #[ensures(result == (p.addr_logic() == q.addr_logic()))]
477 fn addr_eq<T: ?Sized, U: ?Sized>(p: *const T, q: *const U) -> bool;
478
479 #[check(ghost)]
480 #[ensures(result == metadata_logic(ptr))]
481 fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata;
482
483 #[check(ghost)]
486 #[ensures(false)]
487 unsafe fn read_volatile<T>(src: *const T) -> T;
488
489 #[ensures(result as *const T == data && result.len_logic() == len)]
490 fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T];
491
492 #[ensures(result as *mut T == data && result.len_logic() == len)]
493 fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T];
494 }
495 }
496
497 impl<T> Clone for *mut T {
498 #[check(ghost)]
499 #[ensures(result == *self)]
500 fn clone(&self) -> *mut T {
501 *self
502 }
503 }
504
505 impl<T> Clone for *const T {
506 #[check(ghost)]
507 #[ensures(result == *self)]
508 fn clone(&self) -> *const T {
509 *self
510 }
511 }
512}
513
514impl<T: ?Sized> PermTarget for *const T {
515 type Value = T;
516 type Objectiveness = NotObjective;
517
518 #[logic(open, inline)]
523 fn is_disjoint(&self, self_val: &T, other: &Self, other_val: &T) -> bool {
524 pearlite! {
525 size_of_val_logic(*self_val) != 0 && size_of_val_logic(*other_val) != 0 ==>
526 self.addr_logic() != other.addr_logic()
527 }
528 }
529}
530
531impl<T: ?Sized> Invariant for Perm<*const T> {
532 #[logic(open, prophetic)]
533 fn invariant(self) -> bool {
534 pearlite! {
535 !self.ward().is_null_logic()
536 && metadata_matches(*self.val_unsized(), metadata_logic(*self.ward()))
537 && inv(self.val_unsized())
538 }
539 }
540}
541
542impl<T: ?Sized> Perm<*const T> {
543 #[check(terminates)] #[ensures(*result.1.ward() == result.0 && result.1.val() == v)]
547 #[cfg(feature = "std")]
548 pub fn new(v: T) -> (*mut T, Ghost<Perm<*const T>>)
549 where
550 T: Sized,
551 {
552 Self::from_box(Box::new(v))
553 }
554
555 #[trusted]
557 #[check(terminates)] #[ensures(*result.1.ward() == result.0 && *result.1.val_unsized() == *val)]
559 #[erasure(Box::into_raw)]
560 #[cfg(feature = "std")]
561 pub fn from_box(val: Box<T>) -> (*mut T, Ghost<Perm<*const T>>) {
562 (Box::into_raw(val), Ghost::conjure())
563 }
564
565 #[trusted]
577 #[check(terminates)] #[ensures(*result.1.ward() == result.0)]
579 #[ensures(*result.1.val_unsized() == *r)]
580 #[intrinsic("perm_from_ref")]
581 pub fn from_ref(r: &T) -> (*const T, Ghost<&Perm<*const T>>) {
582 (r, Ghost::conjure())
583 }
584
585 #[trusted]
597 #[check(terminates)]
599 #[ensures(result.1.guard() == result.0)]
601 #[ensures(*result.1.inner.val_unsized() == *r)]
602 #[ensures(*(^result.1.inner).val_unsized() == ^r)]
603 #[intrinsic("perm_from_mut")]
604 pub fn from_mut<'a>(
605 r: &'a mut T,
606 ) -> (*mut T, Ghost<Guarded<&'a mut Perm<*const T>, *const T>>) {
607 (r, Ghost::conjure())
608 }
609
610 #[trusted]
629 #[check(terminates)]
630 #[requires(ptr == *own.ward())]
631 #[ensures(*result == *own.val_unsized())]
632 #[allow(unused_variables)]
633 #[intrinsic("perm_as_ref")]
634 pub unsafe fn as_ref(ptr: *const T, own: Ghost<&Perm<*const T>>) -> &T {
635 unsafe { &*ptr }
636 }
637
638 #[trusted]
657 #[check(terminates)]
658 #[allow(unused_variables)]
659 #[requires(ptr as *const T == *own.ward())]
660 #[ensures(*result == *own.val_unsized())]
661 #[ensures((^own).ward() == own.ward())]
662 #[ensures(*(^own).val_unsized() == ^result)]
663 #[intrinsic("perm_as_mut")]
664 pub unsafe fn as_mut(ptr: *mut T, own: Ghost<&mut Perm<*const T>>) -> &mut T {
665 unsafe { &mut *ptr }
666 }
667
668 #[trusted]
677 #[check(terminates)]
678 #[requires(ptr as *const T == *own.ward())]
679 #[ensures(*result == *own.val_unsized())]
680 #[allow(unused_variables)]
681 #[erasure(Box::from_raw)]
682 #[cfg(feature = "std")]
683 pub unsafe fn to_box(ptr: *mut T, own: Ghost<Perm<*const T>>) -> Box<T> {
684 unsafe { Box::from_raw(ptr) }
685 }
686
687 #[check(terminates)]
696 #[requires(ptr as *const T == *own.ward())]
697 #[cfg(feature = "std")]
698 pub unsafe fn drop(ptr: *mut T, own: Ghost<Perm<*const T>>) {
699 let _ = unsafe { Self::to_box(ptr, own) };
700 }
701}
702
703impl<T> Perm<*const [T]> {
711 #[logic(open, inline)]
713 pub fn len(self) -> Int {
714 pearlite! { self.val_unsized()@.len() }
715 }
716
717 #[trusted]
719 #[check(ghost)]
720 #[requires(0 <= index && index <= self.len())]
721 #[ensures(self.ward().thin() == result.0.ward().thin())]
722 #[ensures(self.ward().thin().offset_logic(index) == result.1.ward().thin())]
723 #[ensures(self.val_unsized()@[..index] == result.0.val_unsized()@)]
724 #[ensures(self.val_unsized()@[index..] == result.1.val_unsized()@)]
725 pub fn split_at(&self, index: Int) -> (&Self, &Self) {
726 let _ = index;
727 panic!("called ghost function in normal code")
728 }
729
730 #[trusted]
732 #[check(ghost)]
733 #[requires(0 <= index && index <= self.len())]
734 #[ensures(result.0.guard().thin() == self.ward().thin())]
735 #[ensures(result.1.guard().thin() == self.ward().thin().offset_logic(index))]
736 #[ensures(self.val_unsized()@[..index] == result.0.inner.val_unsized()@)]
737 #[ensures(self.val_unsized()@[index..] == result.1.inner.val_unsized()@)]
738 #[ensures((^self).ward() == self.ward())]
739 #[ensures((^result.0.inner).val_unsized()@.len() == index)]
740 #[ensures((^self).val_unsized()@ == (^result.0.inner).val_unsized()@.concat((^result.1.inner).val_unsized()@))]
741 pub fn split_at_mut<'a>(
742 &'a mut self,
743 #[allow(unused)] index: Int,
744 ) -> (
745 Guarded<&'a mut Perm<*const [T]>, *const [T]>,
746 Guarded<&'a mut Perm<*const [T]>, *const [T]>,
747 ) {
748 panic!("called ghost function in normal code")
749 }
750
751 #[trusted]
753 #[check(ghost)]
754 #[ensures(result.len() == self.len())]
755 #[ensures(forall<i> 0 <= i && i < self.len()
756 ==> *result[i].ward() == self.ward().thin().offset_logic(i)
757 && *result[i].val_unsized() == self.val_unsized()@[i])]
758 pub fn elements(&self) -> Seq<&Perm<*const T>> {
759 panic!("called ghost function in normal code")
760 }
761
762 #[trusted]
764 #[check(ghost)]
765 #[ensures(result.len() == self.len())]
766 #[ensures(forall<i> 0 <= i && i < self.len() ==>
767 *result[i].inner.val_unsized() == self.val_unsized()@[i] &&
768 result[i].guard() == self.ward().thin().offset_logic(i)
769 )]
770 #[ensures((^self).ward() == self.ward())]
771 #[ensures(forall<i> 0 <= i && i < self.len() ==> *(^result[i].inner).val_unsized() == (^self).val_unsized()@[i])]
772 pub fn elements_mut<'a>(&'a mut self) -> Seq<Guarded<&'a mut Perm<*const T>, *const T>> {
773 panic!("called ghost function in normal code")
774 }
775
776 #[check(ghost)]
778 #[requires(0 <= index && index < self.len())]
779 #[ensures(*result.ward() == self.ward().thin().offset_logic(index))]
780 #[ensures(*result.val_unsized() == self.val_unsized()@[index])]
781 pub fn index(&self, index: Int) -> &Perm<*const T> {
782 let mut r = self.elements();
783 r.split_off(index).pop_front().unwrap()
784 }
785
786 #[check(ghost)]
788 #[requires(0 <= index && index < self.len())]
789 #[ensures(result.guard() == self.ward().thin().offset_logic(index))]
790 #[ensures(*result.inner.val_unsized() == self.val_unsized()@[index])]
791 #[ensures((^self).ward() == self.ward())]
792 #[ensures(*(^result.inner).val_unsized() == (^self).val_unsized()@[index])]
793 #[ensures(forall<k: Int> 0 <= k && k < self.len() && k != index ==> (^self).val_unsized()@[k] == self.val_unsized()@[k])]
794 pub fn index_mut<'a>(&'a mut self, index: Int) -> Guarded<&'a mut Perm<*const T>, *const T> {
795 let mut r = self.elements_mut();
796 proof_assert! { forall<k> index < k && k < r.len() ==> r[k].inner.val_unsized() == r[index..].tail()[k-index-1].inner.val_unsized() };
797 let _r = snapshot! { r };
798 let result = r.split_off(index).pop_front().unwrap();
799 proof_assert! { forall<i> 0 <= i && i < index ==> r[i] == _r[i] }; result
801 }
802
803 #[trusted]
805 #[check(ghost)]
806 #[ensures(result.ward() == self.ward().thin())]
807 #[ensures(result.len()@ == self.len())]
808 pub fn live(&self) -> PtrLive<'_, T> {
809 panic!("called ghost function in normal code")
810 }
811
812 #[trusted]
814 #[check(ghost)]
815 #[ensures(result.ward() == self.ward().thin())]
816 #[ensures(result.len()@ == self.len())]
817 pub fn live_mut<'a, 'b>(self: &'b &'a mut Self) -> PtrLive<'a, T> {
818 panic!("called ghost function in normal code")
819 }
820}
821
822#[opaque]
830pub struct PtrLive<'a, T>(PhantomData<&'a T>);
831
832impl<T> Clone for PtrLive<'_, T> {
833 #[trusted]
834 #[check(ghost)]
835 #[ensures(result == *self)]
836 fn clone(&self) -> Self {
837 panic!("called ghost function in normal code")
838 }
839}
840
841impl<T> Copy for PtrLive<'_, T> {}
842
843impl<T> Invariant for PtrLive<'_, T> {
844 #[logic(open, prophetic)]
845 fn invariant(self) -> bool {
846 pearlite! {
847 self.len()@ * size_of_logic::<T>() <= isize::MAX@
850 && self.ward().addr_logic()@ + self.len()@ * size_of_logic::<T>() <= usize::MAX@
854 && self.ward().is_aligned_logic()
856 }
857 }
858}
859
860impl<T> PtrLive<'_, T> {
861 #[trusted]
863 #[logic(opaque)]
864 pub fn ward(self) -> *const T {
865 dead
866 }
867
868 #[trusted]
872 #[logic(opaque)]
873 pub fn len(self) -> usize {
874 dead
875 }
876
877 #[logic(open, inline)]
886 pub fn contains_range(self, ptr: *const T, len: Int) -> bool {
887 pearlite! {
888 let offset = ptr.sub_logic(self.ward());
889 ptr == self.ward().offset_logic(offset)
891 && 0 <= offset && offset <= self.len()@
892 && 0 <= offset + len && offset + len <= self.len()@
893 }
894 }
895}
896
897pub trait PtrAddExt<'a, T> {
918 #[requires(false)]
920 unsafe fn add_live(self, offset: usize, live: Ghost<PtrLive<'a, T>>) -> Self;
921
922 #[requires(false)]
924 unsafe fn offset_live(self, offset: isize, live: Ghost<PtrLive<'a, T>>) -> Self;
925}
926
927impl<'a, T> PtrAddExt<'a, T> for *const T {
928 #[trusted]
930 #[erasure(<*const T>::add)]
931 #[requires(live.contains_range(self, offset@))]
932 #[ensures(result == self.offset_logic(offset@))]
933 unsafe fn add_live(self, offset: usize, live: Ghost<PtrLive<'a, T>>) -> Self {
934 let _ = live;
935 unsafe { self.add(offset) }
936 }
937
938 #[trusted]
940 #[erasure(<*const T>::offset)]
941 #[requires(live.contains_range(self, offset@))]
942 #[ensures(result == self.offset_logic(offset@))]
943 unsafe fn offset_live(self, offset: isize, live: Ghost<PtrLive<'a, T>>) -> Self {
944 let _ = live;
945 unsafe { self.offset(offset) }
946 }
947}
948
949impl<'a, T> PtrAddExt<'a, T> for *mut T {
950 #[trusted]
952 #[erasure(<*mut T>::add)]
953 #[requires(live.contains_range(self, offset@))]
954 #[ensures(result == self.offset_logic(offset@))]
955 unsafe fn add_live(self, offset: usize, live: Ghost<PtrLive<'a, T>>) -> Self {
956 let _ = live;
957 unsafe { self.add(offset) }
958 }
959
960 #[trusted]
962 #[erasure(<*mut T>::offset)]
963 #[requires(live.contains_range(self, offset@))]
964 #[ensures(result == self.offset_logic(offset@))]
965 unsafe fn offset_live(self, offset: isize, live: Ghost<PtrLive<'a, T>>) -> Self {
966 let _ = live;
967 unsafe { self.offset(offset) }
968 }
969}