vstd_extra/resource/storage_protocol/
excl.rs1use vstd::modes::tracked_swap;
3use vstd::prelude::*;
4use vstd::resource::Loc;
5use vstd::resource::exclusive::ExclusiveRA;
6use vstd::resource::storage_protocol::*;
7
8verus! {
9
10pub ghost enum ExclusiveSP<A> {
11 Unit,
12 Exclusive(Option<A>),
14 Invalid,
16}
17
18impl<A> Protocol<(), A> for ExclusiveSP<A> {
19 open spec fn op(self, other: Self) -> Self {
20 match (self, other) {
21 (ExclusiveSP::Unit, x) => x,
22 (x, ExclusiveSP::Unit) => x,
23 _ => ExclusiveSP::Invalid,
24 }
25 }
26
27 open spec fn rel(self, s: Map<(), A>) -> bool {
28 match self {
29 ExclusiveSP::Unit => s.is_empty(),
30 ExclusiveSP::Exclusive(None) => s.is_empty(),
31 ExclusiveSP::Exclusive(Some(x)) => s =~= map![() => x],
32 ExclusiveSP::Invalid => false,
33 }
34 }
35
36 open spec fn unit() -> Self {
37 ExclusiveSP::Unit
38 }
39
40 proof fn commutative(a: Self, b: Self) {
41 }
42
43 proof fn associative(a: Self, b: Self, c: Self) {
44 }
45
46 proof fn op_unit(a: Self) {
47 }
48}
49
50impl<A> ExclusiveSP<A> {
51 pub open spec fn value(self) -> A {
52 match self {
53 ExclusiveSP::Exclusive(Some(x)) => x,
54 _ => arbitrary(),
55 }
56 }
57
58 pub proof fn lemma_deposits(self, value: A)
59 requires
60 self is Exclusive,
61 self->Exclusive_0 is None,
62 ensures
63 deposits(self, map![() => value], ExclusiveSP::Exclusive(Some(value))),
64 {
65 let m = map![() => value];
66 assert forall|q: Self, s: Map<(), A>|
67 #![auto]
68 Self::rel(Self::op(self, q), s) implies exists|s1: Map<(), A>|
69 #![auto]
70 Self::rel(Self::op(ExclusiveSP::Exclusive(Some(value)), q), s1) && s.dom().disjoint(
71 m.dom(),
72 ) && s.union_prefer_right(m) == s1 by {
73 assert(s == Map::<(), A>::empty());
74 assert(Self::rel(Self::op(ExclusiveSP::Exclusive(Some(value)), q), m));
75 assert(s.dom().disjoint(m.dom()));
76 assert(s.union_prefer_right(m) == m);
77 }
78 }
79}
80
81pub tracked struct Exclusive<T> {
85 tracked r: StorageResource<(), T, ExclusiveSP<T>>,
86}
87
88impl<T> Exclusive<T> {
89 pub closed spec fn id(self) -> Loc {
91 self.r.loc()
92 }
93
94 pub closed spec fn protocol_monoid(self) -> ExclusiveSP<T> {
96 self.r.value()
97 }
98
99 pub open spec fn resource(self) -> T {
101 self.protocol_monoid().value()
102 }
103
104 pub open spec fn wf(self) -> bool {
106 self.protocol_monoid() is Exclusive
107 }
108
109 pub open spec fn has_resource(self) -> bool {
111 self.protocol_monoid()->Exclusive_0 is Some
112 }
113
114 pub open spec fn has_no_resource(self) -> bool {
116 self.protocol_monoid()->Exclusive_0 is None
117 }
118
119 #[verifier::type_invariant]
120 closed spec fn type_inv(self) -> bool {
121 self.wf()
122 }
123
124 closed spec fn type_inv_inner(r: ExclusiveSP<T>) -> bool {
125 r is Exclusive
126 }
127
128 pub proof fn validate_with_other(tracked &mut self, tracked other: &Self)
130 ensures
131 *old(self) == *final(self),
132 final(self).wf(),
133 final(self).id() != other.id(),
134 {
135 use_type_invariant(&*self);
136 use_type_invariant(other);
137 if self.id() == other.id() {
138 self.r.validate_with_shared(&other.r);
139 }
140 }
141
142 pub proof fn tracked_borrow(tracked &self) -> (tracked res: &T)
144 requires
145 self.has_resource(),
146 ensures
147 *res == self.resource(),
148 {
149 use_type_invariant(&*self);
150 StorageResource::guard(&self.r, map![() => self.resource()]).tracked_borrow(())
151 }
152
153 pub proof fn take_resource(tracked &mut self) -> (tracked res: T)
155 requires
156 old(self).has_resource(),
157 ensures
158 final(self).has_no_resource(),
159 res == old(self).resource(),
160 final(self).wf(),
161 {
162 use_type_invariant(&*self);
163 Self::take_resource_helper(&mut self.r)
164 }
165
166 proof fn take_resource_helper(
167 tracked r: &mut StorageResource<(), T, ExclusiveSP<T>>,
168 ) -> (tracked res: T)
169 requires
170 Self::type_inv_inner(old(r).value()),
171 old(r).value()->Exclusive_0 is Some,
172 ensures
173 Self::type_inv_inner(final(r).value()),
174 final(r).value()->Exclusive_0 is None,
175 final(r).loc() == old(r).loc(),
176 res == old(r).value()->Exclusive_0->0,
177 {
178 let tracked mut tmp = StorageResource::<(), T, ExclusiveSP<T>>::alloc(
179 ExclusiveSP::Unit,
180 Map::tracked_empty(),
181 );
182 tracked_swap(r, &mut tmp);
183 let tracked (mut r1, mut r2) = tmp.withdraw(
184 ExclusiveSP::Exclusive(None),
185 map![()=> tmp.value().value()],
186 );
187 tracked_swap(r, &mut r1);
188 r2.tracked_remove(())
189 }
190
191 pub proof fn put_resource(tracked &mut self, tracked value: T)
193 requires
194 old(self).has_no_resource(),
195 ensures
196 final(self).has_resource(),
197 final(self).resource() == value,
198 final(self).wf(),
199 {
200 use_type_invariant(&*self);
201 Self::put_resource_helper(&mut self.r, value)
202 }
203
204 proof fn put_resource_helper(
205 tracked r: &mut StorageResource<(), T, ExclusiveSP<T>>,
206 tracked value: T,
207 )
208 requires
209 Self::type_inv_inner(old(r).value()),
210 old(r).value()->Exclusive_0 is None,
211 ensures
212 Self::type_inv_inner(final(r).value()),
213 final(r).value()->Exclusive_0 is Some,
214 final(r).loc() == old(r).loc(),
215 final(r).value()->Exclusive_0->0 == value,
216 {
217 let ghost g = value;
218 let tracked mut tmp = StorageResource::<(), T, ExclusiveSP<T>>::alloc(
219 ExclusiveSP::Unit,
220 Map::tracked_empty(),
221 );
222 tracked_swap(r, &mut tmp);
223 let tracked mut m = Map::tracked_empty();
224 m.tracked_insert((), value);
225 tmp.value().lemma_deposits(g);
226 let tracked mut r1 = tmp.deposit(m, ExclusiveSP::Exclusive(Some(g)));
227 tracked_swap(r, &mut r1);
228 }
229
230 pub proof fn update(tracked &mut self, tracked value: T) -> (tracked res: Option<T>)
232 ensures
233 final(self).has_resource(),
234 final(self).resource() == value,
235 res == if old(self).has_resource() {
236 Some(old(self).resource())
237 } else {
238 None
239 },
240 final(self).wf(),
241 {
242 use_type_invariant(&*self);
243 let tracked mut res = None;
244 if self.has_resource() {
245 res = Some(self.take_resource());
246 }
247 self.put_resource(value);
248 res
249 }
250}
251
252}