1use alloc::{
3 alloc::Allocator,
4 collections::{BTreeMap, btree_map::CursorMut},
5};
6use core::{borrow::Borrow, cmp::Ordering, ops::Bound};
7use vstd::{
8 assert_maps_equal,
9 laws_cmp::obeys_cmp,
10 prelude::*,
11 std_specs::{
12 btree::{
13 borrowed_key_removed, contains_borrowed_key, increasing_seq, maps_borrowed_key_to_value,
14 },
15 cmp::OrdSpec,
16 },
17};
18
19verus! {
20
21#[verifier::external_type_specification]
23#[verifier::external_body]
24#[verifier::reject_recursive_types(K)]
25#[verifier::reject_recursive_types(V)]
26#[verifier::reject_recursive_types(A)]
27pub struct ExCursorMut<'a, K: 'a, V: 'a, A>(CursorMut<'a, K, V, A>);
28
29pub ghost struct CursorMutModel<Key, Value> {
34 pub keys: Seq<Key>,
36 pub position: int,
38 pub map: Map<Key, Value>,
40}
41
42impl<Key, Value> CursorMutModel<Key, Value> {
43 pub open spec fn wf(self) -> bool {
45 &&& 0 <= self.position <= self.keys.len()
46 &&& self.keys.no_duplicates()
47 &&& self.keys.to_set() == self.map.dom()
48 &&& increasing_seq(self.keys)
49 }
50}
51
52pub trait CursorMutAdditionalSpecFns<Key, Value>: Sized {
54 spec fn view(&self) -> CursorMutModel<Key, Value>;
55
56 #[verifier::prophetic]
58 spec fn final_map(self) -> Map<Key, Value>;
59}
60
61impl<'a, Key, Value, A> CursorMutAdditionalSpecFns<Key, Value> for CursorMut<'a, Key, Value, A> {
62 uninterp spec fn view(&self) -> CursorMutModel<Key, Value>;
63
64 #[verifier::prophetic]
65 uninterp spec fn final_map(self) -> Map<Key, Value>;
66}
67
68pub uninterp spec fn borrowed_key_ordering_matches<Key: Borrow<Q> + Ord, Q: Ord + ?Sized>() -> bool;
73
74pub uninterp spec fn borrowed_key_cmp<Key, Q: ?Sized>(stored_key: Key, key: &Q) -> Ordering;
76
77pub broadcast axiom fn axiom_deref_key_ordering_matches<Key: Ord>()
79 ensures
80 #[trigger] borrowed_key_ordering_matches::<Key, Key>(),
81;
82
83pub broadcast axiom fn axiom_deref_key_cmp<Key: Ord>(stored_key: Key, key: &Key)
85 ensures
86 #[trigger] borrowed_key_cmp::<Key, Key>(stored_key, key) == stored_key.cmp_spec(key),
87;
88
89pub open spec fn before_lower_bound<Key, Q: ?Sized>(key: Key, bound: Bound<&Q>) -> bool {
91 match bound {
92 Bound::Included(bound_key) => borrowed_key_cmp(key, bound_key) is Less,
93 Bound::Excluded(bound_key) => !(borrowed_key_cmp(key, bound_key) is Greater),
94 Bound::Unbounded => false,
95 }
96}
97
98pub open spec fn before_upper_bound<Key, Q: ?Sized>(key: Key, bound: Bound<&Q>) -> bool {
100 match bound {
101 Bound::Included(bound_key) => !(borrowed_key_cmp(key, bound_key) is Greater),
102 Bound::Excluded(bound_key) => borrowed_key_cmp(key, bound_key) is Less,
103 Bound::Unbounded => true,
104 }
105}
106
107pub open spec fn positioned_at_lower_bound<Key, Value, Q: ?Sized>(
109 model: CursorMutModel<Key, Value>,
110 bound: Bound<&Q>,
111) -> bool {
112 &&& forall|i: int|
113 #![trigger before_lower_bound(model.keys[i], bound)]
114 0 <= i < model.position ==> before_lower_bound(model.keys[i], bound)
115 &&& forall|i: int|
116 #![trigger before_lower_bound(model.keys[i], bound)]
117 model.position <= i < model.keys.len() ==> !before_lower_bound(model.keys[i], bound)
118}
119
120pub open spec fn positioned_at_upper_bound<Key, Value, Q: ?Sized>(
122 model: CursorMutModel<Key, Value>,
123 bound: Bound<&Q>,
124) -> bool {
125 &&& forall|i: int|
126 #![trigger before_upper_bound(model.keys[i], bound)]
127 0 <= i < model.position ==> before_upper_bound(model.keys[i], bound)
128 &&& forall|i: int|
129 #![trigger before_upper_bound(model.keys[i], bound)]
130 model.position <= i < model.keys.len() ==> !before_upper_bound(model.keys[i], bound)
131}
132
133pub broadcast axiom fn axiom_has_resolved_cursor<Key, Value, A>(cursor: CursorMut<Key, Value, A>)
135 ensures
136 #[trigger] has_resolved(cursor) ==> cursor.final_map() == cursor@.map,
137;
138
139pub open spec fn borrowed_key_mutated<Key, Value, Q: ?Sized>(
141 old_map: Map<Key, Value>,
142 new_map: Map<Key, Value>,
143 key: &Q,
144 old_value: Value,
145 new_value: Value,
146) -> bool {
147 &&& maps_borrowed_key_to_value(old_map, key, old_value)
148 &&& maps_borrowed_key_to_value(new_map, key, new_value)
149 &&& exists|remainder: Map<Key, Value>|
150 {
151 &&& borrowed_key_removed(old_map, remainder, key)
152 &&& borrowed_key_removed(new_map, remainder, key)
153 }
154}
155
156pub broadcast proof fn lemma_borrowed_key_mutated_deref<Key, Value>(
158 old_map: Map<Key, Value>,
159 new_map: Map<Key, Value>,
160 key: &Key,
161 old_value: Value,
162 new_value: Value,
163)
164 ensures
165 #[trigger] borrowed_key_mutated(old_map, new_map, key, old_value, new_value) <==> {
166 &&& old_map.contains_key(*key)
167 &&& old_map[*key] == old_value
168 &&& new_map == old_map.insert(*key, new_value)
169 },
170{
171 broadcast use vstd::std_specs::btree::group_btree_axioms;
172
173 if borrowed_key_mutated(old_map, new_map, key, old_value, new_value) {
174 let remainder = choose|remainder: Map<Key, Value>|
175 {
176 &&& borrowed_key_removed(old_map, remainder, key)
177 &&& borrowed_key_removed(new_map, remainder, key)
178 };
179 assert(remainder == new_map.remove(*key));
180 assert_maps_equal!(new_map, old_map.insert(*key, new_value), candidate => {
181 if candidate != *key {
182 assert(old_map.remove(*key)[candidate] == old_map[candidate]);
183 }
184 });
185 } else if old_map.contains_key(*key) && old_map[*key] == old_value && new_map == old_map.insert(
186 *key,
187 new_value,
188 ) {
189 let remainder = old_map.remove(*key);
190 assert_maps_equal!(new_map.remove(*key), remainder, candidate => {});
191 assert(borrowed_key_removed(new_map, remainder, key));
192 }
193}
194
195pub broadcast group group_btree_extra_axioms {
197 axiom_deref_key_ordering_matches,
198 axiom_deref_key_cmp,
199 axiom_has_resolved_cursor,
200 lemma_borrowed_key_mutated_deref,
201}
202
203pub assume_specification<
205 'a,
206 Key: Borrow<Q> + Ord,
207 Value,
208 A: Allocator + Clone,
209 Q: Ord + ?Sized,
210>[ BTreeMap::<Key, Value, A>::get_mut::<Q> ](
211 map: &'a mut BTreeMap<Key, Value, A>,
212 key: &Q,
213) -> (result: Option<&'a mut Value>)
214 requires
215 borrowed_key_ordering_matches::<Key, Q>(),
216 ensures
217 obeys_cmp::<Key>() ==> match result {
218 Some(value) => borrowed_key_mutated(old(map)@, final(map)@, key, *value, *final(value)),
219 None => !contains_borrowed_key(old(map)@, key) && final(map)@ == old(map)@,
220 },
221;
222
223pub assume_specification<
225 'a,
226 Key: Borrow<Q> + Ord,
227 Value,
228 A: Allocator + Clone,
229 Q: Ord + ?Sized,
230>[ BTreeMap::<Key, Value, A>::lower_bound_mut::<Q> ](
231 map: &'a mut BTreeMap<Key, Value, A>,
232 bound: Bound<&Q>,
233) -> (cursor: CursorMut<'a, Key, Value, A>)
234 requires
235 borrowed_key_ordering_matches::<Key, Q>(),
236 ensures
237 obeys_cmp::<Key>() ==> {
238 &&& cursor@.wf()
239 &&& cursor@.map == old(map)@
240 &&& final(map)@ == cursor.final_map()
241 &&& positioned_at_lower_bound(cursor@, bound)
242 },
243;
244
245pub assume_specification<
247 'a,
248 Key: Borrow<Q> + Ord,
249 Value,
250 A: Allocator + Clone,
251 Q: Ord + ?Sized,
252>[ BTreeMap::<Key, Value, A>::upper_bound_mut::<Q> ](
253 map: &'a mut BTreeMap<Key, Value, A>,
254 bound: Bound<&Q>,
255) -> (cursor: CursorMut<'a, Key, Value, A>)
256 requires
257 borrowed_key_ordering_matches::<Key, Q>(),
258 ensures
259 obeys_cmp::<Key>() ==> {
260 &&& cursor@.wf()
261 &&& cursor@.map == old(map)@
262 &&& final(map)@ == cursor.final_map()
263 &&& positioned_at_upper_bound(cursor@, bound)
264 },
265;
266
267pub assume_specification<'a, 'b, Key, Value, A>[ CursorMut::<'a, Key, Value, A>::peek_prev ](
269 cursor: &'b mut CursorMut<'a, Key, Value, A>,
270) -> (result: Option<(&'b Key, &'b mut Value)>)
271 requires
272 old(cursor)@.wf(),
273 ensures
274 final(cursor).final_map() == old(cursor).final_map(),
275 final(cursor)@.wf(),
276 match result {
277 Some((key, value)) => {
278 let old_model = old(cursor)@;
279 let new_model = final(cursor)@;
280 &&& old_model.position > 0
281 &&& *key == old_model.keys[old_model.position - 1]
282 &&& *value == old_model.map[*key]
283 &&& new_model.keys == old_model.keys
284 &&& new_model.position == old_model.position
285 &&& new_model.map == old_model.map.insert(*key, *final(value))
286 },
287 None => {
288 &&& old(cursor)@.position == 0
289 &&& final(cursor)@ == old(cursor)@
290 },
291 },
292;
293
294pub assume_specification<'a, 'b, Key, Value, A>[ CursorMut::<'a, Key, Value, A>::peek_next ](
296 cursor: &'b mut CursorMut<'a, Key, Value, A>,
297) -> (result: Option<(&'b Key, &'b mut Value)>)
298 requires
299 old(cursor)@.wf(),
300 ensures
301 final(cursor).final_map() == old(cursor).final_map(),
302 final(cursor)@.wf(),
303 match result {
304 Some((key, value)) => {
305 let old_model = old(cursor)@;
306 let new_model = final(cursor)@;
307 &&& old_model.position < old_model.keys.len()
308 &&& *key == old_model.keys[old_model.position]
309 &&& *value == old_model.map[*key]
310 &&& new_model.keys == old_model.keys
311 &&& new_model.position == old_model.position
312 &&& new_model.map == old_model.map.insert(*key, *final(value))
313 },
314 None => {
315 &&& old(cursor)@.position == old(cursor)@.keys.len()
316 &&& final(cursor)@ == old(cursor)@
317 },
318 },
319;
320
321}