use vstd::prelude::*;
verus! {
pub struct Signal {
pub num_values: u64,
pub current_value: u64,
pub change_observed: bool,
pub num_listeners: usize,
pub pending: Vec<bool>,
pub notified: Vec<bool>,
}
impl Signal {
pub open spec fn type_invariant(&self) -> bool {
&&& self.current_value < self.num_values
&&& self.pending.len() == self.num_listeners
&&& self.notified.len() == self.num_listeners
}
pub open spec fn pending_notified_disjointness(&self) -> bool {
forall|i: int|
0 <= i < self.pending.len()
==> !(#[trigger] self.pending@[i] && self.notified@[i])
}
pub open spec fn notification_provenance(&self) -> bool {
&&& !self.change_observed ==> forall|i: int|
0 <= i < self.pending.len()
==> !#[trigger] self.pending@[i] && !self.notified@[i]
&&& self.change_observed ==> forall|i: int|
0 <= i < self.pending.len()
==> #[trigger] self.pending@[i] || self.notified@[i]
}
pub fn new(initial_value: u64, num_values: u64, num_listeners: usize) -> (s: Signal)
requires
initial_value < num_values,
ensures
s.num_values == num_values,
s.num_listeners == num_listeners,
s.current_value == initial_value,
!s.change_observed,
s.pending.len() == num_listeners,
s.notified.len() == num_listeners,
forall|i: int| 0 <= i < num_listeners ==> !s.pending@[i],
forall|i: int| 0 <= i < num_listeners ==> !s.notified@[i],
s.type_invariant(),
s.pending_notified_disjointness(),
s.notification_provenance(),
{
let mut pending: Vec<bool> = Vec::new();
let mut notified: Vec<bool> = Vec::new();
let mut i: usize = 0;
while i < num_listeners
invariant
i <= num_listeners,
pending.len() == i,
notified.len() == i,
forall|k: int| 0 <= k < i ==> !pending@[k],
forall|k: int| 0 <= k < i ==> !notified@[k],
decreases num_listeners - i,
{
pending.push(false);
notified.push(false);
i = i + 1;
}
Signal {
num_values,
current_value: initial_value,
change_observed: false,
num_listeners,
pending,
notified,
}
}
pub fn is_pending(&self, l: usize) -> (b: bool)
requires
l < self.pending.len(),
ensures
b == self.pending@[l as int],
{
self.pending[l]
}
pub fn is_notified(&self, l: usize) -> (b: bool)
requires
l < self.notified.len(),
ensures
b == self.notified@[l as int],
{
self.notified[l]
}
pub fn set_value(&mut self, v: u64) -> (changed: bool)
requires
old(self).type_invariant(),
old(self).pending_notified_disjointness(),
old(self).notification_provenance(),
v < old(self).num_values,
ensures
final(self).num_values == old(self).num_values,
final(self).num_listeners == old(self).num_listeners,
changed == (v != old(self).current_value),
changed ==> final(self).current_value == v,
changed ==> final(self).change_observed,
changed ==> forall|i: int| 0 <= i < final(self).pending.len() ==> final(self).pending@[i],
changed ==> forall|i: int| 0 <= i < final(self).notified.len() ==> !final(self).notified@[i],
!changed ==> final(self).current_value == old(self).current_value,
!changed ==> final(self).change_observed == old(self).change_observed,
!changed ==> final(self).pending@ == old(self).pending@,
!changed ==> final(self).notified@ == old(self).notified@,
final(self).type_invariant(),
final(self).pending_notified_disjointness(),
final(self).notification_provenance(),
{
if v == self.current_value {
return false;
}
let mut i: usize = 0;
while i < self.pending.len()
invariant
self.num_values == old(self).num_values,
self.num_listeners == old(self).num_listeners,
self.current_value == old(self).current_value,
self.pending.len() == old(self).pending.len(),
self.notified.len() == old(self).notified.len(),
old(self).type_invariant(),
i <= self.pending.len(),
forall|k: int| 0 <= k < i ==> self.pending@[k],
forall|k: int| 0 <= k < i ==> !self.notified@[k],
decreases self.pending.len() - i,
{
assert(i < self.notified.len());
self.pending.set(i, true);
self.notified.set(i, false);
i = i + 1;
}
self.current_value = v;
self.change_observed = true;
assert(self.pending_notified_disjointness()) by {
assert forall|j: int| 0 <= j < self.pending.len()
implies !(self.pending@[j] && self.notified@[j]) by {
assert(!self.notified@[j]);
}
}
assert(self.notification_provenance()) by {
assert forall|j: int| 0 <= j < self.pending.len()
implies self.pending@[j] || self.notified@[j] by {
assert(self.pending@[j]);
}
}
true
}
pub fn notify_listener(&mut self, l: usize)
requires
old(self).type_invariant(),
old(self).pending_notified_disjointness(),
old(self).notification_provenance(),
l < old(self).pending.len(),
old(self).pending@[l as int], ensures
final(self).num_values == old(self).num_values,
final(self).num_listeners == old(self).num_listeners,
final(self).current_value == old(self).current_value, final(self).change_observed == old(self).change_observed,
final(self).pending@ == old(self).pending@.update(l as int, false),
final(self).notified@ == old(self).notified@.update(l as int, true),
final(self).type_invariant(),
final(self).pending_notified_disjointness(),
final(self).notification_provenance(),
{
assert(self.change_observed) by {
if !self.change_observed {
assert(!self.pending@[l as int]);
}
}
assert(l < self.notified.len());
self.pending.set(l, false);
self.notified.set(l, true);
assert(self.pending_notified_disjointness()) by {
assert forall|i: int| 0 <= i < self.pending.len()
implies !(self.pending@[i] && self.notified@[i]) by {
if i == l as int {
assert(!self.pending@[i]);
} else {
assert(self.pending@[i] == old(self).pending@[i]);
assert(self.notified@[i] == old(self).notified@[i]);
}
}
}
assert(self.notification_provenance()) by {
assert forall|i: int| 0 <= i < self.pending.len()
implies self.pending@[i] || self.notified@[i] by {
if i == l as int {
assert(self.notified@[i]);
} else {
assert(self.pending@[i] == old(self).pending@[i]);
assert(self.notified@[i] == old(self).notified@[i]);
}
}
}
}
}
}