use vstd::prelude::*;
verus! {
pub struct Accumulator<T: Copy> {
#[allow(dead_code)]
original: Ghost<Seq<T>>,
accumulated: Vec<T>,
pending: Vec<T>,
}
impl<T: Copy> Accumulator<T> {
pub closed spec fn well_formed(&self) -> bool {
crate::connectives::accumulator::carries(
self.original@,
self.accumulated@,
self.pending@,
)
}
pub fn new(values: Vec<T>) -> (accumulator: Self)
ensures accumulator.well_formed(),
{
let ghost original = values@;
Self { original: Ghost(original), accumulated: Vec::new(), pending: values }
}
pub fn accumulated_len(&self) -> usize { self.accumulated.len() }
pub fn pending_len(&self) -> usize { self.pending.len() }
pub fn is_complete(&self) -> bool { self.pending.is_empty() }
#[expect(clippy::indexing_slicing, reason = "the branch proves the accumulated index is in bounds")]
pub fn accumulated(&self, index: usize) -> Option<T> {
if index < self.accumulated.len() { Some(self.accumulated[index]) } else { None }
}
#[expect(clippy::indexing_slicing, reason = "the branch proves the pending index is in bounds")]
pub fn pending(&self, index: usize) -> Option<T> {
if index < self.pending.len() { Some(self.pending[index]) } else { None }
}
#[expect(clippy::indexing_slicing, reason = "the nonempty guard proves the pending head exists")]
pub fn advance(&mut self) -> (value: Option<T>)
requires old(self).well_formed(),
ensures final(self).well_formed(),
{
if self.pending.is_empty() { return None; }
let ghost old_accumulated = self.accumulated@;
let ghost old_pending = self.pending@;
let value = self.pending[0];
self.pending.remove(0);
self.accumulated.push(value);
proof {
crate::connectives::accumulator::consume_pending_head(
old_accumulated,
old_pending,
);
assert(self.accumulated@ =~= old_accumulated.push(old_pending[0]));
assert(self.pending@ =~= old_pending.skip(1));
}
Some(value)
}
}
pub struct Buffer<T> {
capacity: usize,
values: Vec<T>,
}
impl<T> Buffer<T> {
pub closed spec fn well_formed(&self) -> bool {
crate::connectives::buffer::buffer_bounded(self.values@, self.capacity as nat)
}
pub fn new(capacity: usize) -> (buffer: Self)
ensures buffer.well_formed(),
{
Self { capacity, values: Vec::new() }
}
pub fn capacity(&self) -> usize { self.capacity }
pub fn len(&self) -> usize { self.values.len() }
pub fn is_empty(&self) -> bool { self.values.is_empty() }
pub fn is_full(&self) -> bool { self.values.len() == self.capacity }
pub fn push(&mut self, value: T) -> (result: Result<(), T>)
requires old(self).well_formed(),
ensures final(self).well_formed(),
{
if self.values.len() >= self.capacity { return Err(value); }
self.values.push(value);
Ok(())
}
pub fn pop(&mut self) -> (value: Option<T>)
requires old(self).well_formed(),
ensures final(self).well_formed(),
{
if self.values.is_empty() { None } else { Some(self.values.remove(0)) }
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct Counter {
value: u64,
}
impl Counter {
pub fn new(value: u64) -> (counter: Self) { Self { value } }
pub fn value(&self) -> u64 { self.value }
#[must_use]
pub fn try_increment(&mut self) -> (accepted: bool) {
if self.value == u64::MAX { return false; }
self.value = self.value + 1;
true
}
#[must_use]
pub fn try_decrement(&mut self) -> (accepted: bool) {
if self.value == 0 { return false; }
self.value = self.value - 1;
true
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct Marker {
marked: bool,
}
impl Marker {
pub fn new(marked: bool) -> (marker: Self) { Self { marked } }
pub fn is_marked(&self) -> bool { self.marked }
pub fn set(&mut self) -> (changed: bool) {
let changed = !self.marked;
self.marked = true;
changed
}
pub fn clear(&mut self) -> (changed: bool) {
let changed = self.marked;
self.marked = false;
changed
}
}
pub fn projection_consistent(projected: bool, source: bool) -> (consistent: bool)
ensures consistent == crate::connectives::projection::membership_consistent(projected, source),
{
projected == source
}
pub fn strictly_before(left: usize, right: usize) -> (ordered: bool) {
crate::connectives::ordering_pass::is_strictly_before(left, right)
}
}
impl<T: Copy + core::fmt::Debug> core::fmt::Debug for Accumulator<T> {
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
formatter
.debug_struct("Accumulator")
.field("accumulated", &self.accumulated)
.field("pending", &self.pending)
.finish()
}
}
impl<T: core::fmt::Debug> core::fmt::Debug for Buffer<T> {
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
formatter
.debug_struct("Buffer")
.field("capacity", &self.capacity)
.field("values", &self.values)
.finish()
}
}