Skip to main content

vstd/std_specs/
vec.rs

1use super::super::prelude::*;
2use super::iter::{FromIteratorSpecImpl, IteratorSpec};
3use verus_builtin::*;
4
5use super::super::slice::SliceIndexSpec;
6use super::core::IndexSpec;
7use alloc::collections::TryReserveError;
8use alloc::vec::{IntoIter, Vec};
9use core::alloc::Allocator;
10use core::clone::Clone;
11use core::marker::PhantomData;
12use core::ops::Index;
13use core::option::Option;
14use core::option::Option::None;
15use core::slice::SliceIndex;
16
17use verus as verus_skip_verusfmt;
18verus_skip_verusfmt! {
19
20#[verifier::external_type_specification]
21#[verifier::external_body]
22#[verifier::accept_recursive_types(T)]
23#[verifier::reject_recursive_types(A)]
24pub struct ExVec<T, A: Allocator>(Vec<T, A>);
25
26pub trait VecAdditionalSpecFns<T>: View<V = Seq<T>> {
27    spec fn spec_index(&self, i: int) -> T
28        recommends
29            0 <= i < self.view().len(),
30    ;
31}
32
33impl<T, A: Allocator> VecAdditionalSpecFns<T> for Vec<T, A> {
34    #[verifier::inline]
35    open spec fn spec_index(&self, i: int) -> T {
36        self.view().index(i)
37    }
38}
39
40#[verifier::external_type_specification]
41#[verifier::external_body]
42pub struct ExTryReserveError(alloc::collections::TryReserveError);
43
44// We still have a special case for Vec::index on usize.
45// The general Vec::index case now goes through the Index trait,
46// but this special case is still here because it's more direct and efficient in its SMT encoding,
47// and Vec::index on usize is very common.
48//
49// So this is a bit of a hack, but we just manually redirect
50// `vec[i]` to this function here from rust_to_vir_expr.
51#[verifier::external_body]
52#[cfg_attr(verus_keep_ghost, rustc_diagnostic_item = "verus::vstd::std_specs::vec::vec_index")]
53pub fn vec_index<T, A: Allocator>(vec: &Vec<T, A>, i: usize) -> (element: &T)
54    requires
55        i < vec.view().len(),
56    ensures
57        *element == vec.view().index(i as int),
58    no_unwind
59{
60    &vec[i]
61}
62
63/// This is a specification for the indexing operator `vec[i]` when it expands to the `IndexMut` trait
64#[doc(hidden)]
65#[verifier::external_body]
66#[cfg_attr(verus_keep_ghost, rustc_diagnostic_item = "verus::vstd::std_specs::vec::vec_index_mut")]
67pub fn vec_index_mut<T, A: Allocator>(vec: &mut Vec<T, A>, i: usize) -> (element: &mut T)
68    requires
69        i < vec.view().len(),
70    ensures
71        *element == old(vec)@.index(i as int),
72        final(vec)@ == old(vec)@.update(i as int, *final(element)),
73
74        *final(element) == final(vec).view().index(i as int),
75    no_unwind
76{
77    &mut vec[i]
78}
79
80////// Len (with autospec)
81pub uninterp spec fn spec_vec_len<T, A: Allocator>(v: &Vec<T, A>) -> usize;
82
83// This axiom is slightly better than defining spec_vec_len to just be `v@.len() as usize`
84// (the axiom also shows that v@.len() is in-bounds for usize)
85pub broadcast proof fn axiom_spec_len<T, A: Allocator>(v: &Vec<T, A>)
86    ensures
87        #[trigger] spec_vec_len(v) == v@.len(),
88{
89    admit();
90}
91
92#[verifier::when_used_as_spec(spec_vec_len)]
93pub assume_specification<T, A: Allocator>[ Vec::<T, A>::len ](vec: &Vec<T, A>) -> (len: usize)
94    ensures
95        len == spec_vec_len(vec),
96    no_unwind
97;
98
99////// Other functions
100pub assume_specification<T>[ Vec::<T>::new ]() -> (v: Vec<T>)
101    ensures
102        v@ == Seq::<T>::empty(),
103;
104
105pub assume_specification<T>[ <Vec<T> as core::default::Default>::default ]() -> (v: Vec<T>)
106    ensures
107        v@ == Seq::<T>::empty(),
108;
109
110pub assume_specification<T, A: Allocator>[ Vec::<T, A>::new_in ](alloc: A) -> (v: Vec<T, A>)
111    ensures
112        v@ == Seq::<T>::empty(),
113;
114
115pub assume_specification<T>[ Vec::<T>::with_capacity ](capacity: usize) -> (v: Vec<T>)
116    ensures
117        v@ == Seq::<T>::empty(),
118;
119
120pub assume_specification<T, A: Allocator>[ Vec::<T, A>::with_capacity_in ](capacity: usize, alloc: A) -> (v: Vec<T, A>)
121    ensures
122        v@ == Seq::<T>::empty(),
123;
124
125pub assume_specification<T, A: Allocator>[ Vec::<T, A>::reserve ](
126    vec: &mut Vec<T, A>,
127    additional: usize,
128)
129    ensures
130        final(vec)@ == old(vec)@,
131;
132
133pub assume_specification<T, A: Allocator>[ Vec::<T, A>::try_reserve ](
134    vec: &mut Vec<T, A>,
135    additional: usize,
136) -> (result: Result<(), TryReserveError>)
137    ensures
138        final(vec)@ == old(vec)@,
139;
140
141pub assume_specification<T, A: Allocator>[ Vec::<T, A>::try_reserve_exact ](
142    vec: &mut Vec<T, A>,
143    additional: usize,
144) -> (result: Result<(), TryReserveError>)
145    ensures
146        final(vec)@ == old(vec)@,
147;
148
149pub assume_specification<T, A: Allocator>[ Vec::<T, A>::push ](vec: &mut Vec<T, A>, value: T)
150    ensures
151        final(vec)@ == old(vec)@.push(value),
152;
153
154pub assume_specification<T, A: Allocator>[ Vec::<T, A>::pop ](vec: &mut Vec<T, A>) -> (value:
155    Option<T>)
156    ensures
157        old(vec)@.len() > 0 ==> value == Some(old(vec)@[old(vec)@.len() - 1])
158            && final(vec)@ == old(vec)@[..old(vec)@.len() - 1],
159        old(vec)@.len() == 0 ==> value == None::<T> && final(vec)@ == old(vec)@,
160;
161
162pub assume_specification<T, A: Allocator>[ Vec::<T, A>::append ](
163    vec: &mut Vec<T, A>,
164    other: &mut Vec<T, A>,
165)
166    ensures
167        final(vec)@ == old(vec)@ + old(other)@,
168        final(other)@ == Seq::<T>::empty(),
169;
170
171pub assume_specification<T: core::clone::Clone, A: Allocator>[ Vec::<T, A>::extend_from_slice ](
172    vec: &mut Vec<T, A>,
173    other: &[T],
174)
175    ensures
176        final(vec)@.len() == old(vec)@.len() + other@.len(),
177        forall|i: int|
178            #![trigger final(vec)@[i]]
179            0 <= i < final(vec)@.len() ==> if i < old(vec)@.len() {
180                final(vec)@[i] == old(vec)@[i]
181            } else {
182                cloned::<T>(other@[i - old(vec)@.len()], final(vec)@[i])
183            },
184;
185
186impl<T: Sized, I: SliceIndex<[T]>, A: Allocator> super::core::IndexSpecImpl<I> for Vec<T, A> {
187    open spec fn index_req(&self, index: &I) -> bool {
188        forall|s: &[T]| #[trigger] s@ == self@ ==> index.in_bounds(s)
189    }
190}
191
192pub assume_specification<T, I: SliceIndex<[T]>, A: Allocator>[Vec::<T, A>::index](
193    vec: &Vec<T, A>,
194    i: I,
195) -> (r: &<Vec<T, A> as Index<I>>::Output)
196    ensures
197        exists|s: &[T]| #[trigger] s@ == vec@ && call_ensures(<I as SliceIndex<[T]>>::index, (i, s), r),
198;
199
200pub assume_specification<T, A: Allocator>[ Vec::<T, A>::swap_remove ](
201    vec: &mut Vec<T, A>,
202    i: usize,
203) -> (element: T)
204    requires
205        i < old(vec).len(),
206    ensures
207        element == old(vec)[i as int],
208        final(vec)@ == old(vec)@.update(i as int, old(vec)@.last()).drop_last(),
209;
210
211pub assume_specification<T, A: Allocator>[ Vec::<T, A>::insert ](
212    vec: &mut Vec<T, A>,
213    i: usize,
214    element: T,
215)
216    requires
217        i <= old(vec).len(),
218    ensures
219        final(vec)@ == old(vec)@.insert(i as int, element),
220;
221
222pub assume_specification<T, A: Allocator> [ <Vec<T, A>>::is_empty ](
223    v: &Vec<T, A>,
224) -> (res: bool)
225    ensures res <==> v@.len() == 0,
226    opens_invariants none
227    no_unwind
228;
229
230pub assume_specification<T, A: Allocator>[ Vec::<T, A>::remove ](
231    vec: &mut Vec<T, A>,
232    i: usize,
233) -> (element: T)
234    requires
235        i < old(vec).len(),
236    ensures
237        element == old(vec)[i as int],
238        final(vec)@ == old(vec)@.remove(i as int),
239;
240
241pub assume_specification<T, A: Allocator>[ Vec::<T, A>::clear ](vec: &mut Vec<T, A>)
242    ensures
243        final(vec).view() == Seq::<T>::empty(),
244;
245
246pub assume_specification<T, A: Allocator>[ Vec::<T, A>::as_slice ](vec: &Vec<T, A>) -> (slice: &[T])
247    ensures
248        slice@ == vec@,
249    opens_invariants none
250    no_unwind
251;
252
253pub assume_specification<T, A: Allocator>[ <Vec<T, A> as core::convert::AsRef<[T]>>::as_ref ](
254    vec: &Vec<T, A>,
255) -> (slice: &[T])
256    ensures
257        slice@ == vec@,
258    opens_invariants none
259    no_unwind
260;
261
262#[doc(hidden)]
263pub assume_specification<T, A: Allocator>[ Vec::<T, A>::as_mut_slice ](vec: &mut Vec<T, A>) -> (slice: &mut [T])
264    ensures
265        slice@ == old(vec)@,
266        final(slice)@ == final(vec)@,
267    opens_invariants none
268    no_unwind
269;
270
271pub assume_specification<T, A: Allocator>[ <Vec<T, A> as core::ops::Deref>::deref ](
272    vec: &Vec<T, A>,
273) -> (slice: &[T])
274    ensures
275        slice@ == vec@,
276;
277
278pub assume_specification<T, A: Allocator>[ <Vec<T, A> as core::ops::DerefMut>::deref_mut ](
279    vec: &mut Vec<T, A>,
280) -> (slice: &mut [T])
281    ensures
282        slice@ == old(vec)@,
283        final(slice)@ == final(vec)@,
284;
285
286pub assume_specification<T, A: Allocator + core::clone::Clone>[ Vec::<T, A>::split_off ](
287    vec: &mut Vec<T, A>,
288    at: usize,
289) -> (return_value: Vec<T, A>)
290    requires
291        at <= old(vec)@.len(),
292    ensures
293        final(vec)@ == old(vec)@[..at],
294        return_value@ == old(vec)@[at..],
295;
296
297pub open spec fn vec_clone_trigger<T, A: Allocator>(v1: Vec<T, A>, v2: Vec<T, A>) -> bool {
298    true
299}
300
301pub assume_specification<T: Clone, A: Allocator + Clone>[ <Vec<T, A> as Clone>::clone ](
302    vec: &Vec<T, A>,
303) -> (res: Vec<T, A>)
304    ensures
305        res.len() == vec.len(),
306        forall|i| #![all_triggers] 0 <= i < vec.len() ==> cloned::<T>(vec[i], res[i]),
307        vec_clone_trigger(*vec, res),
308        vec@ =~= res@ ==> vec@ == res@,
309;
310
311pub broadcast proof fn vec_clone_deep_view_proof<T: DeepView, A: Allocator>(
312    v1: Vec<T, A>,
313    v2: Vec<T, A>,
314)
315    requires
316        #[trigger] vec_clone_trigger(v1, v2),
317        v1.deep_view() =~= v2.deep_view(),
318    ensures
319        v1.deep_view() == v2.deep_view(),
320{
321}
322
323pub assume_specification<T, A: Allocator>[ Vec::<T, A>::truncate ](vec: &mut Vec<T, A>, len: usize)
324    ensures
325        len <= old(vec).len() ==> final(vec)@ == old(vec)@[..len],
326        len > old(vec).len() ==> final(vec)@ == old(vec)@,
327;
328
329pub assume_specification<T: Clone, A: Allocator>[ Vec::<T, A>::resize ](
330    vec: &mut Vec<T, A>,
331    len: usize,
332    value: T,
333)
334    ensures
335        len <= old(vec).len() ==> final(vec)@ == old(vec)@[..len],
336        len > old(vec).len() ==> {
337            &&& final(vec)@.len() == len
338            &&& final(vec)@[..old(vec).len()] == old(vec)@
339            &&& forall|i| #![all_triggers] old(vec).len() <= i < len ==> cloned::<T>(value, final(vec)@[i])
340        },
341;
342
343pub broadcast proof fn axiom_vec_index_decreases<A>(v: Vec<A>, i: int)
344    requires
345        0 <= i < v.len(),
346    ensures
347        #[trigger] (decreases_to!(v => v[i])),
348{
349    admit();
350}
351
352pub assume_specification<T: PartialEq<U>, U, A1: Allocator, A2: Allocator>[ <Vec<T, A1> as PartialEq<Vec<U, A2>>>::eq ](
353    x: &Vec<T, A1>,
354    y: &Vec<U, A2>,
355) -> bool
356;
357
358impl<T: super::cmp::PartialEqSpec<U>, U, A1: Allocator, A2: Allocator> super::cmp::PartialEqSpecImpl<Vec<U, A2>> for Vec<T, A1> {
359    open spec fn obeys_eq_spec() -> bool {
360        T::obeys_eq_spec()
361    }
362
363    open spec fn eq_spec(&self, other: &Vec<U, A2>) -> bool {
364        &&& self.len() == other.len()
365        &&& forall|i: int| #![auto] 0 <= i < self.len() ==> self[i].eq_spec(&other[i])
366    }
367}
368
369// The `into_iter` method of a `Vec` returns an iterator of type `IntoIter`,
370// so we specify that type here.
371#[verifier::external_type_specification]
372#[verifier::external_body]
373#[verifier::accept_recursive_types(T)]
374#[verifier::reject_recursive_types(A)]
375pub struct ExIntoIter<T, A: Allocator>(IntoIter<T, A>);
376
377// To allow reasoning about the "contents" of the Vec iterator, without using
378// a prophecy, we need a function that gives us the underlying sequence of the original vec.
379pub uninterp spec fn into_iter_elts<T, A: Allocator>(i: IntoIter<T, A>) -> Seq<T>;
380
381impl <T, A: Allocator> super::iter::IteratorSpecImpl for IntoIter<T, A> {
382    open spec fn obeys_prophetic_iter_laws(&self) -> bool {
383        true
384    }
385
386    uninterp spec fn remaining(&self) -> Seq<Self::Item>;
387    #[verifier::prophetic]
388    open spec fn produces(&self) -> Seq<bool> {
389        Seq::new(IteratorSpec::remaining(self).len(), |i: int| true)
390    }
391    uninterp spec fn decrease(&self) -> Option<nat>;
392
393    open spec fn peek(&self, index: int) -> Option<Self::Item> {
394        if 0 <= index < into_iter_elts(*self).len() {
395            Some(into_iter_elts(*self)[index])
396        } else {
397            None
398        }
399    }
400}
401
402impl <T, A: Allocator> super::iter::DoubleEndedIteratorSpecImpl for IntoIter<T, A> {
403    open spec fn peek_back(&self, index: int) -> Option<Self::Item> {
404        let len = into_iter_elts(*self).len();
405        if 0 <= index < len {
406            Some(into_iter_elts(*self)[len - index - 1])
407        } else {
408            None
409        }
410    }
411}
412
413// This is used by `vec![x; n]`
414pub assume_specification<T: Clone>[ alloc::vec::from_elem ](elem: T, n: usize) -> (v: Vec<T>)
415    ensures
416        v.len() == n,
417        forall |i| 0 <= i < n ==> cloned(elem, #[trigger] v@[i]);
418
419pub assume_specification<T, A: Allocator>[ Vec::<T, A>::into_iter ](vec: Vec<T, A>) -> (iter: <Vec<
420    T,
421    A,
422> as core::iter::IntoIterator>::IntoIter)
423    ensures
424        IteratorSpec::remaining(&iter) == vec@,
425        into_iter_elts(iter) == IteratorSpec::remaining(&iter),
426        IteratorSpec::decrease(&iter) is Some,
427;
428
429pub assume_specification<'a, T, A: Allocator> [<&'a Vec<T, A> as core::iter::IntoIterator>::into_iter] (vec: &'a Vec<T, A>) ->
430    (iter: <&'a Vec<T, A> as core::iter::IntoIterator>::IntoIter)
431    ensures
432        IteratorSpec::remaining(&iter) == vec@.as_ref(),
433        super::slice::into_iter_elts(iter) == IteratorSpec::remaining(&iter).unref(),
434        IteratorSpec::decrease(&iter) is Some,
435;
436
437impl<T>  FromIteratorSpecImpl<T> for Vec<T> {
438    open spec fn from_iter_ensures(remaining: Seq<T>, produces: Seq<bool>, s: Self) -> bool {
439        &&& produces.len() == remaining.len()
440        &&& produces.all(|p: bool| p)
441        &&& remaining == s@
442    }
443}
444
445pub broadcast proof fn lemma_vec_obeys_eq_spec<T: PartialEq>()
446    requires
447        super::super::laws_eq::obeys_eq::<T>(),
448    ensures
449        #[trigger] super::super::laws_eq::obeys_eq::<Vec<T>>(),
450{
451    broadcast use {axiom_spec_len, super::super::seq::group_seq_lemmas};
452    reveal(super::super::laws_eq::obeys_eq_spec_properties);
453}
454
455pub broadcast proof fn lemma_vec_obeys_view_eq<T: PartialEq + View>()
456    requires
457        super::super::laws_eq::obeys_concrete_eq::<T>(),
458    ensures
459        #[trigger] super::super::laws_eq::obeys_view_eq::<Vec<T>>(),
460{
461    use super::cmp::PartialEqSpec;
462    broadcast use {axiom_spec_len, super::super::seq::group_seq_lemmas};
463    reveal(super::super::laws_eq::obeys_eq_spec_properties);
464    reveal(super::super::laws_eq::obeys_concrete_eq);
465    reveal(super::super::laws_eq::obeys_view_eq);
466    assert(forall|x: Vec<T>, y: Vec<T>| x.eq_spec(&y) ==> x@ == y@);
467}
468
469pub broadcast proof fn lemma_vec_obeys_deep_eq<T: PartialEq + DeepView>()
470    requires
471        super::super::laws_eq::obeys_deep_eq::<T>(),
472    ensures
473        #[trigger] super::super::laws_eq::obeys_deep_eq::<Vec<T>>(),
474{
475    use super::cmp::PartialEqSpec;
476    broadcast use {axiom_spec_len, super::super::seq::group_seq_lemmas};
477    reveal(super::super::laws_eq::obeys_eq_spec_properties);
478    reveal(super::super::laws_eq::obeys_deep_eq);
479    assert(forall|x: Vec<T>, y: Vec<T>| x.eq_spec(&y) ==> x.deep_view() == y.deep_view());
480    assert forall|x: Vec<T>, y: Vec<T>| x.deep_view() == y.deep_view() implies x.eq_spec(&y) by {
481        assert(x.deep_view().len() == y.deep_view().len());
482        assert forall|i: int| #![auto] 0 <= i < x.len() implies x[i].eq_spec(&y[i]) by {
483            assert(x.deep_view()[i] == y.deep_view()[i]);
484        }
485    }
486}
487
488pub broadcast axiom fn axiom_vec_has_resolved<T>(vec: Vec<T>, i: int)
489    ensures
490        0 <= i < vec.len() ==> #[trigger] has_resolved::<Vec<T>>(vec) ==> has_resolved(
491            #[trigger] vec@[i],
492        ),
493;
494
495pub broadcast axiom fn axiom_vec_decreases_to_view<T>(v: Vec<T>)
496    ensures
497        #[trigger] (decreases_to!(v => v@));
498
499pub broadcast group group_vec_axioms {
500    axiom_spec_len,
501    axiom_vec_index_decreases,
502    vec_clone_deep_view_proof,
503    axiom_vec_has_resolved,
504    axiom_vec_decreases_to_view,
505}
506
507pub axiom fn tracked_borrow_slice<T, A: Allocator>(tracked vec: &Vec<T, A>) -> (tracked t: &[T])
508    ensures t@ == vec@;
509
510pub axiom fn tracked_borrow_mut_slice<T, A: Allocator>(tracked vec: &mut Vec<T, A>) -> (tracked t: &mut [T])
511    ensures
512        (*t)@ == old(vec)@,
513        (*t).len() == final(t).len(),
514        final(vec)@ == final(t)@;
515
516} // verus!