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
16pub mod invcell;
17pub mod pcell;
18pub mod pcell_maybe_uninit;
19
20verus! {
23
24broadcast use {super::map::group_map_axioms, super::set::group_set_axioms};
25
26#[cfg_attr(not(verus_verify_core), deprecated = "use `vstd::cell::pcell::PCell` or `vstd::cell::pcell_maybe_uninit::PCell` instead")]
63#[verifier::external_body]
64#[verifier::accept_recursive_types(V)]
65pub struct PCell<V> {
66 ucell: UnsafeCell<MaybeUninit<V>>,
67}
68
69#[verifier::external]
72unsafe impl<T> Sync for PCell<T> {
73
74}
75
76#[verifier::external]
77unsafe impl<T> Send for PCell<T> {
78
79}
80
81#[verifier::external_body]
88#[verifier::reject_recursive_types_in_ground_variants(V)]
89pub tracked struct PointsTo<V> {
90 phantom: marker::PhantomData<V>,
91 no_copy: NoCopy,
92}
93
94pub ghost struct PointsToData<V> {
95 pub pcell: CellId,
96 pub mem_contents: MemContents<V>,
97}
98
99#[doc(hidden)]
100#[macro_export]
101macro_rules! pcell_points_internal {
102 [$pcell:expr => $val:expr] => {
103 $crate::vstd::cell::PointsToData {
104 pcell: $pcell,
105 mem_contents: $val,
106 }
107 };
108}
109
110#[macro_export]
111macro_rules! pcell_points {
112 [$($tail:tt)*] => {
113 $crate::vstd::prelude::verus_proof_macro_exprs!(
114 $crate::vstd::cell::pcell_points_internal!($($tail)*)
115 )
116 }
117}
118
119pub use pcell_points_internal;
120pub use pcell_points;
121
122#[verifier::external_body]
123pub struct CellId {
124 id: int,
125}
126
127impl<V> PointsTo<V> {
128 pub uninterp spec fn id(&self) -> CellId;
130
131 pub uninterp spec fn mem_contents(&self) -> MemContents<V>;
133
134 pub open spec fn view(self) -> PointsToData<V> {
135 PointsToData { pcell: self.id(), mem_contents: self.mem_contents() }
136 }
137
138 #[verifier::inline]
140 pub open spec fn is_init(&self) -> bool {
141 self.mem_contents().is_init()
142 }
143
144 #[verifier::inline]
146 pub open spec fn is_uninit(&self) -> bool {
147 self.mem_contents().is_uninit()
148 }
149
150 #[verifier::inline]
152 pub open spec fn value(&self) -> V
153 recommends
154 self.is_init(),
155 {
156 self.mem_contents().value()
157 }
158}
159
160impl<V> PCell<V> {
161 pub uninterp spec fn id(&self) -> CellId;
163
164 #[inline(always)]
166 #[verifier::external_body]
167 pub const fn empty() -> (pt: (PCell<V>, Tracked<PointsTo<V>>))
168 ensures
169 pt.1@@ === pcell_points![ pt.0.id() => MemContents::Uninit ],
170 {
171 let p = PCell { ucell: UnsafeCell::new(MaybeUninit::uninit()) };
172 (p, Tracked::assume_new())
173 }
174
175 #[inline(always)]
176 #[verifier::external_body]
177 pub const fn new(v: V) -> (pt: (PCell<V>, Tracked<PointsTo<V>>))
178 ensures
179 pt.1@@ === pcell_points! [ pt.0.id() => MemContents::Init(v) ],
180 {
181 let p = PCell { ucell: UnsafeCell::new(MaybeUninit::new(v)) };
182 (p, Tracked::assume_new())
183 }
184
185 #[inline(always)]
186 #[verifier::external_body]
187 pub fn put(&self, Tracked(perm): Tracked<&mut PointsTo<V>>, v: V)
188 requires
189 old(perm)@ === pcell_points![ self.id() => MemContents::Uninit ],
190 ensures
191 perm@ === pcell_points![ self.id() => MemContents::Init(v) ],
192 opens_invariants none
193 no_unwind
194 {
195 unsafe {
196 *(self.ucell.get()) = MaybeUninit::new(v);
197 }
198 }
199
200 #[inline(always)]
201 #[verifier::external_body]
202 pub fn take(&self, Tracked(perm): Tracked<&mut PointsTo<V>>) -> (v: V)
203 requires
204 self.id() === old(perm)@.pcell,
205 old(perm).is_init(),
206 ensures
207 perm.id() === old(perm)@.pcell,
208 perm.mem_contents() === MemContents::Uninit,
209 v === old(perm).value(),
210 opens_invariants none
211 no_unwind
212 {
213 unsafe {
214 let mut m = MaybeUninit::uninit();
215 mem::swap(&mut m, &mut *self.ucell.get());
216 m.assume_init()
217 }
218 }
219
220 #[inline(always)]
221 #[verifier::external_body]
222 pub fn replace(&self, Tracked(perm): Tracked<&mut PointsTo<V>>, in_v: V) -> (out_v: V)
223 requires
224 self.id() === old(perm)@.pcell,
225 old(perm).is_init(),
226 ensures
227 perm.id() === old(perm)@.pcell,
228 perm.mem_contents() === MemContents::Init(in_v),
229 out_v === old(perm).value(),
230 opens_invariants none
231 no_unwind
232 {
233 unsafe {
234 let mut m = MaybeUninit::new(in_v);
235 mem::swap(&mut m, &mut *self.ucell.get());
236 m.assume_init()
237 }
238 }
239
240 #[inline(always)]
244 #[verifier::external_body]
245 pub fn borrow<'a>(&'a self, Tracked(perm): Tracked<&'a PointsTo<V>>) -> (v: &'a V)
246 requires
247 self.id() === perm@.pcell,
248 perm.is_init(),
249 ensures
250 *v === perm.value(),
251 opens_invariants none
252 no_unwind
253 {
254 unsafe { (*self.ucell.get()).assume_init_ref() }
255 }
256
257 #[inline(always)]
260 pub fn into_inner(self, Tracked(perm): Tracked<PointsTo<V>>) -> (v: V)
261 requires
262 self.id() === perm@.pcell,
263 perm.is_init(),
264 ensures
265 v === perm.value(),
266 opens_invariants none
267 no_unwind
268 {
269 let tracked mut perm = perm;
270 self.take(Tracked(&mut perm))
271 }
272
273 #[doc(hidden)]
274 #[verifier::ignore_outside_new_mut_ref_experiment]
275 #[inline(always)]
276 #[verifier::external_body]
277 pub fn borrow_mut<'a>(&'a self, Tracked(perm): Tracked<&'a mut PointsTo<V>>) -> (v: &'a mut V)
278 requires
279 self.id() === perm@.pcell,
280 perm.is_init(),
281 ensures
282 *v === perm.value(),
283 fin(perm).id() == perm.id(),
284 fin(perm).is_init(),
285 fin(perm).value() === *fin(v),
286 opens_invariants none
287 no_unwind
288 {
289 unsafe { (*self.ucell.get()).assume_init_mut() }
290 }
291}
292
293impl<V: Copy> PCell<V> {
294 #[inline(always)]
295 #[verifier::external_body]
296 pub fn write(&self, Tracked(perm): Tracked<&mut PointsTo<V>>, in_v: V)
297 requires
298 self.id() === old(perm)@.pcell,
299 old(perm).is_init(),
300 ensures
301 perm.id() === old(perm)@.pcell,
302 perm.mem_contents() === MemContents::Init(in_v),
303 opens_invariants none
304 no_unwind
305 {
306 let _out = self.replace(Tracked(&mut *perm), in_v);
307 }
308}
309
310struct InvCellPred {}
311
312impl<T> InvariantPredicate<(Set<T>, PCell<T>), PointsTo<T>> for InvCellPred {
313 closed spec fn inv(k: (Set<T>, PCell<T>), perm: PointsTo<T>) -> bool {
314 let (possible_values, pcell) = k;
315 {
316 &&& perm.is_init()
317 &&& possible_values.contains(perm.value())
318 &&& pcell.id() === perm@.pcell
319 }
320 }
321}
322
323#[cfg_attr(not(verus_verify_core), deprecated = "use `vstd::cell::invcell::InvCell` instead")]
325#[verifier::reject_recursive_types(T)]
326pub struct InvCell<T> {
327 possible_values: Ghost<Set<T>>,
328 pcell: PCell<T>,
329 perm_inv: Tracked<LocalInvariant<(Set<T>, PCell<T>), PointsTo<T>, InvCellPred>>,
330}
331
332impl<T> InvCell<T> {
333 #[verifier::type_invariant]
334 closed spec fn wf(&self) -> bool {
335 &&& self.perm_inv@.constant() === (self.possible_values@, self.pcell)
336 }
337
338 pub closed spec fn inv(&self, val: T) -> bool {
339 &&& self.possible_values@.contains(val)
340 }
341
342 pub fn new(val: T, Ghost(f): Ghost<spec_fn(T) -> bool>) -> (cell: Self)
343 requires
344 f(val),
345 ensures
346 forall|v| f(v) <==> cell.inv(v),
347 {
348 let (pcell, Tracked(perm)) = PCell::new(val);
349 let ghost possible_values = Set::new(f);
350 let tracked perm_inv = LocalInvariant::new((possible_values, pcell), perm, 0);
351 InvCell { possible_values: Ghost(possible_values), pcell, perm_inv: Tracked(perm_inv) }
352 }
353}
354
355impl<T> InvCell<T> {
356 pub fn replace(&self, val: T) -> (old_val: T)
357 requires
358 self.inv(val),
359 ensures
360 self.inv(old_val),
361 {
362 proof {
363 use_type_invariant(self);
364 }
365 let r;
366 open_local_invariant!(self.perm_inv.borrow() => perm => {
367 r = self.pcell.replace(Tracked(&mut perm), val);
368 });
369 r
370 }
371}
372
373impl<T: Copy> InvCell<T> {
374 pub fn get(&self) -> (val: T)
375 ensures
376 self.inv(val),
377 {
378 proof {
379 use_type_invariant(self);
380 }
381 let r;
382 open_local_invariant!(self.perm_inv.borrow() => perm => {
383 r = *self.pcell.borrow(Tracked(&perm));
384 });
385 r
386 }
387}
388
389}