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}