krabka_verified/retention/
coverage.rs1use creusot_std::prelude::*;
2
3#[cfg(creusot)]
5#[cfg_attr(test, mutants::skip)]
6#[logic(open)]
7pub fn remote_ranges_valid(ranges: Seq<(i64, i64)>) -> bool {
8 pearlite! { forall<i: Int> 0 <= i && i < ranges.len() ==> ranges[i].0@ <= ranges[i].1@ }
9}
10
11#[cfg(creusot)]
13#[cfg_attr(test, mutants::skip)]
14#[logic(open)]
15pub fn remote_covers_offset(ranges: Seq<(i64, i64)>, offset: Int) -> bool {
16 pearlite! { exists<i: Int> 0 <= i && i < ranges.len() && ranges[i].0@ <= offset && offset <= ranges[i].1@ }
17}
18
19#[requires(forall<i: Int, j: Int> 0 <= i && i < j && j < [email protected]()
26 ==> ranges@[i].0@ <= ranges@[j].0@)]
27#[ensures(match result {
28 None => !remote_ranges_valid(ranges@)
29 || forall<i: Int> 0 <= i && i < [email protected]()
30 ==> local_start@ < ranges@[i].0@ || ranges@[i].1@ < local_start@,
31 Some(through) => remote_ranges_valid(ranges@) && local_start@ <= through@
32 && (exists<i: Int> 0 <= i && i < [email protected]() && through == ranges@[i].1)
33 && (forall<offset: Int> local_start@ <= offset && offset <= through@
34 ==> remote_covers_offset(ranges@, offset))
35 && forall<i: Int> 0 <= i && i < [email protected]() && ranges@[i].0@ <= through@ + 1
36 ==> ranges@[i].1@ <= through@,
37})]
38#[must_use]
39pub fn remote_covered_through(ranges: &[(i64, i64)], local_start: i64) -> Option<i64> {
40 let mut i = 0usize;
41 #[invariant(i@ <= [email protected]())]
42 #[invariant(forall<j: Int> 0 <= j && j < i@ ==> ranges@[j].0@ <= ranges@[j].1@)]
43 #[variant([email protected]() - i@)]
44 while i < ranges.len() {
45 if matches!(ranges.get(i), Some(&(start, end)) if start > end) {
46 return None;
47 }
48 i += 1;
49 }
50 let mut covered: Option<i64> = None;
51 i = 0;
52 #[invariant(i@ <= [email protected]())]
53 #[invariant(match covered {
54 None => forall<j: Int> 0 <= j && j < i@ ==> local_start@ < ranges@[j].0@ || ranges@[j].1@ < local_start@,
55 Some(through) => local_start@ <= through@
56 && (exists<j: Int> 0 <= j && j < i@ && through == ranges@[j].1)
57 && (forall<j: Int> 0 <= j && j < i@ ==> ranges@[j].1@ <= through@)
58 && forall<offset: Int> local_start@ <= offset && offset <= through@
59 ==> remote_covers_offset(ranges@, offset),
60 })]
61 #[variant([email protected]() - i@)]
62 while i < ranges.len() {
63 let Some(&(start, end)) = ranges.get(i) else {
64 break;
65 };
66 match covered {
67 None if start <= local_start && local_start <= end => covered = Some(end),
68 None => {}
69 Some(through) if start <= through.saturating_add(1) => {
70 if end > through {
71 covered = Some(end);
72 }
73 }
74 Some(_through) => {
75 proof_assert!(forall<j: Int> i@ <= j && j < [email protected]() ==> ranges@[j].0@ > _through@ + 1);
76 return covered;
77 }
78 }
79 i += 1;
80 }
81 covered
82}
83
84#[cfg(test)]
85mod tests;