use vstd::prelude::*;
verus! {
pub struct ActuationPass {
pub num_seats: usize,
pub allocation: Vec<Option<u64>>,
pub effects: Vec<Option<u64>>,
pub complete: bool,
}
impl ActuationPass {
pub open spec fn type_invariant(&self) -> bool {
&&& self.allocation.len() == self.num_seats
&&& self.effects.len() == self.num_seats
}
pub open spec fn effect_fidelity(&self) -> bool {
forall|i: int|
#![trigger self.effects@[i]]
0 <= i < self.effects.len()
==> (self.effects@[i] is Some ==> self.effects@[i] == self.allocation@[i])
}
pub open spec fn actuation_scope(&self) -> bool {
forall|i: int|
#![trigger self.effects@[i]]
0 <= i < self.effects.len()
==> (self.effects@[i] is Some ==> self.allocation@[i] is Some)
}
pub open spec fn ready_to_finish(&self) -> bool {
forall|i: int|
#![trigger self.allocation@[i]]
0 <= i < self.allocation.len()
==> (self.allocation@[i] is Some ==> self.effects@[i] is Some)
}
pub open spec fn pass_completeness(&self) -> bool {
self.complete ==> self.ready_to_finish()
}
pub open spec fn invariant(&self) -> bool {
&&& self.type_invariant()
&&& self.effect_fidelity()
&&& self.actuation_scope()
&&& self.pass_completeness()
}
pub fn new(allocation: Vec<Option<u64>>, num_seats: usize) -> (s: ActuationPass)
requires
allocation.len() == num_seats,
ensures
s.num_seats == num_seats,
s.allocation@ == allocation@,
s.effects.len() == num_seats,
forall|i: int| 0 <= i < num_seats ==> s.effects@[i] is None,
!s.complete,
s.invariant(),
{
let mut effects: Vec<Option<u64>> = Vec::new();
let mut i: usize = 0;
while i < num_seats
invariant
i <= num_seats,
effects.len() == i,
forall|k: int| 0 <= k < i ==> effects@[k] is None,
decreases num_seats - i,
{
effects.push(None);
i = i + 1;
}
ActuationPass { num_seats, allocation, effects, complete: false }
}
pub fn is_allocated(&self, s: usize) -> (b: bool)
requires
s < self.allocation.len(),
ensures
b == (self.allocation@[s as int] is Some),
{
match self.allocation[s] {
Some(_) => true,
None => false,
}
}
pub fn is_actuated(&self, s: usize) -> (b: bool)
requires
s < self.effects.len(),
ensures
b == (self.effects@[s as int] is Some),
{
match self.effects[s] {
Some(_) => true,
None => false,
}
}
pub fn can_allocate(&self, s: usize) -> (b: bool)
requires
self.type_invariant(),
s < self.num_seats,
ensures
b == (!self.complete && self.allocation@[s as int] is None),
{
!self.complete && !self.is_allocated(s)
}
pub fn can_deallocate(&self, s: usize) -> (b: bool)
requires
self.type_invariant(),
s < self.num_seats,
ensures
b == (!self.complete
&& self.allocation@[s as int] is Some
&& self.effects@[s as int] is None),
{
!self.complete && self.is_allocated(s) && !self.is_actuated(s)
}
pub fn can_actuate(&self, s: usize) -> (b: bool)
requires
self.type_invariant(),
s < self.num_seats,
ensures
b == (!self.complete
&& self.effects@[s as int] is None
&& self.allocation@[s as int] is Some),
{
!self.complete && !self.is_actuated(s) && self.is_allocated(s)
}
pub fn ready_to_finish_exec(&self) -> (b: bool)
requires
self.type_invariant(),
ensures
b == self.ready_to_finish(),
{
let len = self.allocation.len();
let mut i: usize = 0;
while i < len
invariant
i <= len,
len == self.allocation.len(),
self.effects.len() == self.allocation.len(),
forall|k: int| 0 <= k < i
==> (self.allocation@[k] is Some ==> self.effects@[k] is Some),
decreases len - i,
{
if self.is_allocated(i) && !self.is_actuated(i) {
assert(self.allocation@[i as int] is Some);
assert(self.effects@[i as int] is None);
return false;
}
i = i + 1;
}
true
}
pub fn allocate(&mut self, s: usize, resource: u64)
requires
old(self).invariant(),
s < old(self).num_seats,
!old(self).complete,
old(self).allocation@[s as int] is None,
ensures
final(self).num_seats == old(self).num_seats,
final(self).allocation@ == old(self).allocation@.update(s as int, Some(resource)),
final(self).effects@ == old(self).effects@,
final(self).complete == old(self).complete,
final(self).invariant(),
{
assert(old(self).effects@[s as int] is None) by {
if old(self).effects@[s as int] is Some {
assert(old(self).effects@[s as int] == old(self).allocation@[s as int]);
}
}
self.allocation.set(s, Some(resource));
assert(self.effect_fidelity()) by {
assert forall|i: int| 0 <= i < self.effects.len() && self.effects@[i] is Some
implies self.effects@[i] == self.allocation@[i] by {
if i == s as int {
assert(self.effects@[i] is None);
} else {
assert(self.effects@[i] == old(self).effects@[i]);
assert(self.allocation@[i] == old(self).allocation@[i]);
}
}
}
}
pub fn deallocate(&mut self, s: usize)
requires
old(self).invariant(),
s < old(self).num_seats,
!old(self).complete,
old(self).allocation@[s as int] is Some,
old(self).effects@[s as int] is None,
ensures
final(self).num_seats == old(self).num_seats,
final(self).allocation@ == old(self).allocation@.update(s as int, None),
final(self).effects@ == old(self).effects@,
final(self).complete == old(self).complete,
final(self).invariant(),
{
self.allocation.set(s, None);
assert(self.effect_fidelity()) by {
assert forall|i: int| 0 <= i < self.effects.len() && self.effects@[i] is Some
implies self.effects@[i] == self.allocation@[i] by {
if i == s as int {
assert(self.effects@[i] is None);
} else {
assert(self.effects@[i] == old(self).effects@[i]);
assert(self.allocation@[i] == old(self).allocation@[i]);
}
}
}
}
pub fn actuate(&mut self, s: usize)
requires
old(self).invariant(),
s < old(self).num_seats,
!old(self).complete,
old(self).effects@[s as int] is None,
old(self).allocation@[s as int] is Some,
ensures
final(self).num_seats == old(self).num_seats,
final(self).allocation@ == old(self).allocation@,
final(self).effects@ == old(self).effects@.update(s as int, old(self).allocation@[s as int]),
final(self).complete == old(self).complete,
final(self).effects@[s as int] == old(self).allocation@[s as int],
final(self).invariant(),
{
let resource = match self.allocation[s] {
Some(r) => r,
None => {
assert(false);
0
},
};
self.effects.set(s, Some(resource));
assert(self.effect_fidelity()) by {
assert forall|i: int| 0 <= i < self.effects.len() && self.effects@[i] is Some
implies self.effects@[i] == self.allocation@[i] by {
if i == s as int {
assert(self.effects@[i] == old(self).allocation@[i]);
assert(self.allocation@[i] == old(self).allocation@[i]);
} else {
assert(self.effects@[i] == old(self).effects@[i]);
assert(self.allocation@[i] == old(self).allocation@[i]);
}
}
}
}
pub fn finish(&mut self)
requires
old(self).invariant(),
!old(self).complete,
old(self).ready_to_finish(),
ensures
final(self).num_seats == old(self).num_seats,
final(self).allocation@ == old(self).allocation@,
final(self).effects@ == old(self).effects@,
crate::connectives::marker::set_if(
old(self).complete,
final(self).complete,
true,
),
final(self).invariant(),
{
self.complete = true;
}
}
}