Skip to main content

vstd/std_specs/
iter.rs

1use super::super::prelude::*;
2use super::super::seq::{
3    axiom_seq_empty, axiom_seq_subrange_index, axiom_seq_subrange_len, group_seq_axioms,
4};
5
6use verus as verus_;
7
8use core::iter::{FromIterator, Iterator, Rev};
9
10verus_! {
11
12#[verifier::external_trait_specification]
13#[verifier::external_trait_extension(IteratorSpec via IteratorSpecImpl)]
14pub trait ExIterator {
15    type ExternalTraitSpecificationFor: Iterator;
16
17    type Item;
18
19    /// This iterator obeys the specifications below on `next`,
20    /// expressed in terms of prophetic spec functions.
21    /// Only iterators that terminate (i.e., eventually return None
22    /// and then continue to return None) should use this interface.
23    spec fn obeys_prophetic_iter_laws(&self) -> bool;
24
25    /// Sequence of items that will (eventually) be returned
26    #[verifier::prophetic]
27    spec fn remaining(&self) -> Seq<Self::Item>;
28
29    /// Does this iterator complete with a `None` after the above sequence?
30    /// (As opposed to hanging indefinitely on a `next()` call)
31    /// Trivially true for most iterators but important for iterators
32    /// that apply an exec closure that may not terminate.
33    #[verifier::prophetic]
34    spec fn will_return_none(&self) -> bool;
35
36    /// Advances the iterator and returns the next value.
37    fn next(&mut self) -> (ret: Option<Self::Item>)
38        ensures
39            // The iterator consistently obeys, completes, and decreases throughout its lifetime
40            final(self).obeys_prophetic_iter_laws() == old(self).obeys_prophetic_iter_laws(),
41            final(self).obeys_prophetic_iter_laws() ==> final(self).will_return_none() == old(self).will_return_none(),
42            final(self).obeys_prophetic_iter_laws() ==> (old(self).decrease() is Some <==> final(self).decrease() is Some),
43            // `next` pops the head of the prophesized remaining(), or returns None
44            final(self).obeys_prophetic_iter_laws() ==>
45            ({
46                if old(self).remaining().len() > 0 {
47                    &&& final(self).remaining() == old(self).remaining().drop_first()
48                    &&& ret == Some(old(self).remaining()[0])
49                } else {
50                    final(self).remaining() == old(self).remaining() && ret == None && final(self).will_return_none()
51                }
52            }),
53            // If the iterator isn't done yet, then it successfully decreases its metric (if any)
54            final(self).obeys_prophetic_iter_laws() && old(self).remaining().len() > 0 && final(self).decrease() is Some ==>
55                decreases_to!(old(self).decrease()->0 => final(self).decrease()->0),
56    ;
57
58    /******* Mechanisms that support ergonomic `for` loops *********/
59
60    /// Value used by default for the decreases clause when no explicit decreases clause is provided
61    /// (the user can override this with an explicit decreases clause).
62    /// If there's no appropriate metric to decrease, this can return None,
63    /// and the user will have to provide an explicit decreases clause.
64    spec fn decrease(&self) -> Option<nat>;
65
66    /// Invariant relating the iterator to the initial expression that created it
67    /// (e.g., `my_vec.iter()`).  This allows for more ergonomic/intuitive invariants.
68    /// When the analysis can infer a spec initial value (by discovering a `when_used_as_spec`
69    /// annotation), the analysis places the value in init.
70    #[verifier::prophetic]
71    spec fn initial_value_relation(&self, init: &Self) -> bool;
72
73    // If we can make a useful guess as to what the i-th value will be, return it.
74    // Otherwise, return None.
75    spec fn peek(&self, index: int) -> Option<Self::Item>;
76
77    // Provided methods
78
79    // TODO: Once we can add when_used_as_spec to provided trait methods, this would be a simpler encoding:
80    //#[verifier::when_used_as_spec(into_rev_spec)]
81    fn rev(self) -> (r: Rev<Self>)
82        where Self: Sized,
83        default_ensures
84            self.obeys_prophetic_iter_laws() && self.initial_value_relation(&self) ==>
85                r == into_rev_spec(self) && rev_post(self, r),
86    ;
87
88    fn collect<B>(self) -> (collection: B)
89        where
90            B: FromIterator<Self::Item>,
91            Self: Sized,
92        default_ensures
93            self.will_return_none(),
94            self.obeys_prophetic_iter_laws() && self.initial_value_relation(&self) ==>
95                FromIteratorSpec::from_iter_ensures(self.remaining(), collection),
96    ;
97
98    fn find<P>(&mut self, predicate: P) -> (r: Option<Self::Item>)
99        where Self: Sized,
100            P: FnMut(&Self::Item) -> bool
101        default_ensures
102            // The iterator consistently obeys, completes, and decreases throughout its lifetime
103            final(self).obeys_prophetic_iter_laws() == old(self).obeys_prophetic_iter_laws(),
104            final(self).obeys_prophetic_iter_laws() ==> final(self).will_return_none() == old(self).will_return_none(),
105            final(self).obeys_prophetic_iter_laws() ==> (old(self).decrease() is Some <==> final(self).decrease() is Some),
106            final(self).obeys_prophetic_iter_laws() ==> {
107                final(self).remaining().is_suffix_of(old(self).remaining())
108            },
109            // If find returns None, then the iterator has no remaining
110            // elements, and the predicate was false for all of the original
111            // iterator's elements.
112            final(self).obeys_prophetic_iter_laws() && r.is_none() ==> {
113                &&& final(self).remaining().len() == 0
114                &&& forall |i| 0 <= i < old(self).remaining().len() ==>
115                    predicate.ensures((#[trigger]&old(self).remaining()[i],), false)
116            },
117            // If find returns Some, then the returned value satisfies the
118            // predicate, and all previous elements did not satisfy the
119            // predicate.
120            final(self).obeys_prophetic_iter_laws() && r.is_some() ==> {
121                let idx = old(self).remaining().len() - final(self).remaining().len() - 1;
122                {
123                    &&& old(self).remaining().len() > 0
124                    &&& predicate.ensures((&r.unwrap(),), true)
125                    &&& old(self).remaining()[idx] == r.unwrap()
126                    &&& forall |i| 0 <= i < idx ==>
127                        predicate.ensures((#[trigger] &old(self).remaining()[i],), false)
128                }
129            };
130
131    // TODO: The Rust implementations of `all` and `any` depend on a correct implementation of `try_fold`
132    //       For now, we assume obeys_prophetic_iter_laws() entails such an implementation, but we should
133    //       eventually constrain implementations of `try_fold` to actually be correct enough to uphold the specs below.
134
135    fn all<F>(&mut self, f: F) -> (r: bool)
136        where Self: Sized,
137            F: FnMut(Self::Item) -> bool
138        default_ensures
139            // The iterator consistently obeys, completes, and decreases throughout its lifetime
140            final(self).obeys_prophetic_iter_laws() == old(self).obeys_prophetic_iter_laws(),
141            final(self).obeys_prophetic_iter_laws() ==> final(self).will_return_none() == old(self).will_return_none(),
142            final(self).obeys_prophetic_iter_laws() ==> (old(self).decrease() is Some <==> final(self).decrease() is Some),
143            final(self).obeys_prophetic_iter_laws() ==> {
144                final(self).remaining().is_suffix_of(old(self).remaining())
145            },
146            // If all returns true, then the iterator has no remaining elements,
147            // and the predicate was true for all of the original iterator's elements.
148            final(self).obeys_prophetic_iter_laws() && r ==> {
149                &&& final(self).remaining().len() == 0
150                &&& forall |i| 0 <= i < old(self).remaining().len() ==>
151                    f.ensures((#[trigger] old(self).remaining()[i],), true)
152            },
153            // If all returns false, then there is some element for which the
154            // predicate was false, and all previous elements satisfied the predicate.
155            final(self).obeys_prophetic_iter_laws() && !r ==> {
156                let idx = old(self).remaining().len() - final(self).remaining().len() - 1;
157                {
158                    // The failing element was consumed, so the remaining sequence strictly shrank
159                    &&& final(self).remaining().len() < old(self).remaining().len()
160                    &&& f.ensures((old(self).remaining()[idx],), false)
161                    &&& forall |i| 0 <= i < idx ==>
162                        f.ensures((#[trigger] old(self).remaining()[i],), true)
163                }
164            };
165
166    fn any<F>(&mut self, f: F) -> (r: bool)
167        where Self: Sized,
168            F: FnMut(Self::Item) -> bool
169        default_ensures
170            // The iterator consistently obeys, completes, and decreases throughout its lifetime
171            final(self).obeys_prophetic_iter_laws() == old(self).obeys_prophetic_iter_laws(),
172            final(self).obeys_prophetic_iter_laws() ==> final(self).will_return_none() == old(self).will_return_none(),
173            final(self).obeys_prophetic_iter_laws() ==> (old(self).decrease() is Some <==> final(self).decrease() is Some),
174            final(self).obeys_prophetic_iter_laws() ==> {
175                final(self).remaining().is_suffix_of(old(self).remaining())
176            },
177            // If any returns false, then the iterator has no remaining elements,
178            // and the predicate was false for all of the original iterator's elements.
179            final(self).obeys_prophetic_iter_laws() && !r ==> {
180                &&& final(self).remaining().len() == 0
181                &&& forall |i| 0 <= i < old(self).remaining().len() ==>
182                    f.ensures((#[trigger] old(self).remaining()[i],), false)
183            },
184            // If any returns true, then there is some element that satisfied the predicate,
185            // and all previous elements did not satisfy the predicate.
186            final(self).obeys_prophetic_iter_laws() && r ==> {
187                let idx = old(self).remaining().len() - final(self).remaining().len() - 1;
188                {
189                    // The satisfying element was consumed, so the remaining sequence strictly shrank
190                    &&& final(self).remaining().len() < old(self).remaining().len()
191                    &&& f.ensures((old(self).remaining()[idx],), true)
192                    &&& forall |i| 0 <= i < idx ==>
193                        f.ensures((#[trigger] old(self).remaining()[i],), false)
194                }
195            };
196}
197
198#[verifier::external_trait_specification]
199#[verifier::external_trait_extension(DoubleEndedIteratorSpec via DoubleEndedIteratorSpecImpl)]
200pub trait ExDoubleEndedIterator : Iterator {
201    type ExternalTraitSpecificationFor: DoubleEndedIterator;
202
203    // In the specs below, we write out the type parameters explicitly, rather than using the more concise form,
204    // e.g., `final(self).obeys_prophetic_iter_laws()`.  If we use the latter, then Rust elaborates it to
205    // `(&final(self)).obeys_prophetic_iter_laws()`, which means the type of the argument is `& &mut Self`,
206    // which means the type argument inferred for `obeys_prophetic_iter_laws` is `&mut Self`.
207    // This happens because of the existing Rust [trait impl](https://doc.rust-lang.org/std/iter/trait.Iterator.html#impl-Iterator-for-%26mut+I):
208    // ```
209    // impl<I> Iterator for &mut I
210    // where
211    //     I: Iterator + ?Sized,[4:21 AM]
212    // ```
213    fn next_back(&mut self) -> (ret: Option<<Self as core::iter::Iterator>::Item>)
214        ensures
215            // The iterator consistently obeys, completes, and decreases throughout its lifetime
216            <Self as IteratorSpec>::obeys_prophetic_iter_laws(final(self)) == <Self as IteratorSpec>::obeys_prophetic_iter_laws(old(self)),
217            <Self as IteratorSpec>::obeys_prophetic_iter_laws(final(self)) ==> <Self as IteratorSpec>::will_return_none(final(self)) == <Self as IteratorSpec>::will_return_none(old(self)),
218            <Self as IteratorSpec>::obeys_prophetic_iter_laws(final(self)) ==> (<Self as IteratorSpec>::decrease(old(self)) is Some <==> <Self as IteratorSpec>::decrease(final(self)) is Some),
219            // `next` pops the tail of the prophesized remaining(), or returns None
220            <Self as IteratorSpec>::obeys_prophetic_iter_laws(final(self)) ==>
221            ({
222                if <Self as IteratorSpec>::remaining(old(self)).len() > 0 {
223                    <Self as IteratorSpec>::remaining(final(self)) == <Self as IteratorSpec>::remaining(old(self)).drop_last()
224                        && ret == Some(<Self as IteratorSpec>::remaining(old(self)).last())
225                } else {
226                    <Self as IteratorSpec>::remaining(final(self)) == <Self as IteratorSpec>::remaining(old(self)) && ret == None && <Self as IteratorSpec>::will_return_none(final(self))
227                }
228            }),
229            // If the iterator isn't done yet, then it successfully decreases its metric (if any)
230            <Self as IteratorSpec>::obeys_prophetic_iter_laws(final(self)) && <Self as IteratorSpec>::remaining(old(self)).len() > 0 && <Self as IteratorSpec>::decrease(final(self)) is Some ==>
231                <Self as IteratorSpec>::decrease(old(self))->0 > <Self as IteratorSpec>::decrease(final(self))->0,
232    ;
233
234    /******* Mechanisms that support ergonomic `for` loops *********/
235
236    // If we can make a useful guess as to what the i-th value from the back will be, return it.
237    // Otherwise, return None.
238    spec fn peek_back(&self, index: int) -> Option<Self::Item>;
239}
240
241/********************************************************************************
242 * Definitions for `IntoIterator` and `FromIterator``
243 ********************************************************************************/
244#[verifier::external_trait_specification]
245pub trait ExIntoIterator {
246    type ExternalTraitSpecificationFor: core::iter::IntoIterator;
247}
248
249pub open spec fn iter_into_iter_spec<I: Iterator>(i: I) -> I {
250    i
251}
252
253#[verifier::when_used_as_spec(iter_into_iter_spec)]
254pub assume_specification<I: Iterator>[ <I as IntoIterator>::into_iter ](i: I) -> (r: I)
255    ensures
256        r == i,
257;
258
259// Uninterpreted function representing the sequence of elements that will be
260// produced by the iterator obtained from an IntoIterator value.
261// This avoids requiring IteratorSpec bounds in from_iter's ensures clause.
262pub uninterp spec fn into_iter_remaining<A, T>(iter: T) -> Seq<A>;
263
264// Connects into_iter_remaining to remaining() for types implementing Iterator + IteratorSpec.
265// This allows callers of from_iter to relate the result to the iterator's remaining elements.
266pub broadcast axiom fn axiom_from_iterator_ensures<A, I: Iterator<Item = A> + IteratorSpec>(iter: I)
267    ensures
268        #[trigger] into_iter_remaining::<A, I>(iter) == iter.remaining(),
269;
270
271#[verifier::external_trait_specification]
272#[verifier::external_trait_extension(FromIteratorSpec via FromIteratorSpecImpl)]
273pub trait ExFromIterator<A>: Sized {
274    type ExternalTraitSpecificationFor: FromIterator<A>;
275
276    spec fn from_iter_ensures(remaining: Seq<A>, s: Self) -> bool;
277
278    fn from_iter<T>(iter: T) -> (s: Self)
279       where T: IntoIterator<Item = A>
280        ensures
281            Self::from_iter_ensures(into_iter_remaining(iter), s),
282    ;
283}
284
285/********************************************************************************
286 * Definitions for `rev()`
287 ********************************************************************************/
288#[verifier::external_body]
289#[verifier::external_type_specification]
290#[verifier::reject_recursive_types(I)]
291pub struct ExRev<I>(Rev<I>);
292
293// Ghost accessor for the inner iterator
294pub uninterp spec fn rev_iter<I>(r: Rev<I>) -> I;
295
296// Spec version of Rev::new
297pub uninterp spec fn into_rev_spec<I>(i: I) -> Rev<I>;
298
299// Ideally, we would write this postcondition directly on the definition of
300// Iterator::rev above.  However, to do so, we would need to impose a trait
301// bound of `Self: DoubleEndedIteratorSpec`.  However, this introduces a cyclic
302// dependency, since DoubleEndedIteratorSpec depends on Iterator.  Hence,
303// we introduce a layer of indirection via this uninterp spec function.
304pub uninterp spec fn rev_post<I>(i: I, r: Rev<I>) -> bool;
305
306pub broadcast axiom fn rev_postcondition<I: DoubleEndedIteratorSpec>(i: I)
307    requires
308        i.obeys_prophetic_iter_laws(),
309        i.initial_value_relation(&i),
310        rev_post(i, into_rev_spec(i)),
311    ensures
312        {
313            let r = #[trigger] into_rev_spec(i);
314            &&& IteratorSpec::remaining(&r) == IteratorSpec::remaining(&i).reverse()
315            &&& IteratorSpec::will_return_none(&r) == i.will_return_none()
316            &&& IteratorSpec::decrease(&r) is Some == i.decrease() is Some
317            &&& IteratorSpec::initial_value_relation(&r, &r)
318        },
319;
320
321impl <I> IteratorSpecImpl for Rev<I>
322    where I: DoubleEndedIterator + DoubleEndedIteratorSpec {
323    open spec fn obeys_prophetic_iter_laws(&self) -> bool {
324        rev_iter(*self).obeys_prophetic_iter_laws()
325    }
326
327    #[verifier::prophetic]
328    closed spec fn remaining(&self) -> Seq<Self::Item> {
329        rev_iter(*self).remaining().reverse()
330    }
331
332    #[verifier::prophetic]
333    closed spec fn will_return_none(&self) -> bool {
334        rev_iter(*self).will_return_none()
335    }
336
337    #[verifier::prophetic]
338    open spec fn initial_value_relation(&self, init: &Self) -> bool {
339        &&& IteratorSpec::remaining(init) == IteratorSpec::remaining(self)
340        &&& rev_iter(*self).initial_value_relation(&rev_iter(*init))
341    }
342
343    closed spec fn decrease(&self) -> Option<nat> {
344        rev_iter(*self).decrease()
345    }
346
347    open spec fn peek(&self, index: int) -> Option<Self::Item> {
348        rev_iter(*self).peek_back(index)
349    }
350}
351
352impl <I> DoubleEndedIteratorSpecImpl for Rev<I>
353    where I: DoubleEndedIterator + IteratorSpec {
354
355    open spec fn peek_back(&self, index: int) -> Option<Self::Item> {
356        rev_iter(*self).peek(index)
357    }
358}
359
360// Forwarding spec impl for the Rust-supplied blanket `impl<I> Iterator for &mut I`.
361// Without this, bare method-call syntax on a `i: &mut I` receiver (e.g. `i.remaining()`)
362// resolves to these (otherwise uninterpreted) functions on `&mut I` rather than on `I`,
363// silently disconnecting clients from `I`'s actual specs.
364impl <I> IteratorSpecImpl for &mut I
365    where I: Iterator {
366    open spec fn obeys_prophetic_iter_laws(&self) -> bool {
367        <I as IteratorSpec>::obeys_prophetic_iter_laws(*self)
368    }
369
370    #[verifier::prophetic]
371    open spec fn remaining(&self) -> Seq<Self::Item> {
372        <I as IteratorSpec>::remaining(*self)
373    }
374
375    #[verifier::prophetic]
376    open spec fn will_return_none(&self) -> bool {
377        <I as IteratorSpec>::will_return_none(*self)
378    }
379
380    #[verifier::prophetic]
381    open spec fn initial_value_relation(&self, init: &Self) -> bool {
382        <I as IteratorSpec>::initial_value_relation(*self, &**init)
383    }
384
385    open spec fn decrease(&self) -> Option<nat> {
386        <I as IteratorSpec>::decrease(*self)
387    }
388
389    open spec fn peek(&self, index: int) -> Option<Self::Item> {
390        <I as IteratorSpec>::peek(*self, index)
391    }
392}
393
394/********************************************************************************
395 * Defines a convenient wrapper type that bundles state and invariants needed
396 * for ergonomic for-loop support.
397 ********************************************************************************/
398
399pub struct VerusForLoopWrapper<'a, I: Iterator> {
400    pub index: Ghost<int>,
401    pub snapshot: Ghost<I>,
402    pub init: Ghost<Option<&'a I>>,
403    pub iter: I,
404    pub history: Ghost<Seq<I::Item>>,
405}
406
407impl <'a, I: Iterator> VerusForLoopWrapper<'a, I> {
408    #[verifier::prophetic]
409    pub open spec fn seq(self) -> Seq<I::Item> {
410        self.snapshot@.remaining()
411    }
412
413    // Keep the interface for history and seq the same
414    pub open spec fn history(self) -> Seq<I::Item> {
415        self.history@
416    }
417
418    pub open spec fn index(self) -> int {
419        self.index@
420    }
421
422    /// These properties help maintain the properties in wf,
423    /// but they don't need to be exposed to the client
424    #[verifier::prophetic]
425    pub closed spec fn wf_inner(self) -> bool {
426        &&& self.iter.remaining().len() == self.seq().len() - self.index()
427        &&& forall |i| 0 <= i < self.iter.remaining().len() ==> #[trigger] self.iter.remaining()[i] == self.seq()[self.index() + i]
428        &&& self.iter.will_return_none() ==> self.snapshot@.will_return_none()
429    }
430
431    /// These properties are needed for the client code to verify
432    #[verifier::prophetic]
433    pub open spec fn wf(self) -> bool {
434        &&& 0 <= self.index() <= self.seq().len()
435        &&& self.init@ matches Some(init) ==> self.snapshot@.initial_value_relation(init)
436        &&& self.wf_inner()
437        &&& self.iter.obeys_prophetic_iter_laws() ==> {
438                &&& self.history@.len() == self.index()
439                &&& forall |i| 0 <= i < self.index() ==> #[trigger] self.history@[i] == self.seq()[i]
440            }
441    }
442
443    /// Bundle the real iterator with its ghost state and loop invariants
444    pub fn new(iter: I, init: Ghost<Option<&'a I>>) -> (s: Self)
445        requires
446            init@ matches Some(i) ==> iter.initial_value_relation(i),
447        ensures
448            s.index == 0,
449            s.snapshot == iter,
450            s.init == init,
451            s.iter == iter,
452            s.history@ == Seq::<I::Item>::empty(),
453            s.wf(),
454    {
455        broadcast use axiom_seq_empty;
456        VerusForLoopWrapper {
457            index: Ghost(0),
458            snapshot: Ghost(iter),
459            init: init,
460            iter,
461            history: Ghost(Seq::empty()),
462        }
463    }
464
465    /// Advance the underlying (real) iterator and prove
466    /// that the loop invariants are preserved.
467    pub fn next(&mut self) -> (ret: Option<I::Item>)
468        requires
469            old(self).wf(),
470        ensures
471            final(self).seq() == old(self).seq(),
472            final(self).index() == old(self).index() + if ret is Some { 1int } else { 0 },
473            final(self).snapshot == old(self).snapshot,
474            final(self).init == old(self).init,
475            final(self).iter.obeys_prophetic_iter_laws() ==> final(self).wf(),
476            final(self).iter.obeys_prophetic_iter_laws() && ret is None ==>
477                final(self).snapshot@.will_return_none() && final(self).index() == final(self).seq().len(),
478            final(self).iter.obeys_prophetic_iter_laws() ==> (ret matches Some(r) ==>
479                r == old(self).seq()[old(self).index()]),
480            // History updates always hold
481            ret matches Some(i) ==> final(self).history@ == old(self).history@.push(i),
482            ret is None ==> final(self).history@ == old(self).history@,
483            // TODO: Uncomment this line to replace everything below, once general mutable refs are supported
484            //call_ensures(I::next, (old(self).iter,), ret),
485            final(self).iter.obeys_prophetic_iter_laws() == old(self).iter.obeys_prophetic_iter_laws(),
486            final(self).iter.obeys_prophetic_iter_laws() ==> final(self).iter.will_return_none() == old(self).iter.will_return_none(),
487            final(self).iter.obeys_prophetic_iter_laws() ==> (old(self).iter.decrease() is Some <==> final(self).iter.decrease() is Some),
488            final(self).iter.obeys_prophetic_iter_laws() ==>
489            ({
490                if old(self).iter.remaining().len() > 0 {
491                    &&& final(self).iter.remaining() == old(self).iter.remaining().drop_first()
492                    &&& ret == Some(old(self).iter.remaining()[0])
493                } else {
494                    final(self).iter.remaining() == old(self).iter.remaining() && ret == None && final(self).iter.will_return_none()
495                }
496            }),
497            final(self).iter.obeys_prophetic_iter_laws() && old(self).iter.remaining().len() > 0 && final(self).iter.decrease() is Some ==>
498                decreases_to!(old(self).iter.decrease()->0 => final(self).iter.decrease()->0),
499    {
500        let ghost old_history = self.history@;
501        let ret = self.iter.next();
502        if ret.is_some() {
503            self.history = Ghost(old_history.push(ret->0));
504        }
505        proof {
506            broadcast use group_seq_axioms;
507            if ret.is_some() {
508                self.index@ = self.index@ + 1;
509            }
510        }
511        ret
512    }
513}
514
515// Artificial function used when we desguar a for loop.
516// It helps bring the definition of `peek` into scope,
517// resulting in better automation for some proofs.
518pub open spec fn trigger_peek_implications<T>(x: T) -> bool { true }
519
520/********************************************************************************
521 * Definitions for the Step trait
522 ********************************************************************************/
523#[verifier::external_trait_specification]
524#[verifier::external_trait_extension(StepSpec via StepSpecImpl)]
525pub trait ExIterStep: Clone + PartialOrd + Sized {
526    type ExternalTraitSpecificationFor: core::iter::Step;
527
528    // REVIEW: it would be nice to be able to use SpecOrd::spec_lt (not yet supported)
529    // TODO: We should now be able to use cmp_spec or partial_cmp_spec here.
530    spec fn spec_is_lt(self, other: Self) -> bool;
531
532    spec fn spec_steps_between(self, end: Self) -> Option<usize>;
533
534    spec fn spec_steps_between_int(self, end: Self) -> int;
535
536    spec fn spec_forward_checked(self, count: usize) -> Option<Self>;
537
538    spec fn spec_forward_checked_int(self, count: int) -> Option<Self>;
539
540    spec fn spec_backward_checked(self, count: usize) -> Option<Self>;
541
542    spec fn spec_backward_checked_int(self, count: int) -> Option<Self>;
543}
544
545
546/********************************************************************************
547 * Collect our broadcast definitions
548 ********************************************************************************/
549
550pub broadcast group group_iter_axioms {
551    rev_postcondition,
552}
553
554} // verus!