pub struct Seq<T>(/* private fields */);Expand description
A type of sequence usable in pearlite and ghost! blocks.
§Logic
This type is (in particular) the logical representation of a Vec. This can be
accessed via its view (The @ operator).
#[logic]
fn get_model<T>(v: Vec<T>) -> Seq<T> {
pearlite!(v@)
}§Ghost
Since Vec have finite capacity, this could cause some issues in ghost code:
ghost! {
let mut v = Vec::new();
for _ in 0..=usize::MAX as u128 + 1 {
v.push(0); // cannot fail, since we are in a ghost block
}
proof_assert!(v@.len() <= usize::MAX@); // by definition
proof_assert!(v@.len() > usize::MAX@); // uh-oh
}This type is designed for this use-case, with no restriction on the capacity.
Implementations§
Source§impl<T> Seq<T>
Logical definitions
impl<T> Seq<T>
Logical definitions
Sourcepub fn create(n: Int, mapping: Mapping<Int, T>) -> Self
pub fn create(n: Int, mapping: Mapping<Int, T>) -> Self
Create a new sequence in pearlite.
The new sequence will be of length n, and will contain mapping[i] at index i.
§Example
let s = snapshot!(Seq::create(5, |i| i + 1));
proof_assert!(s.len() == 5);
proof_assert!(forall<i> 0 <= i && i < 5 ==> s[i] == i + 1);⚠
Sourcepub fn get(self, ix: Int) -> Option<T>
pub fn get(self, ix: Int) -> Option<T>
Returns the value at index ix.
If ix is out of bounds, return None.
(open)
if 0 <= ix && ix < self.len() { Some(self.index_logic(ix)) } else { None }Sourcepub fn index_logic_unsized(self, ix: Int) -> Box<T>
pub fn index_logic_unsized(self, ix: Int) -> Box<T>
Returns the value at index ix.
If ix is out of bounds, the returned value is meaningless.
You should prefer using the indexing operator s[ix].
§Example
let s = snapshot!(Seq::singleton(2));
proof_assert!(s.index_logic_unsized(0) == 2);
proof_assert!(s[0] == 2); // prefer this⚠
Sourcepub fn subsequence(self, start: Int, end: Int) -> Self
pub fn subsequence(self, start: Int, end: Int) -> Self
Returns the subsequence between indices start and end.
If either start or end are out of bounds, the result is meaningless.
§Example
let subs = snapshot! {
let s: Seq<Int> = Seq::create(10, |i| i);
s.subsequence(2, 5)
};
proof_assert!(subs.len() == 3);
proof_assert!(subs[0] == 2 && subs[1] == 3 && subs[2] == 4);⚠
Sourcepub fn singleton(value: T) -> Self
pub fn singleton(value: T) -> Self
Create a sequence containing one element.
§Example
let s = snapshot!(Seq::singleton(42));
proof_assert!(s.len() == 1);
proof_assert!(s[0] == 42);⚠
Sourcepub fn tail(self) -> Self
pub fn tail(self) -> Self
Returns the sequence without its first element.
If the sequence is empty, the result is meaningless.
§Example
let s = snapshot!(seq![5, 10, 15]);
proof_assert!(s.tail() == seq![10, 15]);
proof_assert!(s.tail().tail() == Seq::singleton(15));
proof_assert!(s.tail().tail().tail() == Seq::empty());(open)
self.subsequence(1, self.len())Sourcepub fn pop_front(self) -> Self
pub fn pop_front(self) -> Self
Alias for Self::tail.
(open)
self.tail()Sourcepub fn pop_back(self) -> Self
pub fn pop_back(self) -> Self
Returns the sequence without its last element.
If the sequence is empty, the result is meaningless.
§Example
let s = snapshot!(seq![5, 10, 15]);
proof_assert!(s.pop_back() == seq![5, 10]);
proof_assert!(s.pop_back().pop_back() == Seq::singleton(5));
proof_assert!(s.pop_back().pop_back().pop_back() == Seq::empty());(open)
self.subsequence(0, self.len() - 1)Sourcepub fn len(self) -> Int
pub fn len(self) -> Int
Returns the number of elements in the sequence, also referred to as its ‘length’.
§Example
#[requires(v@.len() > 0)]
fn f<T>(v: Vec<T>) { /* ... */ }⚠
Sourcepub fn set(self, ix: Int, x: T) -> Self
pub fn set(self, ix: Int, x: T) -> Self
Returns a new sequence, where the element at index ix has been replaced by x.
If ix is out of bounds, the result is meaningless.
§Example
let s = snapshot!(Seq::create(2, |_| 0));
let s2 = snapshot!(s.set(1, 3));
proof_assert!(s2[0] == 0);
proof_assert!(s2[1] == 3);⚠
Sourcepub fn ext_eq(self, other: Self) -> bool
pub fn ext_eq(self, other: Self) -> bool
Extensional equality
Returns true if self and other have the same length, and contain the same
elements at the same indices.
This is in fact equivalent with normal equality.
⚠
Sourcepub fn push_front(self, x: T) -> Self
pub fn push_front(self, x: T) -> Self
Returns a new sequence, where x has been prepended to self.
§Example
let s = snapshot!(Seq::singleton(1));
let s2 = snapshot!(s.push_front(2));
proof_assert!(s2[0] == 2);
proof_assert!(s2[1] == 1);(open, inline)
Self::cons(x, self)Sourcepub fn push_back(self, x: T) -> Self
pub fn push_back(self, x: T) -> Self
Returns a new sequence, where x has been appended to self.
§Example
let s = snapshot!(Seq::singleton(1));
let s2 = snapshot!(s.push_back(2));
proof_assert!(s2[0] == 1);
proof_assert!(s2[1] == 2);⚠
Sourcepub fn concat(self, other: Self) -> Self
pub fn concat(self, other: Self) -> Self
Returns a new sequence, made of the concatenation of self and other.
§Example
let s1 = snapshot!(Seq::singleton(1));
let s2 = snapshot!(Seq::create(2, |i| i));
let s = snapshot!(s1.concat(s2));
proof_assert!(s[0] == 1);
proof_assert!(s[1] == 0);
proof_assert!(s[2] == 1);⚠
Sourcepub fn map<U>(self, m: Mapping<T, U>) -> Seq<U>
pub fn map<U>(self, m: Mapping<T, U>) -> Seq<U>
⚠
ensures
result.len() == self.len()ensures
forall<i> 0 <= i && i < self.len() ==> result[i] == m[self[i]]Sourcepub fn flat_map<U>(self, other: Mapping<T, Seq<U>>) -> Seq<U>
pub fn flat_map<U>(self, other: Mapping<T, Seq<U>>) -> Seq<U>
(open)
if self.len() == 0 { Seq::empty() } else { other.get(*self.index_logic_unsized(0)).concat(self.tail().flat_map(other)) }
Sourcepub fn reverse(self) -> Self
pub fn reverse(self) -> Self
Returns a new sequence, which is self in reverse order.
§Example
let s = snapshot!(Seq::create(3, |i| i));
let s2 = snapshot!(s.reverse());
proof_assert!(s2[0] == 2);
proof_assert!(s2[1] == 1);
proof_assert!(s2[2] == 0);⚠
Sourcepub fn permutation_of(self, other: Self) -> bool
pub fn permutation_of(self, other: Self) -> bool
Returns true if other is a permutation of self.
(open)
self.permut(other, 0, self.len())Sourcepub fn permut(self, other: Self, start: Int, end: Int) -> bool
pub fn permut(self, other: Self, start: Int, end: Int) -> bool
Returns true if:
selfandotherhave the same lengthstartandendare in bounds (between0andself.len()included)- Every element of
selfbetweenstart(included) andend(excluded) can also be found inotherbetweenstartandend, and vice-versa
⚠
Sourcepub fn exchange(self, other: Self, i: Int, j: Int) -> bool
pub fn exchange(self, other: Self, i: Int, j: Int) -> bool
Returns true if:
selfandotherhave the same lengthiandjare in bounds (between0andself.len()excluded)otheris equal toselfwhere the elements atiandjare swapped
⚠
Sourcepub fn contains(self, x: T) -> bool
pub fn contains(self, x: T) -> bool
Returns true if there is an index i such that self[i] == x.
(open)
pearlite! { exists<i> 0 <= i && i < self.len() && self[i] == x }Sourcepub fn sorted_range(self, start: Int, end: Int) -> boolwhere
T: OrdLogic,
pub fn sorted_range(self, start: Int, end: Int) -> boolwhere
T: OrdLogic,
Returns true if self is sorted between start and end.
(open)
pearlite! { forall<i, j> start <= i && i <= j && j < end ==> self[i] <= self[j] }
Sourcepub fn sorted(self) -> boolwhere
T: OrdLogic,
pub fn sorted(self) -> boolwhere
T: OrdLogic,
Returns true if self is sorted.
(open)
self.sorted_range(0, self.len())Sourcepub fn concat_contains()
pub fn concat_contains()
(open)
{}ensures
forall<a: Seq<T>, b: Seq<T>, x> a.concat(b).contains(x) == a.contains(x) || b.contains(x)
Source§impl<T> Seq<&T>
impl<T> Seq<&T>
Sourcepub fn to_owned_seq(self) -> Seq<T>
pub fn to_owned_seq(self) -> Seq<T>
Convert Seq<&T> to Seq<T>.
This is simply a utility method, because &T is equivalent to T in pearlite.
⚠
Source§impl<T> Seq<T>
Ghost definitions
impl<T> Seq<T>
Ghost definitions
Sourcepub fn len_ghost(&self) -> Int
pub fn len_ghost(&self) -> Int
Returns the number of elements in the sequence, also referred to as its ‘length’.
If you need to get the length in pearlite, consider using len.
§Example
use creusot_contracts::prelude::*;
let mut s = Seq::new();
ghost! {
s.push_back_ghost(1);
s.push_back_ghost(2);
s.push_back_ghost(3);
let len = s.len_ghost();
proof_assert!(len == 3);
};terminates
ghost
ensures
result == self.len()Sourcepub fn is_empty_ghost(&self) -> bool
pub fn is_empty_ghost(&self) -> bool
Returns true if the sequence is empty.
§Example
use creusot_contracts::prelude::*;
#[check(ghost)]
#[requires(s.len() == 0)]
pub fn foo(mut s: Seq<i32>) {
assert!(s.is_empty_ghost());
s.push_back_ghost(1i32);
assert!(!s.is_empty_ghost());
}
ghost! {
foo(Seq::new().into_inner())
};terminates
ghost
ensures
result == (self.len() == 0)Sourcepub fn push_front_ghost(&mut self, x: T)
pub fn push_front_ghost(&mut self, x: T)
Appends an element to the front of a collection.
§Example
use creusot_contracts::prelude::*;
let mut s = Seq::new();
ghost! {
s.push_front_ghost(1);
s.push_front_ghost(2);
s.push_front_ghost(3);
proof_assert!(s[0] == 3i32 && s[1] == 2i32 && s[2] == 1i32);
};terminates
ghost
ensures
^self == self.push_front(x)Sourcepub fn push_back_ghost(&mut self, x: T)
pub fn push_back_ghost(&mut self, x: T)
Appends an element to the back of a collection.
§Example
use creusot_contracts::prelude::*;
let mut s = Seq::new();
ghost! {
s.push_back_ghost(1);
s.push_back_ghost(2);
s.push_back_ghost(3);
proof_assert!(s[0] == 1i32 && s[1] == 2i32 && s[2] == 3i32);
};terminates
ghost
ensures
^self == self.push_back(x)Sourcepub fn get_ghost(&self, index: Int) -> Option<&T>
pub fn get_ghost(&self, index: Int) -> Option<&T>
Returns a reference to an element at index or None if index is out of bounds.
§Example
use creusot_contracts::prelude::*;
let mut s = Seq::new();
ghost! {
s.push_back_ghost(10);
s.push_back_ghost(40);
s.push_back_ghost(30);
let get1 = s.get_ghost(1int);
let get2 = s.get_ghost(3int);
proof_assert!(get1 == Some(&40i32));
proof_assert!(get2 == None);
};terminates
ghost
ensures
match self.get(index) { None => result == None, Some(v) => result == Some(&v), }
Sourcepub fn get_mut_ghost(&mut self, index: Int) -> Option<&mut T>
pub fn get_mut_ghost(&mut self, index: Int) -> Option<&mut T>
Returns a mutable reference to an element at index or None if index is out of bounds.
§Example
use creusot_contracts::prelude::*;
let mut s = Seq::new();
ghost! {
s.push_back_ghost(0);
s.push_back_ghost(1);
s.push_back_ghost(2);
if let Some(elem) = s.get_mut_ghost(1int) {
*elem = 42;
}
proof_assert!(s[0] == 0i32 && s[1] == 42i32 && s[2] == 2i32);
};terminates
ghost
ensures
match result { None => self.get(index) == None && *self == ^self, Some(r) => self.get(index) == Some(*r) && ^r == (^self)[index], }
ensures
forall<i> i != index ==> (*self).get(i) == (^self).get(i)ensures
(*self).len() == (^self).len()Sourcepub fn pop_back_ghost(&mut self) -> Option<T>
pub fn pop_back_ghost(&mut self) -> Option<T>
Removes the last element from a vector and returns it, or None if it is empty.
§Example
use creusot_contracts::prelude::*;
let mut s = Seq::new();
ghost! {
s.push_back_ghost(1);
s.push_back_ghost(2);
s.push_back_ghost(3);
let popped = s.pop_back_ghost();
proof_assert!(popped == Some(3i32));
proof_assert!(s[0] == 1i32 && s[1] == 2i32);
};terminates
ghost
ensures
match result { None => *self == Seq::empty() && *self == ^self, Some(r) => *self == (^self).push_back(r) }
Sourcepub fn pop_front_ghost(&mut self) -> Option<T>
pub fn pop_front_ghost(&mut self) -> Option<T>
Removes the first element from a vector and returns it, or None if it is empty.
§Example
use creusot_contracts::prelude::*;
let mut s = Seq::new();
ghost! {
s.push_back_ghost(1);
s.push_back_ghost(2);
s.push_back_ghost(3);
let popped = s.pop_front_ghost();
proof_assert!(popped == Some(1i32));
proof_assert!(s[0] == 2i32 && s[1] == 3i32);
};terminates
ghost
ensures
match result { None => *self == Seq::empty() && *self == ^self, Some(r) => (*self).len() > 0 && r == (*self)[0] && ^self == (*self).tail() }
Sourcepub fn clear_ghost(&mut self)
pub fn clear_ghost(&mut self)
Clears the sequence, removing all values.
§Example
use creusot_contracts::prelude::*;
let mut s = Seq::new();
ghost! {
s.push_back_ghost(1);
s.push_back_ghost(2);
s.push_back_ghost(3);
s.clear_ghost();
proof_assert!(s == Seq::empty());
};terminates
ghost
ensures
^self == Self::empty()Sourcepub fn split_off_ghost(&mut self, mid: Int) -> Self
pub fn split_off_ghost(&mut self, mid: Int) -> Self
Split a sequence in two at the given index.
terminates
ghost
requires
0 <= mid && mid <= self.len()ensures
(^self).len() == midensures
(^self).concat(result) == *selfTrait Implementations§
Source§impl<T> IndexLogic<Int> for Seq<T>
impl<T> IndexLogic<Int> for Seq<T>
Source§impl<T> IndexMut<(Int, Int)> for Seq<T>
impl<T> IndexMut<(Int, Int)> for Seq<T>
Source§fn index_mut(&mut self, index: (Int, Int)) -> &mut Self::Output
fn index_mut(&mut self, index: (Int, Int)) -> &mut Self::Output
terminates
ghost
requires
0 <= index.0 && index.0 < self.len() && 0 <= index.1 && index.1 < self.len()
requires
index.0 != index.1ensures
(*result).0 == (*self)[index.0] && (*result).1 == (*self)[index.1] && (^result).0 == (^self)[index.0] && (^result).1 == (^self)[index.1]
ensures
forall<i> i != index.0 && i != index.1 ==> (*self).get(i) == (^self).get(i)
ensures
(*self).len() == (^self).len()