1use super::super::prelude::*;
2use super::super::view::View;
3use super::cmp::{PartialOrdIs, PartialOrdSpec};
4use core::ops::{Range, RangeInclusive};
5
6verus! {
7
8#[verifier::external_type_specification]
9#[verifier::reject_recursive_types_in_ground_variants(Idx)]
10pub struct ExRange<Idx>(Range<Idx>);
11
12#[verifier::external_type_specification]
13#[verifier::external_body]
14#[verifier::reject_recursive_types_in_ground_variants(Idx)]
15pub struct ExRangeInclusive<Idx>(RangeInclusive<Idx>);
16
17pub struct RangeInclusiveView<Idx> {
18 pub start: Idx,
19 pub end: Idx,
20 pub exhausted: bool,
21}
22
23pub trait ContainsSpec<Idx, U> where Idx: PartialOrd<U>, U: ?Sized + PartialOrd<Idx> {
24 spec fn obeys_contains() -> bool;
25
26 spec fn contains_spec(&self, i: &U) -> bool;
27}
28
29impl<Idx, U> ContainsSpec<Idx, U> for RangeInclusive<Idx> where
30 Idx: PartialOrd<U>,
31 U: ?Sized + PartialOrd<Idx>,
32 {
33 open spec fn obeys_contains() -> bool {
34 (U::obeys_partial_cmp_spec() && <Idx as PartialOrdSpec<U>>::obeys_partial_cmp_spec())
35 }
36
37 open spec fn contains_spec(&self, i: &U) -> bool {
38 self@.start.is_le(&i) && if self@.exhausted {
39 i.is_lt(&self@.end)
40 } else {
41 i.is_le(&self@.end)
42 }
43 }
44}
45
46impl<Idx, U> ContainsSpec<Idx, U> for Range<Idx> where
47 Idx: PartialOrd<U>,
48 U: ?Sized + PartialOrd<Idx>,
49 {
50 open spec fn obeys_contains() -> bool {
51 (U::obeys_partial_cmp_spec() && <Idx as PartialOrdSpec<U>>::obeys_partial_cmp_spec())
52 }
53
54 open spec fn contains_spec(&self, i: &U) -> bool {
55 self.start.is_le(&i) && i.is_lt(&self.end)
56 }
57}
58
59impl<Idx> View for RangeInclusive<Idx> {
60 type V = RangeInclusiveView<Idx>;
61
62 uninterp spec fn view(&self) -> Self::V;
63}
64
65pub trait StepSpec where Self: Sized {
66 spec fn spec_is_lt(self, other: Self) -> bool;
68
69 spec fn spec_steps_between(self, end: Self) -> Option<usize>;
70
71 spec fn spec_steps_between_int(self, end: Self) -> int;
72
73 spec fn spec_forward_checked(self, count: usize) -> Option<Self>;
74
75 spec fn spec_forward_checked_int(self, count: int) -> Option<Self>;
76
77 spec fn spec_backward_checked(self, count: usize) -> Option<Self>;
78
79 spec fn spec_backward_checked_int(self, count: int) -> Option<Self>;
80}
81
82pub uninterp spec fn spec_range_next<A>(a: Range<A>) -> (Range<A>, Option<A>);
83
84pub assume_specification<A: core::iter::Step>[ Range::<A>::next ](range: &mut Range<A>) -> (r:
85 Option<A>)
86 ensures
87 (*range, r) == spec_range_next(*old(range)),
88;
89
90pub assume_specification<Idx: PartialOrd<Idx>, U>[ Range::<Idx>::contains ](
95 r: &Range<Idx>,
96 i: &U,
97) -> (ret: bool) where Idx: PartialOrd<U>, U: ?Sized + PartialOrd<Idx>
98 ensures
99 <Range::<Idx> as ContainsSpec<Idx, U>>::obeys_contains() ==> ret == r.contains_spec(i),
100;
101
102pub assume_specification<Idx: PartialOrd<Idx>, U>[ RangeInclusive::<Idx>::contains ](
103 r: &RangeInclusive<Idx>,
104 i: &U,
105) -> (ret: bool) where Idx: PartialOrd<U>, U: ?Sized + PartialOrd<Idx>
106 ensures
107 <RangeInclusive::<Idx> as ContainsSpec<Idx, U>>::obeys_contains() ==> ret
108 == r.contains_spec(i),
109;
110
111pub assume_specification<Idx>[ RangeInclusive::<Idx>::new ](start: Idx, end: Idx) -> (ret:
112 core::ops::RangeInclusive<Idx>)
113 ensures
114 ret@.start == start,
115 ret@.end == end,
116 ret@.exhausted == false,
117;
118
119pub struct RangeGhostIterator<A> {
120 pub start: A,
121 pub cur: A,
122 pub end: A,
123}
124
125impl<A: StepSpec> super::super::pervasive::ForLoopGhostIteratorNew for Range<A> {
126 type GhostIter = RangeGhostIterator<A>;
127
128 open spec fn ghost_iter(&self) -> RangeGhostIterator<A> {
129 RangeGhostIterator { start: self.start, cur: self.start, end: self.end }
130 }
131}
132
133impl<
134 A: StepSpec + core::iter::Step,
135> super::super::pervasive::ForLoopGhostIterator for RangeGhostIterator<A> {
136 type ExecIter = Range<A>;
137
138 type Item = A;
139
140 type Decrease = int;
141
142 open spec fn exec_invariant(&self, exec_iter: &Range<A>) -> bool {
143 &&& self.cur == exec_iter.start
144 &&& self.end == exec_iter.end
145 }
146
147 open spec fn ghost_invariant(&self, init: Option<&Self>) -> bool {
148 &&& self.start.spec_is_lt(self.cur) || self.start == self.cur
149 &&& self.cur.spec_is_lt(self.end) || self.cur
150 == self.end
151 &&& if let Some(init) = init {
153 &&& init.start == init.cur
154 &&& init.start == self.start
155 &&& init.end == self.end
156 } else {
157 true
158 }
159 }
160
161 open spec fn ghost_ensures(&self) -> bool {
162 !self.cur.spec_is_lt(self.end)
163 }
164
165 open spec fn ghost_decrease(&self) -> Option<int> {
166 Some(self.cur.spec_steps_between_int(self.end))
167 }
168
169 open spec fn ghost_peek_next(&self) -> Option<A> {
170 Some(self.cur)
171 }
172
173 open spec fn ghost_advance(&self, _exec_iter: &Range<A>) -> RangeGhostIterator<A> {
174 RangeGhostIterator { cur: self.cur.spec_forward_checked(1).unwrap(), ..*self }
175 }
176}
177
178impl<A: StepSpec + core::iter::Step> View for RangeGhostIterator<A> {
179 type V = Seq<A>;
180
181 open spec fn view(&self) -> Seq<A> {
183 Seq::new(
184 self.start.spec_steps_between_int(self.cur) as nat,
185 |i: int| self.start.spec_forward_checked_int(i).unwrap(),
186 )
187 }
188}
189
190} macro_rules! step_specs {
192 ($t: ty, $axiom: ident) => {
193 verus! {
194 impl StepSpec for $t {
195 open spec fn spec_is_lt(self, other: Self) -> bool {
196 self < other
197 }
198 open spec fn spec_steps_between(self, end: Self) -> Option<usize> {
199 let n = end - self;
200 if usize::MIN <= n <= usize::MAX {
201 Some(n as usize)
202 } else {
203 None
204 }
205 }
206 open spec fn spec_steps_between_int(self, end: Self) -> int {
207 end - self
208 }
209 open spec fn spec_forward_checked(self, count: usize) -> Option<Self> {
210 self.spec_forward_checked_int(count as int)
211 }
212 open spec fn spec_forward_checked_int(self, count: int) -> Option<Self> {
213 if self + count <= $t::MAX {
214 Some((self + count) as $t)
215 } else {
216 None
217 }
218 }
219 open spec fn spec_backward_checked(self, count: usize) -> Option<Self> {
220 self.spec_backward_checked_int(count as int)
221 }
222 open spec fn spec_backward_checked_int(self, count: int) -> Option<Self> {
223 if self - count >= $t::MIN {
224 Some((self - count) as $t)
225 } else {
226 None
227 }
228 }
229 }
230 pub broadcast proof fn $axiom(range: Range<$t>)
233 ensures
234 range.start.spec_is_lt(range.end) ==>
235 (if let Some(n) = range.start.spec_forward_checked(1) {
237 spec_range_next(range) == (Range { start: n, ..range }, Some(range.start))
238 } else {
239 true
240 }),
241 !range.start.spec_is_lt(range.end) ==>
242 #[trigger] spec_range_next(range) == (range, None::<$t>),
243 {
244 admit();
245 }
246 } };
248}
249
250step_specs!(u8, axiom_spec_range_next_u8);
251step_specs!(u16, axiom_spec_range_next_u16);
252step_specs!(u32, axiom_spec_range_next_u32);
253step_specs!(u64, axiom_spec_range_next_u64);
254step_specs!(u128, axiom_spec_range_next_u128);
255step_specs!(usize, axiom_spec_range_next_usize);
256step_specs!(i8, axiom_spec_range_next_i8);
257step_specs!(i16, axiom_spec_range_next_i16);
258step_specs!(i32, axiom_spec_range_next_i32);
259step_specs!(i64, axiom_spec_range_next_i64);
260step_specs!(i128, axiom_spec_range_next_i128);
261step_specs!(isize, axiom_spec_range_next_isize);
262
263verus! {
264
265pub broadcast group group_range_axioms {
266 axiom_spec_range_next_u8,
267 axiom_spec_range_next_u16,
268 axiom_spec_range_next_u32,
269 axiom_spec_range_next_u64,
270 axiom_spec_range_next_u128,
271 axiom_spec_range_next_usize,
272 axiom_spec_range_next_i8,
273 axiom_spec_range_next_i16,
274 axiom_spec_range_next_i32,
275 axiom_spec_range_next_i64,
276 axiom_spec_range_next_i128,
277 axiom_spec_range_next_isize,
278}
279
280}