Skip to main content

vstd/std_specs/
iter.rs

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