use vstd::prelude::*;
verus! {
pub open spec fn nonnegative(value: int) -> bool {
0 <= value
}
pub open spec fn positive(value: int) -> bool {
&&& nonnegative(value)
&&& value > 0
}
pub open spec fn increment(pre: int, post: int) -> bool {
post == pre + 1
}
pub proof fn stalled_increment_rejected(pre: int)
ensures !increment(pre, pre),
{
}
pub open spec fn stutter(pre: int, post: int) -> bool {
post == pre
}
pub open spec fn decrement_if(pre: int, post: int, selected: bool) -> bool {
post == pre - if selected { 1int } else { 0int }
}
pub open spec fn guarded_decrement_if(pre: int, post: int, selected: bool) -> bool {
&&& nonnegative(pre)
&&& decrement_if(pre, post, selected)
&&& nonnegative(post)
&&& (selected ==> 0 < pre)
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct Counter {
pub value: u64,
}
impl Counter {
pub open spec fn value_spec(&self) -> nat {
self.value as nat
}
pub fn new(value: u64) -> (counter: Self)
ensures counter.value_spec() == value as nat,
{
Self { value }
}
pub fn value(&self) -> (value: u64)
ensures value as nat == self.value_spec(),
{
self.value
}
#[must_use]
pub fn try_increment(&mut self) -> (accepted: bool)
ensures
accepted == (old(self).value_spec() < u64::MAX as nat),
accepted ==> final(self).value_spec() == old(self).value_spec() + 1,
!accepted ==> final(self).value_spec() == old(self).value_spec(),
{
if self.value == u64::MAX {
return false;
}
self.value = self.value + 1;
true
}
#[must_use]
pub fn try_decrement(&mut self) -> (accepted: bool)
ensures
accepted == (old(self).value_spec() > 0),
accepted ==> final(self).value_spec() + 1 == old(self).value_spec(),
!accepted ==> final(self).value_spec() == old(self).value_spec(),
{
if self.value == 0 {
return false;
}
self.value = self.value - 1;
true
}
}
}