#[cfg(kani)]
pub trait KaniCompose: Sized {
fn kani_depth0() -> Self;
fn kani_depth1() -> Self {
Self::kani_depth0()
}
fn kani_depth2() -> Self {
Self::kani_depth1()
}
fn kani_chunk(n: usize) -> Vec<Self> {
(0..n)
.map(|i| match i % 3 {
0 => Self::kani_depth0(),
1 => Self::kani_depth1(),
_ => Self::kani_depth2(),
})
.collect()
}
fn kani_vec_chunk_d0(_n: usize) -> Vec<Self> {
Vec::new()
}
fn kani_vec_chunk_d1(n: usize) -> Vec<Self> {
Self::kani_chunk(n)
}
fn kani_vec_chunk_d2(n: usize) -> Vec<Self> {
let mut v = Self::kani_chunk(n);
v.extend(Self::kani_chunk(n));
v
}
fn kani_vec_closure(n: usize, max_chunks: usize) -> Vec<Self> {
let chunks: usize = kani::any();
kani::assume(chunks <= max_chunks);
(0..chunks).flat_map(|_| Self::kani_chunk(n)).collect()
}
fn kani_any() -> Self {
Self::kani_depth0()
}
}
macro_rules! impl_kani_compose_primitive {
($($t:ty),* $(,)?) => {
$(
#[cfg(kani)]
impl KaniCompose for $t {
fn kani_depth0() -> Self { kani::any::<Self>() }
fn kani_any() -> Self { kani::any::<Self>() }
}
)*
};
}
impl_kani_compose_primitive!(
bool, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64, usize, isize, char,
);
#[cfg(kani)]
impl KaniCompose for String {
fn kani_depth0() -> Self {
String::new()
}
fn kani_depth1() -> Self {
kani::any::<char>().to_string()
}
fn kani_depth2() -> Self {
let c1: char = kani::any();
let c2: char = kani::any();
let mut s = c1.to_string();
s.push(c2);
s
}
fn kani_any() -> Self {
let len: usize = kani::any();
kani::assume(len <= 4);
(0..len).map(|_| kani::any::<char>()).collect()
}
}
#[cfg(kani)]
impl<T: KaniCompose> KaniCompose for Vec<T> {
fn kani_depth0() -> Self {
Vec::new()
}
fn kani_depth1() -> Self {
vec![T::kani_depth0()]
}
fn kani_depth2() -> Self {
vec![T::kani_depth0(), T::kani_depth0()]
}
fn kani_any() -> Self {
T::kani_vec_closure(1, 3)
}
}
#[cfg(kani)]
impl<T: KaniCompose, const N: usize> KaniCompose for [T; N] {
fn kani_depth0() -> Self {
std::array::from_fn(|_| T::kani_depth0())
}
fn kani_depth1() -> Self {
std::array::from_fn(|_| T::kani_depth1())
}
fn kani_depth2() -> Self {
std::array::from_fn(|_| T::kani_depth2())
}
}
#[cfg(kani)]
impl<T: KaniCompose> KaniCompose for Option<T> {
fn kani_depth0() -> Self {
None
}
fn kani_depth1() -> Self {
Some(T::kani_depth0())
}
fn kani_any() -> Self {
if kani::any::<bool>() {
Some(T::kani_any())
} else {
None
}
}
}
#[cfg(kani)]
impl<K, V> KaniCompose for std::collections::BTreeMap<K, V>
where
K: KaniCompose + Ord,
V: KaniCompose,
{
fn kani_depth0() -> Self {
std::collections::BTreeMap::new()
}
}
#[cfg(kani)]
impl<K, V, S> KaniCompose for std::collections::HashMap<K, V, S>
where
K: KaniCompose + Eq + std::hash::Hash,
V: KaniCompose,
S: Default + std::hash::BuildHasher,
{
fn kani_depth0() -> Self {
std::collections::HashMap::with_hasher(S::default())
}
}
#[cfg(kani)]
impl<A: KaniCompose, B: KaniCompose> KaniCompose for (A, B) {
fn kani_depth0() -> Self {
(A::kani_depth0(), B::kani_depth0())
}
fn kani_depth1() -> Self {
(A::kani_depth1(), B::kani_depth1())
}
fn kani_depth2() -> Self {
(A::kani_depth2(), B::kani_depth2())
}
}
#[cfg(kani)]
impl<A: KaniCompose, B: KaniCompose, C: KaniCompose> KaniCompose for (A, B, C) {
fn kani_depth0() -> Self {
(A::kani_depth0(), B::kani_depth0(), C::kani_depth0())
}
fn kani_depth1() -> Self {
(A::kani_depth1(), B::kani_depth1(), C::kani_depth1())
}
fn kani_depth2() -> Self {
(A::kani_depth2(), B::kani_depth2(), C::kani_depth2())
}
}
#[cfg(kani)]
impl<A: KaniCompose, B: KaniCompose, C: KaniCompose, D: KaniCompose> KaniCompose for (A, B, C, D) {
fn kani_depth0() -> Self {
(
A::kani_depth0(),
B::kani_depth0(),
C::kani_depth0(),
D::kani_depth0(),
)
}
fn kani_depth1() -> Self {
(
A::kani_depth1(),
B::kani_depth1(),
C::kani_depth1(),
D::kani_depth1(),
)
}
fn kani_depth2() -> Self {
(
A::kani_depth2(),
B::kani_depth2(),
C::kani_depth2(),
D::kani_depth2(),
)
}
}
#[cfg(kani)]
impl<T: KaniCompose> KaniCompose for Box<T> {
fn kani_depth0() -> Self {
Box::new(T::kani_depth0())
}
fn kani_depth1() -> Self {
Box::new(T::kani_depth1())
}
fn kani_depth2() -> Self {
Box::new(T::kani_depth2())
}
fn kani_any() -> Self {
Box::new(T::kani_any())
}
}
#[cfg(all(kani, feature = "chrono"))]
impl KaniCompose for chrono::DateTime<chrono::Utc> {
fn kani_depth0() -> Self {
chrono::DateTime::from_timestamp(0, 0).unwrap_or_default()
}
}
#[cfg(kani)]
impl<P: crate::contracts::Prop> KaniCompose for crate::contracts::Established<P> {
fn kani_depth0() -> Self {
crate::contracts::Established::assert()
}
fn kani_depth1() -> Self {
crate::contracts::Established::assert()
}
fn kani_depth2() -> Self {
crate::contracts::Established::assert()
}
}