1use super::super::prelude::*;
2use super::super::view::View;
3use super::cmp::{PartialOrdIs, PartialOrdSpec};
4use super::iter::{IteratorSpec, StepSpec, StepSpecImpl};
5use core::ops::{Range, RangeInclusive};
6
7verus! {
8
9#[verifier::external_type_specification]
10#[verifier::reject_recursive_types_in_ground_variants(Idx)]
11pub struct ExRange<Idx>(Range<Idx>);
12
13#[verifier::external_type_specification]
14#[verifier::external_body]
15#[verifier::reject_recursive_types_in_ground_variants(Idx)]
16pub struct ExRangeInclusive<Idx>(RangeInclusive<Idx>);
17
18pub struct RangeInclusiveView<Idx> {
19 pub start: Idx,
20 pub end: Idx,
21 pub exhausted: bool,
22}
23
24pub trait ContainsSpec<Idx, U> where Idx: PartialOrd<U>, U: ?Sized + PartialOrd<Idx> {
25 spec fn obeys_contains() -> bool;
26
27 spec fn contains_spec(&self, i: &U) -> bool;
28}
29
30impl<Idx, U> ContainsSpec<Idx, U> for RangeInclusive<Idx> where
31 Idx: PartialOrd<U>,
32 U: ?Sized + PartialOrd<Idx>,
33 {
34 open spec fn obeys_contains() -> bool {
35 (U::obeys_partial_cmp_spec() && <Idx as PartialOrdSpec<U>>::obeys_partial_cmp_spec())
36 }
37
38 open spec fn contains_spec(&self, i: &U) -> bool {
39 self@.start.is_le(&i) && if self@.exhausted {
40 i.is_lt(&self@.end)
41 } else {
42 i.is_le(&self@.end)
43 }
44 }
45}
46
47impl<Idx, U> ContainsSpec<Idx, U> for Range<Idx> where
48 Idx: PartialOrd<U>,
49 U: ?Sized + PartialOrd<Idx>,
50 {
51 open spec fn obeys_contains() -> bool {
52 (U::obeys_partial_cmp_spec() && <Idx as PartialOrdSpec<U>>::obeys_partial_cmp_spec())
53 }
54
55 open spec fn contains_spec(&self, i: &U) -> bool {
56 self.start.is_le(&i) && i.is_lt(&self.end)
57 }
58}
59
60impl<Idx> View for RangeInclusive<Idx> {
61 type V = RangeInclusiveView<Idx>;
62
63 uninterp spec fn view(&self) -> Self::V;
64}
65
66pub uninterp spec fn spec_range_next<A>(a: Range<A>) -> (Range<A>, Option<A>);
67
68pub assume_specification<Idx: PartialOrd<Idx>, U>[ Range::<Idx>::contains ](
73 r: &Range<Idx>,
74 i: &U,
75) -> (ret: bool) where Idx: PartialOrd<U>, U: ?Sized + PartialOrd<Idx>
76 ensures
77 <Range::<Idx> as ContainsSpec<Idx, U>>::obeys_contains() ==> ret == r.contains_spec(i),
78;
79
80pub assume_specification<Idx: PartialOrd<Idx>, U>[ RangeInclusive::<Idx>::contains ](
81 r: &RangeInclusive<Idx>,
82 i: &U,
83) -> (ret: bool) where Idx: PartialOrd<U>, U: ?Sized + PartialOrd<Idx>
84 ensures
85 <RangeInclusive::<Idx> as ContainsSpec<Idx, U>>::obeys_contains() ==> ret
86 == r.contains_spec(i),
87;
88
89pub uninterp spec fn spec_range_inclusive_new<Idx>(
97 start: Idx,
98 end: Idx,
99) -> core::ops::RangeInclusive<Idx>;
100
101pub broadcast axiom fn axiom_spec_range_inclusive_new<Idx>(start: Idx, end: Idx)
102 ensures
103 (#[trigger] spec_range_inclusive_new(start, end))@ == {
104 RangeInclusiveView { start, end, exhausted: false }
105 },
106;
107
108#[verifier::when_used_as_spec(spec_range_inclusive_new)]
109pub assume_specification<Idx>[ RangeInclusive::<Idx>::new ](start: Idx, end: Idx) -> (ret:
110 core::ops::RangeInclusive<Idx>)
111 ensures
112 ret == spec_range_inclusive_new(start, end),
113;
114
115impl<A: core::iter::Step> super::iter::IteratorSpecImpl for Range<A> {
116 open spec fn obeys_prophetic_iter_laws(&self) -> bool {
117 true
118 }
119
120 open spec fn remaining(&self) -> Seq<Self::Item> {
121 Seq::new(
122 self.start.spec_steps_between_int(self.end) as nat,
123 |i: int| self.start.spec_forward_checked_int(i).unwrap(),
124 )
125 }
126
127 uninterp spec fn will_return_none(&self) -> bool;
128
129 #[verifier::prophetic]
130 open spec fn initial_value_relation(&self, init: &Self) -> bool {
131 &&& (self.start.spec_steps_between_int(self.end) <= 0 && IteratorSpec::remaining(self).len()
135 == 0) || (self.start.spec_steps_between_int(self.end) == IteratorSpec::remaining(
136 self,
137 ).len() as int)
138 &&& forall|i: int|
139 0 <= i < IteratorSpec::remaining(self).len() ==> #[trigger] IteratorSpec::remaining(
140 self,
141 )[i] == self.start.spec_forward_checked_int(
142 i,
143 ).unwrap()
144 &&& self.start == init.start
146 &&& self.end == init.end
147 &&& (init.start.spec_steps_between_int(init.end) <= 0 && IteratorSpec::remaining(self).len()
148 == 0) || (init.start.spec_steps_between_int(self.end) == IteratorSpec::remaining(
149 self,
150 ).len() as int)
151 &&& forall|i: int|
152 0 <= i < IteratorSpec::remaining(self).len() ==> #[trigger] IteratorSpec::remaining(
153 self,
154 )[i] == init.start.spec_forward_checked_int(i).unwrap()
155 }
156
157 open spec fn decrease(&self) -> Option<nat> {
158 Some(self.start.spec_steps_between_int(self.end) as nat)
159 }
160
161 open spec fn peek(&self, index: int) -> Option<Self::Item> {
162 if 0 <= index <= self.start.spec_steps_between_int(self.end) {
164 Some(self.start.spec_forward_checked_int(index).unwrap())
165 } else {
166 None
167 }
168 }
169}
170
171impl<A: core::iter::Step> super::iter::IteratorSpecImpl for RangeInclusive<A> {
172 open spec fn obeys_prophetic_iter_laws(&self) -> bool {
173 true
174 }
175
176 open spec fn remaining(&self) -> Seq<Self::Item> {
177 Seq::new(
178 (self@.start.spec_steps_between_int(self@.end) + 1) as nat,
179 |i: int| self@.start.spec_forward_checked_int(i).unwrap(),
180 )
181 }
182
183 uninterp spec fn will_return_none(&self) -> bool;
184
185 #[verifier::prophetic]
186 open spec fn initial_value_relation(&self, init: &Self) -> bool {
187 &&& (self@.start.spec_steps_between_int(self@.end) + 1 <= 0 && IteratorSpec::remaining(
191 self,
192 ).len() == 0) || (self@.start.spec_steps_between_int(self@.end) + 1
193 == IteratorSpec::remaining(self).len() as int)
194 &&& forall|i: int|
195 0 <= i < IteratorSpec::remaining(self).len() ==> #[trigger] IteratorSpec::remaining(
196 self,
197 )[i] == self@.start.spec_forward_checked_int(
198 i,
199 ).unwrap()
200 &&& self@.start == init@.start
202 &&& self@.end == init@.end
203 &&& (init@.start.spec_steps_between_int(init@.end) + 1 <= 0 && IteratorSpec::remaining(
204 self,
205 ).len() == 0) || (init@.start.spec_steps_between_int(self@.end) + 1
206 == IteratorSpec::remaining(self).len() as int)
207 &&& forall|i: int|
208 0 <= i < IteratorSpec::remaining(self).len() ==> #[trigger] IteratorSpec::remaining(
209 self,
210 )[i] == init@.start.spec_forward_checked_int(i).unwrap()
211 }
212
213 open spec fn decrease(&self) -> Option<nat> {
214 Some((self@.start.spec_steps_between_int(self@.end) + 1) as nat)
215 }
216
217 open spec fn peek(&self, index: int) -> Option<Self::Item> {
218 if 0 <= index <= self@.start.spec_steps_between_int(self@.end) + 1 {
219 Some(self@.start.spec_forward_checked_int(index).unwrap())
220 } else {
221 None
222 }
223 }
224}
225
226pub assume_specification<A: core::iter::Step>[ <Range<A> as Iterator>::next ](
227 range: &mut Range<A>,
228) -> (r: Option<A>)
229 ensures
230 (*final(range), r) == spec_range_next(*old(range)),
231;
232
233} macro_rules! step_specs {
235 ($t: ty, $axiom: ident) => {
236 verus! {
237 impl StepSpecImpl for $t {
238 open spec fn spec_is_lt(self, other: Self) -> bool {
239 self < other
240 }
241 open spec fn spec_steps_between(self, end: Self) -> Option<usize> {
242 let n = end - self;
243 if usize::MIN <= n <= usize::MAX {
244 Some(n as usize)
245 } else {
246 None
247 }
248 }
249 open spec fn spec_steps_between_int(self, end: Self) -> int {
250 end - self
251 }
252 open spec fn spec_forward_checked(self, count: usize) -> Option<Self> {
253 StepSpec::spec_forward_checked_int(self, count as int)
254 }
255 open spec fn spec_forward_checked_int(self, count: int) -> Option<Self> {
256 if self + count <= $t::MAX {
257 Some((self + count) as $t)
258 } else {
259 None
260 }
261 }
262 open spec fn spec_backward_checked(self, count: usize) -> Option<Self> {
263 StepSpec::spec_backward_checked_int(self, count as int)
264 }
265 open spec fn spec_backward_checked_int(self, count: int) -> Option<Self> {
266 if self - count >= $t::MIN {
267 Some((self - count) as $t)
268 } else {
269 None
270 }
271 }
272 }
273 pub broadcast proof fn $axiom(range: Range<$t>)
276 ensures
277 StepSpec::spec_is_lt(range.start, range.end) ==>
278 (if let Some(n) = StepSpec::spec_forward_checked(range.start, 1) {
280 spec_range_next(range) == (Range { start: n, ..range }, Some(range.start))
281 } else {
282 true
283 }),
284 !StepSpec::spec_is_lt(range.start, range.end) ==>
285 #[trigger] spec_range_next(range) == (range, None::<$t>),
286 {
287 admit();
288 }
289 } };
291}
292
293step_specs!(u8, axiom_spec_range_next_u8);
294step_specs!(u16, axiom_spec_range_next_u16);
295step_specs!(u32, axiom_spec_range_next_u32);
296step_specs!(u64, axiom_spec_range_next_u64);
297step_specs!(u128, axiom_spec_range_next_u128);
298step_specs!(usize, axiom_spec_range_next_usize);
299step_specs!(i8, axiom_spec_range_next_i8);
300step_specs!(i16, axiom_spec_range_next_i16);
301step_specs!(i32, axiom_spec_range_next_i32);
302step_specs!(i64, axiom_spec_range_next_i64);
303step_specs!(i128, axiom_spec_range_next_i128);
304step_specs!(isize, axiom_spec_range_next_isize);
305
306verus! {
307
308pub broadcast group group_range_axioms {
309 axiom_spec_range_next_u8,
310 axiom_spec_range_next_u16,
311 axiom_spec_range_next_u32,
312 axiom_spec_range_next_u64,
313 axiom_spec_range_next_u128,
314 axiom_spec_range_next_usize,
315 axiom_spec_range_next_i8,
316 axiom_spec_range_next_i16,
317 axiom_spec_range_next_i32,
318 axiom_spec_range_next_i64,
319 axiom_spec_range_next_i128,
320 axiom_spec_range_next_isize,
321 axiom_spec_range_inclusive_new,
322}
323
324}