Skip to content

Commit d8659d9

Browse files
committed
resource: isolate GhostVar and GhostVarAuth
1 parent bca29c5 commit d8659d9

File tree

3 files changed

+125
-116
lines changed

3 files changed

+125
-116
lines changed

source/vstd/resource/frac.rs

Lines changed: 1 addition & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ impl<T> PCM for FractionalCarrier<T> {
103103
///
104104
/// let tracked mut a = FracGhost::<u32>::new(5);
105105
/// assert(a@ == 5);
106-
/// assert(a.frac() == 2);
106+
/// assert(a.frac() == 1real);
107107
/// let tracked mut b = a.split();
108108
/// assert(a.frac() == (0.5 as real));
109109
/// assert(b.frac() == (0.5 as real));
@@ -305,121 +305,6 @@ impl<T> FracGhost<T> {
305305
}
306306
}
307307

308-
/// See [`GhostVarAuth<T>`] for more information.
309-
pub struct GhostVar<T> {
310-
frac: FracGhost<T>,
311-
}
312-
313-
impl<T> GhostVar<T> {
314-
#[verifier::type_invariant]
315-
spec fn inv(self) -> bool {
316-
self.frac.frac() == 1 as real
317-
}
318-
319-
pub closed spec fn id(self) -> Loc {
320-
self.frac.id()
321-
}
322-
323-
pub closed spec fn view(self) -> T {
324-
self.frac.view()
325-
}
326-
}
327-
328-
/** `GhostVarAuth<T>` is one half of a pair of tokens—the other being [`GhostVar<T>`].
329-
These tokens each track a value, and they can only be allocated or updated together.
330-
Thus, the pair of tokens always agree on the value, but they can be owned separately.
331-
332-
One possible application is to have a library which
333-
keeps `GhostVarAuth<T>` and maintains an invariant relating the implementation's
334-
abstract state to the value of `GhostVarAuth<T>`. Both `GhostVarAuth<T>`
335-
and [`GhostVar<T>`] are needed together to update the value, but either one alone
336-
allows reasoning about the current state.
337-
338-
These tokens can be implemented using fractional permissions, e.g., [`FracGhost`].
339-
340-
### Example
341-
342-
```
343-
fn example() {
344-
let tracked (mut gauth, mut gvar) = GhostVarAuth::<u64>::new(1);
345-
assert(gauth@ == 1);
346-
assert(gvar@ == 1);
347-
proof {
348-
gauth.update(&mut gvar, 2);
349-
}
350-
assert(gauth@ == 2);
351-
assert(gvar@ == 2);
352-
}
353-
```
354-
*/
355-
356-
pub struct GhostVarAuth<T> {
357-
frac: FracGhost<T>,
358-
}
359-
360-
impl<T> GhostVarAuth<T> {
361-
#[verifier::type_invariant]
362-
spec fn inv(self) -> bool {
363-
self.frac.frac() == 1 as real
364-
}
365-
366-
pub closed spec fn id(self) -> Loc {
367-
self.frac.id()
368-
}
369-
370-
pub closed spec fn view(self) -> T {
371-
self.frac.view()
372-
}
373-
374-
/// Allocate a new pair of tokens, each initialized to the given value.
375-
pub proof fn new(v: T) -> (tracked result: (GhostVarAuth<T>, GhostVar<T>))
376-
ensures
377-
result.0.id() == result.1.id(),
378-
result.0@ == v,
379-
result.1@ == v,
380-
{
381-
let tracked mut f = FracGhost::<T>::new(v);
382-
let tracked v = GhostVar::<T> { frac: f.split() };
383-
let tracked a = GhostVarAuth::<T> { frac: f };
384-
(a, v)
385-
}
386-
387-
/// Ensure that both tokens agree on the value.
388-
pub proof fn agree(tracked &self, tracked v: &GhostVar<T>)
389-
requires
390-
self.id() == v.id(),
391-
ensures
392-
self@ == v@,
393-
{
394-
self.frac.agree(&v.frac)
395-
}
396-
397-
/// Update the value on each token.
398-
pub proof fn update(tracked &mut self, tracked v: &mut GhostVar<T>, new_val: T)
399-
requires
400-
old(self).id() == old(v).id(),
401-
ensures
402-
self.id() == old(self).id(),
403-
v.id() == old(v).id(),
404-
old(self)@ == old(v)@,
405-
self@ == new_val,
406-
v@ == new_val,
407-
{
408-
let tracked (mut ms, mut mv) = Self::new(new_val);
409-
tracked_swap(self, &mut ms);
410-
tracked_swap(v, &mut mv);
411-
use_type_invariant(&ms);
412-
use_type_invariant(&mv);
413-
let tracked mut msfrac = ms.frac;
414-
msfrac.combine(mv.frac);
415-
msfrac.update(new_val);
416-
let tracked mut nv = GhostVar::<T> { frac: msfrac.split() };
417-
let tracked mut ns = Self { frac: msfrac };
418-
tracked_swap(self, &mut ns);
419-
tracked_swap(v, &mut nv);
420-
}
421-
}
422-
423308
/////// Fractional tokens that allow borrowing of resources
424309
enum FractionalCarrierOpt<T> {
425310
Value { v: Option<T>, frac: real },

source/vstd/resource/ghost_var.rs

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
#[cfg(verus_keep_ghost)]
2+
use super::super::modes::tracked_swap;
3+
use super::super::prelude::*;
4+
use super::Loc;
5+
use super::frac::FracGhost;
6+
7+
verus! {
8+
9+
/// See [`GhostVarAuth<T>`] for more information.
10+
pub struct GhostVar<T> {
11+
frac: FracGhost<T>,
12+
}
13+
14+
impl<T> GhostVar<T> {
15+
#[verifier::type_invariant]
16+
spec fn inv(self) -> bool {
17+
self.frac.frac() == (1 as real) / (2 as real)
18+
}
19+
20+
pub closed spec fn id(self) -> Loc {
21+
self.frac.id()
22+
}
23+
24+
pub closed spec fn view(self) -> T {
25+
self.frac.view()
26+
}
27+
}
28+
29+
/// `GhostVarAuth<T>` is one half of a pair of tokens—the other being [`GhostVar<T>`].
30+
/// These tokens each track a value, and they can only be allocated or updated together.
31+
/// Thus, the pair of tokens always agree on the value, but they can be owned separately.
32+
///
33+
/// One possible application is to have a library which
34+
/// keeps `GhostVarAuth<T>` and maintains an invariant relating the implementation's
35+
/// abstract state to the value of `GhostVarAuth<T>`. Both `GhostVarAuth<T>`
36+
/// and [`GhostVar<T>`] are needed together to update the value, but either one alone
37+
/// allows reasoning about the current state.
38+
///
39+
/// These tokens can be implemented using fractional permissions, e.g., [`FracGhost`].
40+
///
41+
/// ### Example
42+
///
43+
/// ```
44+
/// fn example() {
45+
/// let tracked (mut gauth, mut gvar) = GhostVarAuth::<u64>::new(1);
46+
/// assert(gauth@ == 1);
47+
/// assert(gvar@ == 1);
48+
/// proof {
49+
/// gauth.update(&mut gvar, 2);
50+
/// }
51+
/// assert(gauth@ == 2);
52+
/// assert(gvar@ == 2);
53+
/// }
54+
/// ```
55+
pub struct GhostVarAuth<T> {
56+
frac: FracGhost<T>,
57+
}
58+
59+
impl<T> GhostVarAuth<T> {
60+
#[verifier::type_invariant]
61+
spec fn inv(self) -> bool {
62+
self.frac.frac() == (1 as real) / (2 as real)
63+
}
64+
65+
pub closed spec fn id(self) -> Loc {
66+
self.frac.id()
67+
}
68+
69+
pub closed spec fn view(self) -> T {
70+
self.frac.view()
71+
}
72+
73+
/// Allocate a new pair of tokens, each initialized to the given value.
74+
pub proof fn new(v: T) -> (tracked result: (GhostVarAuth<T>, GhostVar<T>))
75+
ensures
76+
result.0.id() == result.1.id(),
77+
result.0@ == v,
78+
result.1@ == v,
79+
{
80+
let tracked mut f = FracGhost::<T>::new(v);
81+
let tracked v = GhostVar::<T> { frac: f.split() };
82+
let tracked a = GhostVarAuth::<T> { frac: f };
83+
(a, v)
84+
}
85+
86+
/// Ensure that both tokens agree on the value.
87+
pub proof fn agree(tracked &self, tracked v: &GhostVar<T>)
88+
requires
89+
self.id() == v.id(),
90+
ensures
91+
self@ == v@,
92+
{
93+
self.frac.agree(&v.frac)
94+
}
95+
96+
/// Update the value on each token.
97+
pub proof fn update(tracked &mut self, tracked v: &mut GhostVar<T>, new_val: T)
98+
requires
99+
old(self).id() == old(v).id(),
100+
ensures
101+
self.id() == old(self).id(),
102+
v.id() == old(v).id(),
103+
old(self)@ == old(v)@,
104+
self@ == new_val,
105+
v@ == new_val,
106+
{
107+
let tracked (mut ms, mut mv) = Self::new(new_val);
108+
tracked_swap(self, &mut ms);
109+
tracked_swap(v, &mut mv);
110+
use_type_invariant(&ms);
111+
use_type_invariant(&mv);
112+
let tracked mut msfrac = ms.frac;
113+
msfrac.combine(mv.frac);
114+
msfrac.update(new_val);
115+
let tracked mut nv = GhostVar::<T> { frac: msfrac.split() };
116+
let tracked mut ns = Self { frac: msfrac };
117+
tracked_swap(self, &mut ns);
118+
tracked_swap(v, &mut nv);
119+
}
120+
}
121+
122+
} // verus!

source/vstd/resource/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ pub mod algebra;
55
pub mod auth;
66
pub mod exclusive;
77
pub mod frac;
8+
pub mod frac_opt;
9+
pub mod ghost_var;
810
mod lib;
911
pub mod map;
1012
pub mod option;

0 commit comments

Comments
 (0)