1#[cfg(creusot)]
8use crate::{ghost::Objective, resolve::structural_resolve};
9use crate::{
10 ghost::{FnGhost, NotObjective, Plain, resource::Resource},
11 logic::{Id, ops::Fin, real::PositiveReal},
12 prelude::*,
13};
14use core::marker::PhantomData;
15
16#[derive(Copy)]
23pub struct Lifetime(Id);
24
25impl Clone for Lifetime {
26 #[check(ghost)]
27 #[ensures(result == *self)]
28 fn clone(&self) -> Self {
29 *self
30 }
31}
32
33impl Plain for Lifetime {
34 #[check(ghost)]
35 #[ensures(*result == *snap)]
36 #[allow(unused_variables)]
37 fn into_ghost(snap: Snapshot<Self>) -> Ghost<Self> {
38 let s: Snapshot<Id> = snapshot!(snap.0);
39 ghost!(Self(s.into_ghost().into_inner()))
40 }
41}
42
43pub struct LifetimeToken(Ghost<Resource<PositiveReal>>);
53
54impl LifetimeToken {
55 #[logic]
60 pub fn frac(self) -> PositiveReal {
61 self.0.val()
62 }
63
64 #[logic]
68 pub fn lft(self) -> Lifetime {
69 Lifetime(self.0.id())
70 }
71
72 #[check(ghost)]
74 #[ensures(result.frac() == PositiveReal::from_int(1))]
75 pub fn new() -> Self {
76 Self(Resource::alloc(snapshot!(PositiveReal::from_int(1))))
77 }
78
79 #[check(ghost)]
81 #[ensures(result.0.lft() == self.lft() && result.1.lft() == self.lft())]
82 #[ensures(result.0.frac() + result.1.frac() == self.frac())]
83 #[ensures(result.0.frac() == self.frac() / PositiveReal::from_int(2)
84 && result.1.frac() == self.frac() / PositiveReal::from_int(2))]
85 pub fn split(self) -> (Self, Self) {
86 let (r1, r2) = ghost! {
87 let q = snapshot!(self.frac() / PositiveReal::from_int(2));
88 self.0.into_inner().split(q, q)
89 }
90 .split();
91 (Self(r1), Self(r2))
92 }
93
94 #[check(ghost)]
97 #[ensures(result.lft() == self.lft() && (^self).lft() == (*self).lft())]
98 #[ensures(result.frac() + (^self).frac() == self.frac())]
99 #[ensures(result.frac() == self.frac() / PositiveReal::from_int(2) && (^self).frac() == self.frac() / PositiveReal::from_int(2))]
100 pub fn split_off(&mut self) -> Self {
101 Self(ghost! {
102 let half = snapshot!(self.frac() / PositiveReal::from_int(2));
103 self.0.split_off(half, half)
104 })
105 }
106
107 #[check(ghost)]
109 #[requires(self.lft() == other.lft())]
110 #[ensures(result.lft() == self.lft())]
111 #[ensures(result.frac() == self.frac() + other.frac())]
112 pub fn join(self, other: Self) -> Self {
113 Self(ghost!(self.0.into_inner().join(other.0.into_inner())))
114 }
115
116 #[check(ghost)]
118 #[requires(self.lft() == other.lft())]
119 #[ensures((^self).lft() == self.lft())]
120 #[ensures((^self).frac() == self.frac() + other.frac())]
121 pub fn join_in(&mut self, other: Self) {
122 ghost! { self.0.join_in(other.0.into_inner()) };
123 }
124
125 #[check(ghost)]
127 #[requires(self.frac() == PositiveReal::from_int(1))]
128 #[ensures(result.lft() == self.lft())]
129 pub fn end(self) -> LifetimeDead {
130 LifetimeDead(snapshot!(self.lft()))
131 }
132}
133
134impl Default for LifetimeToken {
135 #[check(ghost)]
136 #[ensures(result.frac() == PositiveReal::from_int(1))]
137 fn default() -> Self {
138 Self::new()
139 }
140}
141
142#[derive(Copy)]
149pub struct LifetimeDead(Snapshot<Lifetime>);
150
151impl Clone for LifetimeDead {
152 #[ensures(result == *self)]
153 fn clone(&self) -> Self {
154 *self
155 }
156}
157
158impl LifetimeDead {
159 #[logic]
161 pub fn lft(self) -> Lifetime {
162 *self.0
163 }
164}
165
166#[opaque]
173pub struct FullBorrow<T>(PhantomData<(*mut T, NotObjective)>);
174
175#[trusted]
176unsafe impl<T: Send> Send for FullBorrow<T> {}
177#[trusted]
178unsafe impl<T: Sync> Sync for FullBorrow<T> {}
179
180#[cfg(creusot)]
181#[trusted]
182impl<T: Objective> Objective for FullBorrow<T> {}
183
184#[opaque]
189pub struct EndBorrow<T>(PhantomData<(*mut T, NotObjective)>);
190
191#[trusted]
192unsafe impl<T: Send> Send for EndBorrow<T> {}
193#[trusted]
194unsafe impl<T: Sync> Sync for EndBorrow<T> {}
195
196#[cfg(creusot)]
197#[trusted]
198impl<T: Objective> Objective for EndBorrow<T> {}
199
200impl<T> Fin for FullBorrow<T> {
201 type Target = T;
202
203 #[logic(opaque, prophetic)]
204 fn fin<'a>(self) -> &'a T {
205 dead
206 }
207}
208
209impl<T> Resolve for FullBorrow<T> {
210 #[logic(open, prophetic)]
211 fn resolve(self) -> bool {
212 pearlite! { self.cur() == ^self }
213 }
214
215 #[trusted]
216 #[logic(prophetic)]
217 #[requires(inv(self))]
218 #[requires(structural_resolve(self))]
219 #[ensures(self.resolve())]
220 fn resolve_coherence(self) {}
221}
222
223impl<T> Invariant for FullBorrow<T> {
224 #[logic(open, prophetic, inline)]
225 #[creusot::trusted_trivial_if_param_trivial]
226 fn invariant(self) -> bool {
227 pearlite! { inv(self.cur()) && inv(^self) }
228 }
229}
230
231impl<T> FullBorrow<T> {
232 #[logic(opaque)]
234 pub fn lft(self) -> Lifetime {
235 dead
236 }
237
238 #[logic(opaque)]
240 pub fn cur(self) -> T {
241 dead
242 }
243
244 #[logic(open, prophetic)]
248 pub fn fin(self) -> T {
249 pearlite! { ^self }
250 }
251
252 #[trusted]
262 #[check(ghost)]
263 #[ensures(result.0.cur() == *x)]
264 #[ensures(result.0.lft() == *lft && result.1.lft() == *lft)]
265 #[ensures(^result.0 == ^result.1)]
266 #[allow(unused_variables)]
267 pub fn new(x: Ghost<T>, lft: Snapshot<Lifetime>) -> (Ghost<Self>, Ghost<EndBorrow<T>>) {
268 (Ghost::conjure(), Ghost::conjure())
269 }
270
271 #[trusted]
276 #[check(ghost)]
277 #[requires(self.lft() == token.lft())]
278 #[ensures(*result == self.cur())]
279 #[allow(unused_variables)]
280 pub fn borrow<'a>(&'a self, token: &'a LifetimeToken) -> &'a T {
281 unreachable!("ghost code only")
282 }
283
284 #[trusted]
296 #[check(ghost)]
297 #[requires(self.lft() == token.lft())]
298 #[ensures((^self).lft() == self.lft())]
299 #[ensures(^^self == ^*self)]
300 #[ensures((*self).cur() == *result && (^self).cur() == ^result)]
301 #[allow(unused_variables)]
302 pub fn borrow_mut<'a>(&'a mut self, token: &'a LifetimeToken) -> &'a mut T {
303 unreachable!("ghost code only")
304 }
305
306 #[trusted]
310 #[check(ghost)]
311 #[requires(self.lft() == token.lft())]
312 #[requires(forall<b: &mut T> *b == self.cur() && ^b == ^self ==>
313 f.precondition((b,)))]
314 #[ensures(exists<b: &mut T, res: &mut U>
315 *b == self.cur() && ^b == ^self && *res == result.cur() && ^res == ^result &&
316 f.postcondition_once((b,), res)
317 )]
318 #[ensures(result.lft() == self.lft())]
319 #[allow(unused_variables)]
320 pub fn map<U, F>(self, f: F, token: &LifetimeToken) -> FullBorrow<U>
321 where
322 F: for<'a> FnOnce(&'a mut T) -> &'a mut U + FnGhost,
323 {
324 unreachable!("ghost code only")
325 }
326}
327
328macro_rules! tuple_split {
329 ( $map_split:ident $( ($name:ident, $idx:tt) )+ ) => {
330 impl<$($name),+> FullBorrow<($($name,)+)> {
331 #[trusted]
333 #[check(ghost)]
334 $(
335 #[ensures(result.$idx.lft() == self.lft())]
336 #[ensures(result.$idx.cur() == self.cur().$idx && ^result.$idx == (^self).$idx)]
337 )+
338 pub fn split(self) -> ($(FullBorrow<$name>,)+){
339 unreachable!("ghost code only")
340 }
341 }
342
343 impl<T0> FullBorrow<T0> {
344 #[trusted]
345 #[check(ghost)]
346 #[requires(self.lft() == token.lft())]
347 #[requires(forall<b: &mut T0> *b == self.cur() && ^b == ^self ==>
348 f.precondition((b,)))]
349 #[ensures(exists<b: &mut T0, res: ($(&mut $name,)+)>
350 *b == self.cur() && ^b == ^self &&
351 $(*res.$idx == result.$idx.cur() && ^res.$idx == ^result.$idx &&)+
352 f.postcondition_once((b,), res)
353 )]
354 $(
355 #[ensures(result.$idx.lft() == self.lft())]
356 )+
357 #[allow(unused_variables)]
358 pub fn $map_split<$($name,)+ F>(self, f: F, token: &LifetimeToken) -> ($(FullBorrow<$name>,)+)
359 where
360 F: for<'a> FnOnce(&'a mut T0) -> ($(&'a mut $name,)+) + FnGhost,
361 {
362 unreachable!("ghost code only")
363 }
364 }
365 };
366}
367
368tuple_split! { map_split_1 (T,0) }
369tuple_split! { map_split_2 (U,0) (T,1) }
370tuple_split! { map_split_3 (V,0) (U,1) (T,2) }
371tuple_split! { map_split_4 (W,0) (V,1) (U,2) (T,3) }
372tuple_split! { map_split_5 (X,0) (W,1) (V,2) (U,3) (T,4) }
373tuple_split! { map_split_6 (Y,0) (X,1) (W,2) (V,3) (U,4) (T,5) }
374tuple_split! { map_split_7 (Z,0) (Y,1) (X,2) (W,3) (V,4) (U,5) (T,6) }
375tuple_split! { map_split_8 (A,0) (Z,1) (Y,2) (X,3) (W,4) (V,5) (U,6) (T,7) }
376tuple_split! { map_split_9 (B,0) (A,1) (Z,2) (Y,3) (X,4) (W,5) (V,6) (U,7) (T,8) }
377tuple_split! { map_split_10 (C,0) (B,1) (A,2) (Z,3) (Y,4) (X,5) (W,6) (V,7) (U,8) (T,9) }
378tuple_split! { map_split_11 (D,0) (C,1) (B,2) (A,3) (Z,4) (Y,5) (X,6) (W,7) (V,8) (U,9) (T,10) }
379tuple_split! { map_split_12 (E,0) (D,1) (C,2) (B,3) (A,4) (Z,5) (Y,6) (X,7) (W,8) (V,9) (U,10) (T,11) }
380
381impl<T> Fin for EndBorrow<T> {
382 type Target = T;
383 #[logic(opaque, prophetic)]
384 fn fin<'a>(self) -> &'a T {
385 dead
386 }
387}
388
389impl<T> EndBorrow<T> {
390 #[logic(opaque)]
392 pub fn lft(self) -> Lifetime {
393 dead
394 }
395
396 #[trusted]
398 #[check(ghost)]
399 #[requires(self.lft() == lft_dead.lft())]
400 #[ensures(result == ^self)]
401 #[allow(unused_variables)]
402 pub fn get(self, lft_dead: LifetimeDead) -> T {
403 unreachable!("ghost code only")
404 }
405}