1#![allow(deprecated)]
2#![allow(unused_imports)]
3
4use core::cell::UnsafeCell;
5use core::marker;
6use core::{mem, mem::MaybeUninit};
7
8use super::invariant::*;
9use super::modes::*;
10use super::pervasive::*;
11use super::prelude::*;
12pub use super::raw_ptr::MemContents;
13use super::set::*;
14use super::*;
15
16verus! {
17
18broadcast use {super::map::group_map_axioms, super::set::group_set_axioms};
19#[verifier::external_body]
58#[verifier::accept_recursive_types(V)]
59pub struct PCell<V> {
60 ucell: UnsafeCell<MaybeUninit<V>>,
61}
62
63#[verifier::external]
66unsafe impl<T> Sync for PCell<T> {
67
68}
69
70#[verifier::external]
71unsafe impl<T> Send for PCell<T> {
72
73}
74
75#[verifier::external_body]
82#[verifier::reject_recursive_types_in_ground_variants(V)]
83pub tracked struct PointsTo<V> {
84 phantom: marker::PhantomData<V>,
85 no_copy: NoCopy,
86}
87
88pub ghost struct PointsToData<V> {
89 pub pcell: CellId,
90 #[cfg_attr(not(verus_verify_core), deprecated = "use `pcell_points!`, or `mem_contents()` instead")]
91 pub value: Option<V>,
92}
93
94#[doc(hidden)]
95pub open spec fn option_from_mem_contents<V>(val: MemContents<V>) -> Option<V> {
96 match val {
97 MemContents::Init(v) => Some(v),
98 MemContents::Uninit => None,
99 }
100}
101
102#[doc(hidden)]
103#[macro_export]
104macro_rules! pcell_opt_internal {
105 [$pcell:expr => $val:expr] => {
106 $crate::vstd::cell::PointsToData {
107 pcell: $pcell,
108 value: $val,
109 }
110 };
111}
112
113#[cfg_attr(not(verus_verify_core), deprecated = "use pcell_points! instead")]
114#[macro_export]
115macro_rules! pcell_opt {
116 [$($tail:tt)*] => {
117 ::verus_builtin_macros::verus_proof_macro_exprs!(
118 $crate::vstd::cell::pcell_opt_internal!($($tail)*)
119 )
120 }
121}
122
123pub use pcell_opt_internal;
124pub use pcell_opt;
125
126#[doc(hidden)]
127#[macro_export]
128macro_rules! pcell_points_internal {
129 [$pcell:expr => $val:expr] => {
130 $crate::vstd::cell::PointsToData {
131 pcell: $pcell,
132 value: $crate::vstd::cell::option_from_mem_contents($val),
133 }
134 };
135}
136
137#[macro_export]
138macro_rules! pcell_points {
139 [$($tail:tt)*] => {
140 ::verus_builtin_macros::verus_proof_macro_exprs!(
141 $crate::vstd::cell::pcell_points_internal!($($tail)*)
142 )
143 }
144}
145
146pub use pcell_points_internal;
147pub use pcell_points;
148
149#[verifier::external_body]
150pub struct CellId {
151 id: int,
152}
153
154impl<V> PointsTo<V> {
155 pub uninterp spec fn id(&self) -> CellId;
157
158 pub uninterp spec fn mem_contents(&self) -> MemContents<V>;
160
161 pub open spec fn view(self) -> PointsToData<V> {
162 PointsToData { pcell: self.id(), value: option_from_mem_contents(self.mem_contents()) }
163 }
164
165 #[cfg_attr(not(verus_verify_core), deprecated = "use mem_contents() instead")]
166 pub open spec fn opt_value(&self) -> Option<V> {
167 match self.mem_contents() {
168 MemContents::Init(value) => Some(value),
169 MemContents::Uninit => None,
170 }
171 }
172
173 #[verifier::inline]
175 pub open spec fn is_init(&self) -> bool {
176 self.mem_contents().is_init()
177 }
178
179 #[verifier::inline]
181 pub open spec fn is_uninit(&self) -> bool {
182 self.mem_contents().is_uninit()
183 }
184
185 #[verifier::inline]
187 pub open spec fn value(&self) -> V
188 recommends
189 self.is_init(),
190 {
191 self.mem_contents().value()
192 }
193}
194
195impl<V> PCell<V> {
196 pub uninterp spec fn id(&self) -> CellId;
198
199 #[inline(always)]
201 #[verifier::external_body]
202 pub const fn empty() -> (pt: (PCell<V>, Tracked<PointsTo<V>>))
203 ensures
204 pt.1@@ === pcell_points![ pt.0.id() => MemContents::Uninit ],
205 {
206 let p = PCell { ucell: UnsafeCell::new(MaybeUninit::uninit()) };
207 (p, Tracked::assume_new())
208 }
209
210 #[inline(always)]
211 #[verifier::external_body]
212 pub const fn new(v: V) -> (pt: (PCell<V>, Tracked<PointsTo<V>>))
213 ensures
214 pt.1@@ === pcell_points! [ pt.0.id() => MemContents::Init(v) ],
215 {
216 let p = PCell { ucell: UnsafeCell::new(MaybeUninit::new(v)) };
217 (p, Tracked::assume_new())
218 }
219
220 #[inline(always)]
221 #[verifier::external_body]
222 pub fn put(&self, Tracked(perm): Tracked<&mut PointsTo<V>>, v: V)
223 requires
224 old(perm)@ === pcell_points![ self.id() => MemContents::Uninit ],
225 ensures
226 perm@ === pcell_points![ self.id() => MemContents::Init(v) ],
227 opens_invariants none
228 no_unwind
229 {
230 unsafe {
231 *(self.ucell.get()) = MaybeUninit::new(v);
232 }
233 }
234
235 #[inline(always)]
236 #[verifier::external_body]
237 pub fn take(&self, Tracked(perm): Tracked<&mut PointsTo<V>>) -> (v: V)
238 requires
239 self.id() === old(perm)@.pcell,
240 old(perm).is_init(),
241 ensures
242 perm.id() === old(perm)@.pcell,
243 perm.mem_contents() === MemContents::Uninit,
244 v === old(perm).value(),
245 opens_invariants none
246 no_unwind
247 {
248 unsafe {
249 let mut m = MaybeUninit::uninit();
250 mem::swap(&mut m, &mut *self.ucell.get());
251 m.assume_init()
252 }
253 }
254
255 #[inline(always)]
256 #[verifier::external_body]
257 pub fn replace(&self, Tracked(perm): Tracked<&mut PointsTo<V>>, in_v: V) -> (out_v: V)
258 requires
259 self.id() === old(perm)@.pcell,
260 old(perm).is_init(),
261 ensures
262 perm.id() === old(perm)@.pcell,
263 perm.mem_contents() === MemContents::Init(in_v),
264 out_v === old(perm).value(),
265 opens_invariants none
266 no_unwind
267 {
268 unsafe {
269 let mut m = MaybeUninit::new(in_v);
270 mem::swap(&mut m, &mut *self.ucell.get());
271 m.assume_init()
272 }
273 }
274
275 #[inline(always)]
279 #[verifier::external_body]
280 pub fn borrow<'a>(&'a self, Tracked(perm): Tracked<&'a PointsTo<V>>) -> (v: &'a V)
281 requires
282 self.id() === perm@.pcell,
283 perm.is_init(),
284 ensures
285 *v === perm.value(),
286 opens_invariants none
287 no_unwind
288 {
289 unsafe { (*self.ucell.get()).assume_init_ref() }
290 }
291
292 #[inline(always)]
295 pub fn into_inner(self, Tracked(perm): Tracked<PointsTo<V>>) -> (v: V)
296 requires
297 self.id() === perm@.pcell,
298 perm.is_init(),
299 ensures
300 v === perm.value(),
301 opens_invariants none
302 no_unwind
303 {
304 let tracked mut perm = perm;
305 self.take(Tracked(&mut perm))
306 }
307 }
319
320impl<V: Copy> PCell<V> {
321 #[inline(always)]
322 #[verifier::external_body]
323 pub fn write(&self, Tracked(perm): Tracked<&mut PointsTo<V>>, in_v: V)
324 requires
325 self.id() === old(perm)@.pcell,
326 old(perm).is_init(),
327 ensures
328 perm.id() === old(perm)@.pcell,
329 perm.mem_contents() === MemContents::Init(in_v),
330 opens_invariants none
331 no_unwind
332 {
333 let _out = self.replace(Tracked(&mut *perm), in_v);
334 }
335}
336
337struct InvCellPred {}
338
339impl<T> InvariantPredicate<(Set<T>, PCell<T>), PointsTo<T>> for InvCellPred {
340 closed spec fn inv(k: (Set<T>, PCell<T>), perm: PointsTo<T>) -> bool {
341 let (possible_values, pcell) = k;
342 {
343 &&& perm.is_init()
344 &&& possible_values.contains(perm.value())
345 &&& pcell.id() === perm@.pcell
346 }
347 }
348}
349
350#[verifier::reject_recursive_types(T)]
351pub struct InvCell<T> {
352 possible_values: Ghost<Set<T>>,
353 pcell: PCell<T>,
354 perm_inv: Tracked<LocalInvariant<(Set<T>, PCell<T>), PointsTo<T>, InvCellPred>>,
355}
356
357impl<T> InvCell<T> {
358 #[verifier::type_invariant]
359 closed spec fn wf(&self) -> bool {
360 &&& self.perm_inv@.constant() === (self.possible_values@, self.pcell)
361 }
362
363 pub closed spec fn inv(&self, val: T) -> bool {
364 &&& self.possible_values@.contains(val)
365 }
366
367 pub fn new(val: T, Ghost(f): Ghost<spec_fn(T) -> bool>) -> (cell: Self)
368 requires
369 f(val),
370 ensures
371 forall|v| f(v) <==> cell.inv(v),
372 {
373 let (pcell, Tracked(perm)) = PCell::new(val);
374 let ghost possible_values = Set::new(f);
375 let tracked perm_inv = LocalInvariant::new((possible_values, pcell), perm, 0);
376 InvCell { possible_values: Ghost(possible_values), pcell, perm_inv: Tracked(perm_inv) }
377 }
378}
379
380impl<T> InvCell<T> {
381 pub fn replace(&self, val: T) -> (old_val: T)
382 requires
383 self.inv(val),
384 ensures
385 self.inv(old_val),
386 {
387 proof {
388 use_type_invariant(self);
389 }
390 let r;
391 open_local_invariant!(self.perm_inv.borrow() => perm => {
392 r = self.pcell.replace(Tracked(&mut perm), val);
393 });
394 r
395 }
396}
397
398impl<T: Copy> InvCell<T> {
399 pub fn get(&self) -> (val: T)
400 ensures
401 self.inv(val),
402 {
403 proof {
404 use_type_invariant(self);
405 }
406 let r;
407 open_local_invariant!(self.perm_inv.borrow() => perm => {
408 r = *self.pcell.borrow(Tracked(&perm));
409 });
410 r
411 }
412}
413
414}