vstd/std_specs/
range.rs
1use super::super::prelude::*;
2use super::super::view::View;
3use super::cmp::{PartialOrdIs, PartialOrdSpec};
4use core::ops::Range;
5
6verus! {
7
8#[verifier::external_type_specification]
9#[verifier::reject_recursive_types_in_ground_variants(Idx)]
10pub struct ExRange<Idx>(Range<Idx>);
11
12pub trait StepSpec where Self: Sized {
13 spec fn spec_is_lt(self, other: Self) -> bool;
15
16 spec fn spec_steps_between(self, end: Self) -> Option<usize>;
17
18 spec fn spec_steps_between_int(self, end: Self) -> int;
19
20 spec fn spec_forward_checked(self, count: usize) -> Option<Self>;
21
22 spec fn spec_forward_checked_int(self, count: int) -> Option<Self>;
23
24 spec fn spec_backward_checked(self, count: usize) -> Option<Self>;
25
26 spec fn spec_backward_checked_int(self, count: int) -> Option<Self>;
27}
28
29pub uninterp spec fn spec_range_next<A>(a: Range<A>) -> (Range<A>, Option<A>);
30
31pub assume_specification<A: core::iter::Step>[ Range::<A>::next ](range: &mut Range<A>) -> (r:
32 Option<A>)
33 ensures
34 (*range, r) == spec_range_next(*old(range)),
35;
36
37pub assume_specification<Idx: PartialOrd<Idx>, U>[ Range::<Idx>::contains ](
42 r: &Range<Idx>,
43 i: &U,
44) -> (ret: bool) where Idx: PartialOrd<U>, U: ?Sized + PartialOrd<Idx>
45 ensures
46 (U::obeys_partial_cmp_spec() && <Idx as PartialOrdSpec<U>>::obeys_partial_cmp_spec())
47 ==> ret == (r.start.is_le(i) && i.is_lt(&r.end)),
48;
49
50pub struct RangeGhostIterator<A> {
51 pub start: A,
52 pub cur: A,
53 pub end: A,
54}
55
56impl<A: StepSpec> super::super::pervasive::ForLoopGhostIteratorNew for Range<A> {
57 type GhostIter = RangeGhostIterator<A>;
58
59 open spec fn ghost_iter(&self) -> RangeGhostIterator<A> {
60 RangeGhostIterator { start: self.start, cur: self.start, end: self.end }
61 }
62}
63
64impl<
65 A: StepSpec + core::iter::Step,
66> super::super::pervasive::ForLoopGhostIterator for RangeGhostIterator<A> {
67 type ExecIter = Range<A>;
68
69 type Item = A;
70
71 type Decrease = int;
72
73 open spec fn exec_invariant(&self, exec_iter: &Range<A>) -> bool {
74 &&& self.cur == exec_iter.start
75 &&& self.end == exec_iter.end
76 }
77
78 open spec fn ghost_invariant(&self, init: Option<&Self>) -> bool {
79 &&& self.start.spec_is_lt(self.cur) || self.start == self.cur
80 &&& self.cur.spec_is_lt(self.end) || self.cur
81 == self.end
82 &&& if let Some(init) = init {
84 &&& init.start == init.cur
85 &&& init.start == self.start
86 &&& init.end == self.end
87 } else {
88 true
89 }
90 }
91
92 open spec fn ghost_ensures(&self) -> bool {
93 !self.cur.spec_is_lt(self.end)
94 }
95
96 open spec fn ghost_decrease(&self) -> Option<int> {
97 Some(self.cur.spec_steps_between_int(self.end))
98 }
99
100 open spec fn ghost_peek_next(&self) -> Option<A> {
101 Some(self.cur)
102 }
103
104 open spec fn ghost_advance(&self, _exec_iter: &Range<A>) -> RangeGhostIterator<A> {
105 RangeGhostIterator { cur: self.cur.spec_forward_checked(1).unwrap(), ..*self }
106 }
107}
108
109impl<A: StepSpec + core::iter::Step> View for RangeGhostIterator<A> {
110 type V = Seq<A>;
111
112 open spec fn view(&self) -> Seq<A> {
114 Seq::new(
115 self.start.spec_steps_between_int(self.cur) as nat,
116 |i: int| self.start.spec_forward_checked_int(i).unwrap(),
117 )
118 }
119}
120
121} macro_rules! step_specs {
123 ($t: ty, $axiom: ident) => {
124 verus! {
125 impl StepSpec for $t {
126 open spec fn spec_is_lt(self, other: Self) -> bool {
127 self < other
128 }
129 open spec fn spec_steps_between(self, end: Self) -> Option<usize> {
130 let n = end - self;
131 if usize::MIN <= n <= usize::MAX {
132 Some(n as usize)
133 } else {
134 None
135 }
136 }
137 open spec fn spec_steps_between_int(self, end: Self) -> int {
138 end - self
139 }
140 open spec fn spec_forward_checked(self, count: usize) -> Option<Self> {
141 self.spec_forward_checked_int(count as int)
142 }
143 open spec fn spec_forward_checked_int(self, count: int) -> Option<Self> {
144 if self + count <= $t::MAX {
145 Some((self + count) as $t)
146 } else {
147 None
148 }
149 }
150 open spec fn spec_backward_checked(self, count: usize) -> Option<Self> {
151 self.spec_backward_checked_int(count as int)
152 }
153 open spec fn spec_backward_checked_int(self, count: int) -> Option<Self> {
154 if self - count >= $t::MIN {
155 Some((self - count) as $t)
156 } else {
157 None
158 }
159 }
160 }
161 pub broadcast proof fn $axiom(range: Range<$t>)
164 ensures
165 range.start.spec_is_lt(range.end) ==>
166 (if let Some(n) = range.start.spec_forward_checked(1) {
168 spec_range_next(range) == (Range { start: n, ..range }, Some(range.start))
169 } else {
170 true
171 }),
172 !range.start.spec_is_lt(range.end) ==>
173 #[trigger] spec_range_next(range) == (range, None::<$t>),
174 {
175 admit();
176 }
177 } };
179}
180
181step_specs!(u8, axiom_spec_range_next_u8);
182step_specs!(u16, axiom_spec_range_next_u16);
183step_specs!(u32, axiom_spec_range_next_u32);
184step_specs!(u64, axiom_spec_range_next_u64);
185step_specs!(u128, axiom_spec_range_next_u128);
186step_specs!(usize, axiom_spec_range_next_usize);
187step_specs!(i8, axiom_spec_range_next_i8);
188step_specs!(i16, axiom_spec_range_next_i16);
189step_specs!(i32, axiom_spec_range_next_i32);
190step_specs!(i64, axiom_spec_range_next_i64);
191step_specs!(i128, axiom_spec_range_next_i128);
192step_specs!(isize, axiom_spec_range_next_isize);
193
194verus! {
195
196pub broadcast group group_range_axioms {
197 axiom_spec_range_next_u8,
198 axiom_spec_range_next_u16,
199 axiom_spec_range_next_u32,
200 axiom_spec_range_next_u64,
201 axiom_spec_range_next_u128,
202 axiom_spec_range_next_usize,
203 axiom_spec_range_next_i8,
204 axiom_spec_range_next_i16,
205 axiom_spec_range_next_i32,
206 axiom_spec_range_next_i64,
207 axiom_spec_range_next_i128,
208 axiom_spec_range_next_isize,
209}
210
211}