creusot_contracts/logic/
seq.rs

1use crate::{
2    ghost::Plain,
3    logic::{Mapping, ops::IndexLogic},
4    *,
5};
6
7/// A type of sequence usable in pearlite and `ghost!` blocks.
8///
9/// # Logic
10///
11/// This type is (in particular) the logical representation of a [`Vec`]. This can be
12/// accessed via its [view](crate::View) (The `@` operator).
13///
14/// ```rust,creusot
15/// # use creusot_contracts::*;
16/// #[logic]
17/// fn get_model<T>(v: Vec<T>) -> Seq<T> {
18///     pearlite!(v@)
19/// }
20/// ```
21///
22/// # Ghost
23///
24/// Since [`Vec`] have finite capacity, this could cause some issues in ghost code:
25/// ```rust,creusot,compile_fail
26/// ghost! {
27///     let mut v = Vec::new();
28///     for _ in 0..=usize::MAX as u128 + 1 {
29///         v.push(0); // cannot fail, since we are in a ghost block
30///     }
31///     proof_assert!(v@.len() <= usize::MAX@); // by definition
32///     proof_assert!(v@.len() > usize::MAX@); // uh-oh
33/// }
34/// ```
35///
36/// This type is designed for this use-case, with no restriction on the capacity.
37#[builtin("seq.Seq.seq")]
38pub struct Seq<T>(std::marker::PhantomData<T>);
39
40/// Logical definitions
41impl<T> Seq<T> {
42    /// Returns the empty sequence.
43    #[logic]
44    #[builtin("seq.Seq.empty", ascription)]
45    pub fn empty() -> Self {
46        dead
47    }
48
49    /// Create a new sequence in pearlite.
50    ///
51    /// The new sequence will be of length `n`, and will contain `mapping[i]` at index `i`.
52    ///
53    /// # Example
54    ///
55    /// ```
56    /// # use creusot_contracts::*;
57    /// let s = snapshot!(Seq::create(5, |i| i + 1));
58    /// proof_assert!(s.len() == 5);
59    /// proof_assert!(forall<i> 0 <= i && i < 5 ==> s[i] == i + 1);
60    /// ```
61    #[logic]
62    #[builtin("seq.Seq.create")]
63    pub fn create(n: Int, mapping: Mapping<Int, T>) -> Self {
64        let _ = n;
65        let _ = mapping;
66        dead
67    }
68
69    /// Returns the value at index `ix`.
70    ///
71    /// If `ix` is out of bounds, return `None`.
72    #[logic(open)]
73    pub fn get(self, ix: Int) -> Option<T> {
74        if 0 <= ix && ix < self.len() { Some(self.index_logic(ix)) } else { None }
75    }
76
77    /// Returns the value at index `ix`.
78    ///
79    /// If `ix` is out of bounds, the returned value is meaningless.
80    ///
81    /// You should prefer using the indexing operator `s[ix]`.
82    ///
83    /// # Example
84    ///
85    /// ```
86    /// # use creusot_contracts::*;
87    /// let s = snapshot!(Seq::singleton(2));
88    /// proof_assert!(s.index_logic_unsized(0) == 2);
89    /// proof_assert!(s[0] == 2); // prefer this
90    /// ```
91    #[logic]
92    #[builtin("seq.Seq.get")]
93    pub fn index_logic_unsized(self, ix: Int) -> Box<T> {
94        let _ = ix;
95        dead
96    }
97
98    /// Returns the subsequence between indices `start` and `end`.
99    ///
100    /// If either `start` or `end` are out of bounds, the result is meaningless.
101    ///
102    /// # Example
103    ///
104    /// ```
105    /// # use creusot_contracts::*;
106    /// let subs = snapshot! {
107    ///     let s: Seq<Int> = Seq::create(10, |i| i);
108    ///     s.subsequence(2, 5)
109    /// };
110    /// proof_assert!(subs.len() == 3);
111    /// proof_assert!(subs[0] == 2 && subs[1] == 3 && subs[2] == 4);
112    /// ```
113    #[logic]
114    #[builtin("seq.Seq.([..])")]
115    pub fn subsequence(self, start: Int, end: Int) -> Self {
116        let _ = start;
117        let _ = end;
118        dead
119    }
120
121    /// Create a sequence containing one element.
122    ///
123    /// # Example
124    ///
125    /// ```
126    /// # use creusot_contracts::*;
127    /// let s = snapshot!(Seq::singleton(42));
128    /// proof_assert!(s.len() == 1);
129    /// proof_assert!(s[0] == 42);
130    /// ```
131    #[logic]
132    #[builtin("seq.Seq.singleton")]
133    pub fn singleton(value: T) -> Self {
134        let _ = value;
135        dead
136    }
137
138    /// Returns the sequence without its first element.
139    ///
140    /// If the sequence is empty, the result is meaningless.
141    ///
142    /// # Example
143    ///
144    /// ```
145    /// # use creusot_contracts::*;
146    /// let s = snapshot!(Seq::singleton(5).push_back(10).push_back(15));
147    /// proof_assert!(s.tail() == Seq::singleton(10).push_back(15));
148    /// proof_assert!(s.tail().tail() == Seq::singleton(15));
149    /// proof_assert!(s.tail().tail().tail() == Seq::empty());
150    /// ```
151    #[logic(open)]
152    pub fn tail(self) -> Self {
153        self.subsequence(1, self.len())
154    }
155
156    /// Returns the number of elements in the sequence, also referred to as its 'length'.
157    ///
158    /// # Example
159    ///
160    /// ```
161    /// # use creusot_contracts::*;
162    /// #[requires(v@.len() > 0)]
163    /// fn f<T>(v: Vec<T>) { /* ... */ }
164    /// ```
165    #[logic]
166    #[builtin("seq.Seq.length")]
167    pub fn len(self) -> Int {
168        dead
169    }
170
171    /// Returns a new sequence, where the element at index `ix` has been replaced by `x`.
172    ///
173    /// If `ix` is out of bounds, the result is meaningless.
174    ///
175    /// # Example
176    ///
177    /// ```
178    /// # use creusot_contracts::*;
179    /// let s = snapshot!(Seq::create(2, |_| 0));
180    /// let s2 = snapshot!(s.set(1, 3));
181    /// proof_assert!(s2[0] == 0);
182    /// proof_assert!(s2[1] == 3);
183    /// ```
184    #[logic]
185    #[builtin("seq.Seq.set")]
186    pub fn set(self, ix: Int, x: T) -> Self {
187        let _ = ix;
188        let _ = x;
189        dead
190    }
191
192    /// Extensional equality
193    ///
194    /// Returns `true` if `self` and `other` have the same length, and contain the same
195    /// elements at the same indices.
196    ///
197    /// This is in fact equivalent with normal equality.
198    #[logic]
199    #[builtin("seq.Seq.(==)")]
200    pub fn ext_eq(self, other: Self) -> bool {
201        let _ = other;
202        dead
203    }
204
205    // internal wrapper to match the order of arguments of Seq.cons
206    #[doc(hidden)]
207    #[logic]
208    #[builtin("seq.Seq.cons")]
209    pub fn cons(_: T, _: Self) -> Self {
210        dead
211    }
212
213    /// Returns a new sequence, where `x` has been prepended to `self`.
214    ///
215    /// # Example
216    ///
217    /// ```
218    /// let s = snapshot!(Seq::singleton(1));
219    /// let s2 = snapshot!(s.push_front(2));
220    /// proof_assert!(s2[0] == 2);
221    /// proof_assert!(s2[1] == 1);
222    /// ```
223    #[logic(open, inline)]
224    pub fn push_front(self, x: T) -> Self {
225        Self::cons(x, self)
226    }
227
228    /// Returns a new sequence, where `x` has been appended to `self`.
229    ///
230    /// # Example
231    ///
232    /// ```
233    /// let s = snapshot!(Seq::singleton(1));
234    /// let s2 = snapshot!(s.push_back(2));
235    /// proof_assert!(s2[0] == 1);
236    /// proof_assert!(s2[1] == 2);
237    /// ```
238    #[logic]
239    #[builtin("seq.Seq.snoc")]
240    pub fn push_back(self, x: T) -> Self {
241        let _ = x;
242        dead
243    }
244
245    /// Returns a new sequence, made of the concatenation of `self` and `other`.
246    ///
247    /// # Example
248    ///
249    /// ```
250    /// # use creusot_contracts::*;
251    /// let s1 = snapshot!(Seq::singleton(1));
252    /// let s2 = snapshot!(Seq::create(2, |i| i));
253    /// let s = snapshot!(s1.concat(s2));
254    /// proof_assert!(s[0] == 1);
255    /// proof_assert!(s[1] == 0);
256    /// proof_assert!(s[2] == 1);
257    /// ```
258    #[logic]
259    #[builtin("seq.Seq.(++)")]
260    pub fn concat(self, other: Self) -> Self {
261        let _ = other;
262        dead
263    }
264
265    #[logic(open)]
266    #[variant(self.len())]
267    pub fn flat_map<U>(self, other: Mapping<T, Seq<U>>) -> Seq<U> {
268        if self.len() == 0 {
269            Seq::empty()
270        } else {
271            other.get(*self.index_logic_unsized(0)).concat(self.tail().flat_map(other))
272        }
273    }
274
275    /// Returns a new sequence, which is `self` in reverse order.
276    ///
277    /// # Example
278    ///
279    /// ```
280    /// # use creusot_contracts::*;
281    /// let s = snapshot!(Seq::create(3, |i| i));
282    /// let s2 = snapshot!(s.reverse());
283    /// proof_assert!(s2[0] == 2);
284    /// proof_assert!(s2[1] == 1);
285    /// proof_assert!(s2[2] == 0);
286    /// ```
287    #[logic]
288    #[builtin("seq.Reverse.reverse")]
289    pub fn reverse(self) -> Self {
290        dead
291    }
292
293    /// Returns `true` if `other` is a permutation of `self`.
294    #[logic(open)]
295    pub fn permutation_of(self, other: Self) -> bool {
296        self.permut(other, 0, self.len())
297    }
298
299    /// Returns `true` if:
300    /// - `self` and `other` have the same length
301    /// - `start` and `end` are in bounds (between `0` and `self.len()` included)
302    /// - Every element of `self` between `start` (included) and `end` (excluded) can
303    ///   also be found in `other` between `start` and `end`, and vice-versa
304    #[logic]
305    #[builtin("seq.Permut.permut")]
306    pub fn permut(self, other: Self, start: Int, end: Int) -> bool {
307        let _ = other;
308        let _ = start;
309        let _ = end;
310        dead
311    }
312
313    /// Returns `true` if:
314    /// - `self` and `other` have the same length
315    /// - `i` and `j` are in bounds (between `0` and `self.len()` excluded)
316    /// - `other` is equal to `self` where the elements at `i` and `j` are swapped
317    #[logic]
318    #[builtin("seq.Permut.exchange")]
319    pub fn exchange(self, other: Self, i: Int, j: Int) -> bool {
320        let _ = other;
321        let _ = i;
322        let _ = j;
323        dead
324    }
325
326    /// Returns `true` if there is an index `i` such that `self[i] == x`.
327    #[logic(open)]
328    pub fn contains(self, x: T) -> bool {
329        pearlite! { exists<i> 0 <= i &&  i < self.len() && self[i] == x }
330    }
331
332    /// Returns `true` if `self` is sorted between `start` and `end`.
333    #[logic(open)]
334    pub fn sorted_range(self, start: Int, end: Int) -> bool
335    where
336        T: OrdLogic,
337    {
338        pearlite! {
339            forall<i, j> start <= i && i <= j && j < end ==> self[i] <= self[j]
340        }
341    }
342
343    /// Returns `true` if `self` is sorted.
344    #[logic(open)]
345    pub fn sorted(self) -> bool
346    where
347        T: OrdLogic,
348    {
349        self.sorted_range(0, self.len())
350    }
351
352    #[logic(open)]
353    #[ensures(forall<a: Seq<T>, b: Seq<T>, x>
354        a.concat(b).contains(x) == a.contains(x) || b.contains(x))]
355    pub fn concat_contains() {}
356}
357
358impl<T> Seq<Seq<T>> {
359    #[logic(open)]
360    #[variant(self.len())]
361    pub fn flatten(self) -> Seq<T> {
362        if self.len() == 0 {
363            Seq::empty()
364        } else {
365            self.index_logic_unsized(0).concat(self.tail().flatten())
366        }
367    }
368}
369
370impl<T> Seq<&T> {
371    /// Convert `Seq<&T>` to `Seq<T>`.
372    ///
373    /// This is simply a utility method, because `&T` is equivalent to `T` in pearlite.
374    #[logic]
375    #[builtin("identity")]
376    pub fn to_owned_seq(self) -> Seq<T> {
377        dead
378    }
379}
380
381impl<T> IndexLogic<Int> for Seq<T> {
382    type Item = T;
383
384    #[logic]
385    #[builtin("seq.Seq.get")]
386    fn index_logic(self, _: Int) -> Self::Item {
387        dead
388    }
389}
390
391/// Ghost definitions
392impl<T> Seq<T> {
393    /// Constructs a new, empty `Seq<T>`.
394    ///
395    /// This can only be manipulated in the ghost world, and as such is wrapped in [`Ghost`].
396    ///
397    /// # Example
398    ///
399    /// ```rust,creusot
400    /// use creusot_contracts::{proof_assert, Seq};
401    /// let ghost_seq = Seq::<i32>::new();
402    /// proof_assert!(seq == Seq::create());
403    /// ```
404    #[trusted]
405    #[check(ghost)]
406    #[ensures(*result == Self::empty())]
407    #[allow(unreachable_code)]
408    pub fn new() -> Ghost<Self> {
409        Ghost::conjure()
410    }
411
412    /// Returns the number of elements in the sequence, also referred to as its 'length'.
413    ///
414    /// If you need to get the length in pearlite, consider using [`len`](Self::len).
415    ///
416    /// # Example
417    /// ```rust,creusot
418    /// use creusot_contracts::{ghost, proof_assert, Seq};
419    ///
420    /// let mut s = Seq::new();
421    /// ghost! {
422    ///     s.push_back_ghost(1);
423    ///     s.push_back_ghost(2);
424    ///     s.push_back_ghost(3);
425    ///     let len = s.len_ghost();
426    ///     proof_assert!(len == 3);
427    /// };
428    /// ```
429    #[trusted]
430    #[check(ghost)]
431    #[ensures(result == self.len())]
432    pub fn len_ghost(&self) -> Int {
433        panic!()
434    }
435
436    /// Returns `true` if the sequence is empty.
437    ///
438    /// # Example
439    ///
440    /// ```rust,creusot
441    /// use creusot_contracts::*;
442    /// #[check(ghost)]
443    /// #[requires(s.len() == 0)]
444    /// pub fn foo(mut s: Seq<i32>) {
445    ///     assert!(s.is_empty_ghost());
446    ///     s.push_back_ghost(1i32);
447    ///     assert!(!s.is_empty_ghost());
448    /// }
449    /// ghost! {
450    ///     foo(Seq::new().into_inner())
451    /// };
452    /// ```
453    #[trusted]
454    #[check(ghost)]
455    #[ensures(result == (self.len() == 0))]
456    pub fn is_empty_ghost(&self) -> bool {
457        panic!()
458    }
459
460    /// Appends an element to the front of a collection.
461    ///
462    /// # Example
463    /// ```rust,creusot
464    /// use creusot_contracts::{ghost, proof_assert, Seq};
465    ///
466    /// let mut s = Seq::new();
467    /// ghost! {
468    ///     s.push_front_ghost(1);
469    ///     s.push_front_ghost(2);
470    ///     s.push_front_ghost(3);
471    ///     proof_assert!(s[0] == 3i32 && s[1] == 2i32 && s[2] == 1i32);
472    /// };
473    /// ```
474    #[trusted]
475    #[check(ghost)]
476    #[ensures(^self == self.push_front(x))]
477    pub fn push_front_ghost(&mut self, x: T) {
478        let _ = x;
479        panic!()
480    }
481
482    /// Appends an element to the back of a collection.
483    ///
484    /// # Example
485    /// ```rust,creusot
486    /// use creusot_contracts::{ghost, proof_assert, Seq};
487    ///
488    /// let mut s = Seq::new();
489    /// ghost! {
490    ///     s.push_back_ghost(1);
491    ///     s.push_back_ghost(2);
492    ///     s.push_back_ghost(3);
493    ///     proof_assert!(s[0] == 1i32 && s[1] == 2i32 && s[2] == 3i32);
494    /// };
495    /// ```
496    #[trusted]
497    #[check(ghost)]
498    #[ensures(^self == self.push_back(x))]
499    pub fn push_back_ghost(&mut self, x: T) {
500        let _ = x;
501        panic!()
502    }
503
504    /// Returns a reference to an element at `index` or `None` if `index` is out of bounds.
505    ///
506    /// # Example
507    /// ```rust,creusot
508    /// use creusot_contracts::{ghost, Int, proof_assert, Seq};
509    ///
510    /// let mut s = Seq::new();
511    /// ghost! {
512    ///     s.push_back_ghost(10);
513    ///     s.push_back_ghost(40);
514    ///     s.push_back_ghost(30);
515    ///     let get1 = s.get_ghost(1int);
516    ///     let get2 = s.get_ghost(3int);
517    ///     proof_assert!(get1 == Some(&40i32));
518    ///     proof_assert!(get2 == None);
519    /// };
520    /// ```
521    #[trusted]
522    #[check(ghost)]
523    #[ensures(match self.get(index) {
524        None => result == None,
525        Some(v) => result == Some(&v),
526    })]
527    pub fn get_ghost(&self, index: Int) -> Option<&T> {
528        let _ = index;
529        panic!()
530    }
531
532    /// Returns a mutable reference to an element at `index` or `None` if `index` is out of bounds.
533    ///
534    /// # Example
535    /// ```rust,creusot
536    /// use creusot_contracts::{ghost, Int, proof_assert, Seq};
537    ///
538    /// let mut s = Seq::new();
539    ///
540    /// ghost! {
541    ///     s.push_back_ghost(0);
542    ///     s.push_back_ghost(1);
543    ///     s.push_back_ghost(2);
544    ///     if let Some(elem) = s.get_mut_ghost(1int) {
545    ///         *elem = 42;
546    ///     }
547    ///     proof_assert!(s[0] == 0i32 && s[1] == 42i32 && s[2] == 2i32);
548    /// };
549    /// ```
550    #[trusted]
551    #[check(ghost)]
552    #[ensures(match result {
553        None => self.get(index) == None && *self == ^self,
554        Some(r) => self.get(index) == Some(*r) && ^r == (^self)[index],
555    })]
556    #[ensures(forall<i> i != index ==> (*self).get(i) == (^self).get(i))]
557    #[ensures((*self).len() == (^self).len())]
558    pub fn get_mut_ghost(&mut self, index: Int) -> Option<&mut T> {
559        let _ = index;
560        panic!()
561    }
562
563    /// Removes the last element from a vector and returns it, or `None` if it is empty.
564    ///
565    /// # Example
566    /// ```rust,creusot
567    /// use creusot_contracts::{ghost, proof_assert, Seq};
568    ///
569    /// let mut s = Seq::new();
570    /// ghost! {
571    ///     s.push_back_ghost(1);
572    ///     s.push_back_ghost(2);
573    ///     s.push_back_ghost(3);
574    ///     let popped = s.pop_back_ghost();
575    ///     proof_assert!(popped == Some(3i32));
576    ///     proof_assert!(s[0] == 1i32 && s[1] == 2i32);
577    /// };
578    /// ```
579    #[trusted]
580    #[check(ghost)]
581    #[ensures(match result {
582        None => *self == Seq::empty() && *self == ^self,
583        Some(r) => *self == (^self).push_back(r)
584    })]
585    pub fn pop_back_ghost(&mut self) -> Option<T> {
586        panic!()
587    }
588
589    /// Removes the first element from a vector and returns it, or `None` if it is empty.
590    ///
591    /// # Example
592    /// ```rust,creusot
593    /// use creusot_contracts::{ghost, proof_assert, Seq};
594    ///
595    /// let mut s = Seq::new();
596    /// ghost! {
597    ///     s.push_back_ghost(1);
598    ///     s.push_back_ghost(2);
599    ///     s.push_back_ghost(3);
600    ///     let popped = s.pop_front_ghost();
601    ///     proof_assert!(popped == Some(1i32));
602    ///     proof_assert!(s[0] == 2i32 && s[1] == 3i32);
603    /// };
604    /// ```
605    #[trusted]
606    #[check(ghost)]
607    #[ensures(match result {
608        None => *self == Seq::empty() && *self == ^self,
609        Some(r) => *self == (^self).push_front(r)
610    })]
611    pub fn pop_front_ghost(&mut self) -> Option<T> {
612        panic!()
613    }
614
615    /// Clears the sequence, removing all values.
616    ///
617    /// # Example
618    /// ```rust,creusot
619    /// use creusot_contracts::{ghost, proof_assert, Seq};
620    ///
621    /// let mut s = Seq::new();
622    /// ghost! {
623    ///     s.push_back_ghost(1);
624    ///     s.push_back_ghost(2);
625    ///     s.push_back_ghost(3);
626    ///     s.clear_ghost();
627    ///     proof_assert!(s == Seq::empty());
628    /// };
629    /// ```
630    #[trusted]
631    #[check(ghost)]
632    #[ensures(^self == Self::empty())]
633    pub fn clear_ghost(&mut self) {}
634}
635
636// Having `Copy` guarantees that the operation is pure, even if we decide to change the definition of `Clone`.
637impl<T: Clone + Copy> Clone for Seq<T> {
638    #[trusted]
639    #[check(ghost)]
640    #[ensures(result == *self)]
641    fn clone(&self) -> Self {
642        *self
643    }
644}
645
646impl<T: Copy> Copy for Seq<T> {}
647#[trusted]
648impl<T: Plain> Plain for Seq<T> {}
649
650impl<T> Invariant for Seq<T> {
651    #[logic(open, prophetic, inline)]
652    #[creusot::trusted_ignore_structural_inv]
653    #[creusot::trusted_is_tyinv_trivial_if_param_trivial]
654    fn invariant(self) -> bool {
655        pearlite! { forall<i> 0 <= i && i < self.len() ==> inv(self.index_logic_unsized(i)) }
656    }
657}
658
659#[logic(open)]
660#[ensures(forall<x: A, f: Mapping<A, Seq<B>>> Seq::singleton(x).flat_map(f) == f.get(x))]
661pub fn flat_map_singleton<A, B>() {}
662
663#[logic(open)]
664#[ensures(forall<x: A, f: Mapping<A, Seq<B>>> xs.push_back(x).flat_map(f) == xs.flat_map(f).concat(f.get(x)))]
665#[variant(xs.len())]
666pub fn flat_map_push_back<A, B>(xs: Seq<A>) {
667    if xs.len() > 0 {
668        flat_map_push_back::<A, B>(xs.tail());
669        proof_assert! { forall<x: A> xs.tail().push_back(x) == xs.push_back(x).tail() }
670    }
671}
672
673/// A sequence literal `seq![a, b, c]`.
674#[macro_export]
675macro_rules! seq {
676    ($($items:expr),+) => { creusot_contracts::__stubs::seq_literal(&[$($items),+]) };
677    () => { Seq::empty() };
678}