/// This code adds specifications for the standard-library type /// `std::collections::VecDeque`. use super::super::prelude::*; use super::iter::IteratorSpec; use alloc::collections::vec_deque::Iter; use alloc::collections::vec_deque::VecDeque; use core::alloc::Allocator; use core::clone::Clone; use core::ops::{Index, IndexMut}; use core::option::Option; use core::option::Option::None; verus! { #[verifier::external_type_specification] #[verifier::external_body] #[verifier::accept_recursive_types(T)] #[verifier::reject_recursive_types(A)] pub struct ExVecDeque(VecDeque); impl View for VecDeque { type V = Seq; uninterp spec fn view(&self) -> Seq; } impl DeepView for VecDeque { type V = Seq; open spec fn deep_view(&self) -> Seq { let v = self.view(); Seq::new(v.len(), |i: int| v[i].deep_view()) } } pub trait VecDequeAdditionalSpecFns: View> { spec fn spec_index(&self, i: int) -> T recommends 0 <= i < self.view().len(), ; } impl VecDequeAdditionalSpecFns for VecDeque { #[verifier::inline] open spec fn spec_index(&self, i: int) -> T { self.view().index(i) } } ////// Len (with autospec) pub uninterp spec fn spec_vec_dequeue_len(v: &VecDeque) -> usize; // This axiom is slightly better than defining spec_vec_dequeue_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: &VecDeque) ensures #[trigger] spec_vec_dequeue_len(v) == v@.len(), { admit(); } impl super::core::IndexSpecImpl for VecDeque { open spec fn index_req(&self, index: &usize) -> bool { *index < self.len() } } pub assume_specification[ VecDeque::::index ]( v: &VecDeque, i: usize, ) -> (output: &T) ensures output == v.spec_index(i as int), ; pub assume_specification[ VecDeque::::index_mut ]( v: &mut VecDeque, i: usize, ) -> (output: &mut T) ensures *output == old(v).spec_index(i as int), final(v)@ == old(v)@.update(i as int, *final(output)), ; #[verifier::when_used_as_spec(spec_vec_dequeue_len)] pub assume_specification[ VecDeque::::len ](v: &VecDeque) -> (len: usize) ensures len == spec_vec_dequeue_len(v), ; pub assume_specification[ VecDeque::::new ]() -> (v: VecDeque) ensures v@ == Seq::::empty(), ; pub assume_specification[ as core::default::Default>::default ]() -> (v: VecDeque< T, >) ensures v@ == Seq::::empty(), ; pub assume_specification[ VecDeque::::with_capacity ](capacity: usize) -> (v: VecDeque) ensures v@ == Seq::::empty(), ; pub assume_specification[ VecDeque::::reserve ]( v: &mut VecDeque, additional: usize, ) ensures final(v)@ == old(v)@, ; pub assume_specification[ VecDeque::::push_back ]( v: &mut VecDeque, value: T, ) ensures final(v)@ == old(v)@.push(value), ; pub assume_specification[ VecDeque::::push_front ]( v: &mut VecDeque, value: T, ) ensures final(v)@ == seq![value] + old(v)@, ; pub assume_specification[ VecDeque::::pop_back ]( v: &mut VecDeque, ) -> (value: Option) ensures match value { Some(x) => { &&& old(v)@.len() > 0 &&& x == old(v)@[old(v)@.len() - 1] &&& final(v)@ == old(v)@[..old(v)@.len() - 1] }, None => { &&& old(v)@.len() == 0 &&& final(v)@ == old(v)@ }, }, ; pub assume_specification[ VecDeque::::pop_front ]( v: &mut VecDeque, ) -> (value: Option) ensures match value { Some(x) => { &&& old(v)@.len() > 0 &&& x == old(v)@[0] &&& final(v)@ == old(v)@[1..] }, None => { &&& old(v)@.len() == 0 &&& final(v)@ == old(v)@ }, }, ; pub assume_specification[ VecDeque::::append ]( v: &mut VecDeque, other: &mut VecDeque, ) ensures final(v)@ == old(v)@ + old(other)@, final(other)@ == Seq::::empty(), ; pub assume_specification[ VecDeque::::insert ]( v: &mut VecDeque, i: usize, element: T, ) requires i <= old(v).len(), ensures final(v)@ == old(v)@.insert(i as int, element), ; pub assume_specification[ VecDeque::::remove ]( v: &mut VecDeque, i: usize, ) -> (element: Option) ensures match element { Some(x) => { &&& i < old(v)@.len() &&& x == old(v)@[i as int] &&& final(v)@ == old(v)@.remove(i as int) }, None => { &&& old(v)@.len() <= i &&& final(v)@ == old(v)@ }, }, ; pub assume_specification[ VecDeque::::clear ](v: &mut VecDeque) ensures final(v).view() == Seq::::empty(), ; pub assume_specification[ VecDeque::::split_off ]( v: &mut VecDeque, at: usize, ) -> (return_value: VecDeque) requires at <= old(v)@.len(), ensures final(v)@ == old(v)@[..at], return_value@ == old(v)@[at..], ; pub open spec fn vec_dequeue_clone_trigger( v1: VecDeque, v2: VecDeque, ) -> bool { true } pub assume_specification[ as Clone>::clone ]( v: &VecDeque, ) -> (res: VecDeque) ensures res.len() == v.len(), forall|i| #![all_triggers] 0 <= i < v.len() ==> cloned::(v[i], res[i]), vec_dequeue_clone_trigger(*v, res), v@ =~= res@ ==> v@ == res@, ; pub assume_specification[ VecDeque::::truncate ]( v: &mut VecDeque, len: usize, ) ensures len <= old(v).len() ==> final(v)@ == old(v)@[..len], len > old(v).len() ==> final(v)@ == old(v)@, ; pub assume_specification[ VecDeque::::resize ]( v: &mut VecDeque, len: usize, value: T, ) ensures len <= old(v).len() ==> final(v)@ == old(v)@[..len], len > old(v).len() ==> { &&& final(v)@.len() == len &&& final(v)@[..old(v).len()] == old(v)@ &&& forall|i| #![all_triggers] old(v).len() <= i < len ==> cloned::(value, final(v)@[i]) }, ; pub broadcast proof fn axiom_vec_dequeue_index_decreases(v: VecDeque, i: int) requires 0 <= i < v.len(), ensures #[trigger] (decreases_to!(v => v[i])), { admit(); } // The `iter` method of a `VecDeque` returns an iterator of type `Iter`, // so we specify that type here. #[verifier::external_type_specification] #[verifier::external_body] #[verifier::accept_recursive_types(T)] pub struct ExIter<'a, T: 'a>(Iter<'a, T>); // To allow reasoning about the "contents" of the VecDeque 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<'a, T: 'a>(i: Iter<'a, T>) -> Seq<&'a T>; impl<'a, T: 'a> super::iter::IteratorSpecImpl for Iter<'a, T> { 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<'a, T: 'a> super::iter::DoubleEndedIteratorSpecImpl for Iter<'a, T> { open spec fn peek_back(&self, index: int) -> Option { if 0 <= index < into_iter_elts(*self).len() { Some(&into_iter_elts(*self)[into_iter_elts(*self).len() - index - 1]) } else { None } } } pub assume_specification<'a, T, A: Allocator>[ VecDeque::::iter ]( v: &'a VecDeque, ) -> (iter: Iter<'a, T>) ensures IteratorSpec::remaining(&iter) == v@.as_ref(), into_iter_elts(iter) == IteratorSpec::remaining(&iter), IteratorSpec::decrease(&iter) is Some, ; pub broadcast group group_vec_dequeue_axioms { axiom_spec_len, axiom_vec_dequeue_index_decreases, } } // verus!