use super::super::prelude::*; use super::iter::{FromIteratorSpecImpl, IteratorSpec}; use verus_builtin::*; use super::super::slice::SliceIndexSpec; use super::core::IndexSpec; use alloc::collections::TryReserveError; use alloc::vec::{IntoIter, Vec}; use core::alloc::Allocator; use core::clone::Clone; use core::marker::PhantomData; use core::ops::Index; use core::option::Option; use core::option::Option::None; use core::slice::SliceIndex; use verus as verus_skip_verusfmt; verus_skip_verusfmt! { #[verifier::external_type_specification] #[verifier::external_body] #[verifier::accept_recursive_types(T)] #[verifier::reject_recursive_types(A)] pub struct ExVec(Vec); pub trait VecAdditionalSpecFns: View> { spec fn spec_index(&self, i: int) -> T recommends 0 <= i < self.view().len(), ; } impl VecAdditionalSpecFns for Vec { #[verifier::inline] open spec fn spec_index(&self, i: int) -> T { self.view().index(i) } } #[verifier::external_type_specification] #[verifier::external_body] pub struct ExTryReserveError(alloc::collections::TryReserveError); // We still have a special case for Vec::index on usize. // The general Vec::index case now goes through the Index trait, // but this special case is still here because it's more direct and efficient in its SMT encoding, // and Vec::index on usize is very common. // // So this is a bit of a hack, but we just manually redirect // `vec[i]` to this function here from rust_to_vir_expr. #[verifier::external_body] #[cfg_attr(verus_keep_ghost, rustc_diagnostic_item = "verus::vstd::std_specs::vec::vec_index")] pub fn vec_index(vec: &Vec, i: usize) -> (element: &T) requires i < vec.view().len(), ensures *element == vec.view().index(i as int), no_unwind { &vec[i] } /// This is a specification for the indexing operator `vec[i]` when it expands to the `IndexMut` trait #[doc(hidden)] #[verifier::external_body] #[cfg_attr(verus_keep_ghost, rustc_diagnostic_item = "verus::vstd::std_specs::vec::vec_index_mut")] pub fn vec_index_mut(vec: &mut Vec, i: usize) -> (element: &mut T) requires i < vec.view().len(), ensures *element == old(vec)@.index(i as int), final(vec)@ == old(vec)@.update(i as int, *final(element)), *final(element) == final(vec).view().index(i as int), no_unwind { &mut vec[i] } ////// Len (with autospec) pub uninterp spec fn spec_vec_len(v: &Vec) -> usize; // This axiom is slightly better than defining spec_vec_len to just be `v@.len() as usize` // (the axiom also shows that v@.len() is in-bounds for usize) pub broadcast proof fn axiom_spec_len(v: &Vec) ensures #[trigger] spec_vec_len(v) == v@.len(), { admit(); } #[verifier::when_used_as_spec(spec_vec_len)] pub assume_specification[ Vec::::len ](vec: &Vec) -> (len: usize) ensures len == spec_vec_len(vec), no_unwind ; ////// Other functions pub assume_specification[ Vec::::new ]() -> (v: Vec) ensures v@ == Seq::::empty(), ; pub assume_specification[ as core::default::Default>::default ]() -> (v: Vec) ensures v@ == Seq::::empty(), ; pub assume_specification[ Vec::::new_in ](alloc: A) -> (v: Vec) ensures v@ == Seq::::empty(), ; pub assume_specification[ Vec::::with_capacity ](capacity: usize) -> (v: Vec) ensures v@ == Seq::::empty(), ; pub assume_specification[ Vec::::with_capacity_in ](capacity: usize, alloc: A) -> (v: Vec) ensures v@ == Seq::::empty(), ; pub assume_specification[ Vec::::reserve ]( vec: &mut Vec, additional: usize, ) ensures final(vec)@ == old(vec)@, ; pub assume_specification[ Vec::::try_reserve ]( vec: &mut Vec, additional: usize, ) -> (result: Result<(), TryReserveError>) ensures final(vec)@ == old(vec)@, ; pub assume_specification[ Vec::::try_reserve_exact ]( vec: &mut Vec, additional: usize, ) -> (result: Result<(), TryReserveError>) ensures final(vec)@ == old(vec)@, ; pub assume_specification[ Vec::::push ](vec: &mut Vec, value: T) ensures final(vec)@ == old(vec)@.push(value), ; pub assume_specification[ Vec::::pop ](vec: &mut Vec) -> (value: Option) ensures old(vec)@.len() > 0 ==> value == Some(old(vec)@[old(vec)@.len() - 1]) && final(vec)@ == old(vec)@[..old(vec)@.len() - 1], old(vec)@.len() == 0 ==> value == None:: && final(vec)@ == old(vec)@, ; pub assume_specification[ Vec::::append ]( vec: &mut Vec, other: &mut Vec, ) ensures final(vec)@ == old(vec)@ + old(other)@, final(other)@ == Seq::::empty(), ; pub assume_specification[ Vec::::extend_from_slice ]( vec: &mut Vec, other: &[T], ) ensures final(vec)@.len() == old(vec)@.len() + other@.len(), forall|i: int| #![trigger final(vec)@[i]] 0 <= i < final(vec)@.len() ==> if i < old(vec)@.len() { final(vec)@[i] == old(vec)@[i] } else { cloned::(other@[i - old(vec)@.len()], final(vec)@[i]) }, ; impl, A: Allocator> super::core::IndexSpecImpl for Vec { open spec fn index_req(&self, index: &I) -> bool { forall|s: &[T]| #[trigger] s@ == self@ ==> index.in_bounds(s) } } pub assume_specification, A: Allocator>[Vec::::index]( vec: &Vec, i: I, ) -> (r: & as Index>::Output) ensures exists|s: &[T]| #[trigger] s@ == vec@ && call_ensures(>::index, (i, s), r), ; pub assume_specification[ Vec::::swap_remove ]( vec: &mut Vec, i: usize, ) -> (element: T) requires i < old(vec).len(), ensures element == old(vec)[i as int], final(vec)@ == old(vec)@.update(i as int, old(vec)@.last()).drop_last(), ; pub assume_specification[ Vec::::insert ]( vec: &mut Vec, i: usize, element: T, ) requires i <= old(vec).len(), ensures final(vec)@ == old(vec)@.insert(i as int, element), ; pub assume_specification [ >::is_empty ]( v: &Vec, ) -> (res: bool) ensures res <==> v@.len() == 0, opens_invariants none no_unwind ; pub assume_specification[ Vec::::remove ]( vec: &mut Vec, i: usize, ) -> (element: T) requires i < old(vec).len(), ensures element == old(vec)[i as int], final(vec)@ == old(vec)@.remove(i as int), ; pub assume_specification[ Vec::::clear ](vec: &mut Vec) ensures final(vec).view() == Seq::::empty(), ; pub assume_specification[ Vec::::as_slice ](vec: &Vec) -> (slice: &[T]) ensures slice@ == vec@, opens_invariants none no_unwind ; pub assume_specification[ as core::convert::AsRef<[T]>>::as_ref ]( vec: &Vec, ) -> (slice: &[T]) ensures slice@ == vec@, opens_invariants none no_unwind ; #[doc(hidden)] pub assume_specification[ Vec::::as_mut_slice ](vec: &mut Vec) -> (slice: &mut [T]) ensures slice@ == old(vec)@, final(slice)@ == final(vec)@, opens_invariants none no_unwind ; pub assume_specification[ as core::ops::Deref>::deref ]( vec: &Vec, ) -> (slice: &[T]) ensures slice@ == vec@, ; pub assume_specification[ as core::ops::DerefMut>::deref_mut ]( vec: &mut Vec, ) -> (slice: &mut [T]) ensures slice@ == old(vec)@, final(slice)@ == final(vec)@, ; pub assume_specification[ Vec::::split_off ]( vec: &mut Vec, at: usize, ) -> (return_value: Vec) requires at <= old(vec)@.len(), ensures final(vec)@ == old(vec)@[..at], return_value@ == old(vec)@[at..], ; pub open spec fn vec_clone_trigger(v1: Vec, v2: Vec) -> bool { true } pub assume_specification[ as Clone>::clone ]( vec: &Vec, ) -> (res: Vec) ensures res.len() == vec.len(), forall|i| #![all_triggers] 0 <= i < vec.len() ==> cloned::(vec[i], res[i]), vec_clone_trigger(*vec, res), vec@ =~= res@ ==> vec@ == res@, ; pub broadcast proof fn vec_clone_deep_view_proof( v1: Vec, v2: Vec, ) requires #[trigger] vec_clone_trigger(v1, v2), v1.deep_view() =~= v2.deep_view(), ensures v1.deep_view() == v2.deep_view(), { } pub assume_specification[ Vec::::truncate ](vec: &mut Vec, len: usize) ensures len <= old(vec).len() ==> final(vec)@ == old(vec)@[..len], len > old(vec).len() ==> final(vec)@ == old(vec)@, ; pub assume_specification[ Vec::::resize ]( vec: &mut Vec, len: usize, value: T, ) ensures len <= old(vec).len() ==> final(vec)@ == old(vec)@[..len], len > old(vec).len() ==> { &&& final(vec)@.len() == len &&& final(vec)@[..old(vec).len()] == old(vec)@ &&& forall|i| #![all_triggers] old(vec).len() <= i < len ==> cloned::(value, final(vec)@[i]) }, ; pub broadcast proof fn axiom_vec_index_decreases(v: Vec, i: int) requires 0 <= i < v.len(), ensures #[trigger] (decreases_to!(v => v[i])), { admit(); } pub assume_specification, U, A1: Allocator, A2: Allocator>[ as PartialEq>>::eq ]( x: &Vec, y: &Vec, ) -> bool ; impl, U, A1: Allocator, A2: Allocator> super::cmp::PartialEqSpecImpl> for Vec { open spec fn obeys_eq_spec() -> bool { T::obeys_eq_spec() } open spec fn eq_spec(&self, other: &Vec) -> bool { &&& self.len() == other.len() &&& forall|i: int| #![auto] 0 <= i < self.len() ==> self[i].eq_spec(&other[i]) } } // The `into_iter` method of a `Vec` returns an iterator of type `IntoIter`, // so we specify that type here. #[verifier::external_type_specification] #[verifier::external_body] #[verifier::accept_recursive_types(T)] #[verifier::reject_recursive_types(A)] pub struct ExIntoIter(IntoIter); // To allow reasoning about the "contents" of the Vec iterator, without using // a prophecy, we need a function that gives us the underlying sequence of the original vec. pub uninterp spec fn into_iter_elts(i: IntoIter) -> Seq; impl super::iter::IteratorSpecImpl for IntoIter { open spec fn obeys_prophetic_iter_laws(&self) -> bool { true } uninterp spec fn remaining(&self) -> Seq; #[verifier::prophetic] open spec fn produces(&self) -> Seq { Seq::new(IteratorSpec::remaining(self).len(), |i: int| true) } uninterp spec fn decrease(&self) -> Option; open spec fn peek(&self, index: int) -> Option { if 0 <= index < into_iter_elts(*self).len() { Some(into_iter_elts(*self)[index]) } else { None } } } impl super::iter::DoubleEndedIteratorSpecImpl for IntoIter { open spec fn peek_back(&self, index: int) -> Option { let len = into_iter_elts(*self).len(); if 0 <= index < len { Some(into_iter_elts(*self)[len - index - 1]) } else { None } } } // This is used by `vec![x; n]` pub assume_specification[ alloc::vec::from_elem ](elem: T, n: usize) -> (v: Vec) ensures v.len() == n, forall |i| 0 <= i < n ==> cloned(elem, #[trigger] v@[i]); pub assume_specification[ Vec::::into_iter ](vec: Vec) -> (iter: as core::iter::IntoIterator>::IntoIter) ensures IteratorSpec::remaining(&iter) == vec@, into_iter_elts(iter) == IteratorSpec::remaining(&iter), IteratorSpec::decrease(&iter) is Some, ; pub assume_specification<'a, T, A: Allocator> [<&'a Vec as core::iter::IntoIterator>::into_iter] (vec: &'a Vec) -> (iter: <&'a Vec as core::iter::IntoIterator>::IntoIter) ensures IteratorSpec::remaining(&iter) == vec@.as_ref(), super::slice::into_iter_elts(iter) == IteratorSpec::remaining(&iter).unref(), IteratorSpec::decrease(&iter) is Some, ; impl FromIteratorSpecImpl for Vec { open spec fn from_iter_ensures(remaining: Seq, produces: Seq, s: Self) -> bool { &&& produces.len() == remaining.len() &&& produces.all(|p: bool| p) &&& remaining == s@ } } pub broadcast proof fn lemma_vec_obeys_eq_spec() requires super::super::laws_eq::obeys_eq::(), ensures #[trigger] super::super::laws_eq::obeys_eq::>(), { broadcast use {axiom_spec_len, super::super::seq::group_seq_lemmas}; reveal(super::super::laws_eq::obeys_eq_spec_properties); } pub broadcast proof fn lemma_vec_obeys_view_eq() requires super::super::laws_eq::obeys_concrete_eq::(), ensures #[trigger] super::super::laws_eq::obeys_view_eq::>(), { use super::cmp::PartialEqSpec; broadcast use {axiom_spec_len, super::super::seq::group_seq_lemmas}; reveal(super::super::laws_eq::obeys_eq_spec_properties); reveal(super::super::laws_eq::obeys_concrete_eq); reveal(super::super::laws_eq::obeys_view_eq); assert(forall|x: Vec, y: Vec| x.eq_spec(&y) ==> x@ == y@); } pub broadcast proof fn lemma_vec_obeys_deep_eq() requires super::super::laws_eq::obeys_deep_eq::(), ensures #[trigger] super::super::laws_eq::obeys_deep_eq::>(), { use super::cmp::PartialEqSpec; broadcast use {axiom_spec_len, super::super::seq::group_seq_lemmas}; reveal(super::super::laws_eq::obeys_eq_spec_properties); reveal(super::super::laws_eq::obeys_deep_eq); assert(forall|x: Vec, y: Vec| x.eq_spec(&y) ==> x.deep_view() == y.deep_view()); assert forall|x: Vec, y: Vec| x.deep_view() == y.deep_view() implies x.eq_spec(&y) by { assert(x.deep_view().len() == y.deep_view().len()); assert forall|i: int| #![auto] 0 <= i < x.len() implies x[i].eq_spec(&y[i]) by { assert(x.deep_view()[i] == y.deep_view()[i]); } } } pub broadcast axiom fn axiom_vec_has_resolved(vec: Vec, i: int) ensures 0 <= i < vec.len() ==> #[trigger] has_resolved::>(vec) ==> has_resolved( #[trigger] vec@[i], ), ; pub broadcast axiom fn axiom_vec_decreases_to_view(v: Vec) ensures #[trigger] (decreases_to!(v => v@)); pub broadcast group group_vec_axioms { axiom_spec_len, axiom_vec_index_decreases, vec_clone_deep_view_proof, axiom_vec_has_resolved, axiom_vec_decreases_to_view, } pub axiom fn tracked_borrow_slice(tracked vec: &Vec) -> (tracked t: &[T]) ensures t@ == vec@; pub axiom fn tracked_borrow_mut_slice(tracked vec: &mut Vec) -> (tracked t: &mut [T]) ensures (*t)@ == old(vec)@, (*t).len() == final(t).len(), final(vec)@ == final(t)@; } // verus!