use vstd::prelude::*;
verus! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EditAdmission {
Admitted,
Readonly,
Stale,
}
pub open spec fn edit_admitted(readonly: bool, base: int, live: int) -> bool {
!readonly && base == live
}
pub open spec fn save_allowed(readonly: bool, force: bool) -> bool {
!readonly || force
}
pub open spec fn ack_current(saved: int, live: int) -> bool {
saved == live
}
pub fn classify_edit(readonly: bool, base: u64, live: u64) -> (decision: EditAdmission)
ensures
(decision == EditAdmission::Admitted) == edit_admitted(readonly, base as int, live as int),
(decision == EditAdmission::Readonly) == readonly,
(decision == EditAdmission::Stale) == (!readonly && base as int != live as int),
{
if readonly {
EditAdmission::Readonly
} else if base != live {
EditAdmission::Stale
} else {
EditAdmission::Admitted
}
}
pub fn writable(readonly: bool) -> (yes: bool)
ensures
yes == !readonly,
{
!readonly
}
pub fn save_admitted(readonly: bool, force: bool) -> (admitted: bool)
ensures
admitted == save_allowed(readonly, force),
{
!readonly || force
}
pub fn save_ack_is_current(saved: u64, live: u64) -> (current: bool)
ensures
current == ack_current(saved as int, live as int),
{
saved == live
}
proof fn readonly_never_admitted(base: int, live: int)
ensures
!edit_admitted(true, base, live),
{
}
proof fn stale_base_never_admitted(base: int, live: int)
requires
base != live,
ensures
!edit_admitted(false, base, live),
{
}
proof fn older_save_retires_nothing(saved: int, live: int)
requires
saved != live,
ensures
!ack_current(saved, live),
{
}
}