Skip to main content

automation_structures/connectives/
buffer.rs

1//! Reusable Buffer connective contract.
2//!
3//! Buffer is a connective role rather than a second queue implementation. It owns the generic
4//! retained-sequence bound used by compositions. A compact ring, fixed array, or other physical
5//! layout receives Buffer credit only through a checked view satisfying this contract.
6
7use vstd::prelude::*;
8
9use crate::value_eq::ValueEq;
10
11verus! {
12
13/// A retained logical sequence fits within its admitted capacity.
14pub open spec fn buffer_bounded<T>(values: Seq<T>, capacity: nat) -> bool {
15    values.len() <= capacity
16}
17
18/// A retained sequence at exact capacity remains admitted.
19pub proof fn exact_capacity_admitted<T>(values: Seq<T>, capacity: nat)
20    requires values.len() == capacity,
21    ensures buffer_bounded(values, capacity),
22{
23}
24
25/// Whether `value` occurs in the first `end` retained positions.
26pub open spec fn contains_up_to<T>(values: Seq<T>, end: int, value: T) -> bool {
27    exists|index: int| 0 <= index < end && index < values.len() && values[index] == value
28}
29
30/// Whether `value` is retained by a Buffer.
31pub open spec fn contains_value<T>(values: Seq<T>, value: T) -> bool {
32    contains_up_to(values, values.len() as int, value)
33}
34
35/// Whether every retained value is distinct.
36pub open spec fn all_distinct<T>(values: Seq<T>) -> bool {
37    forall|left: int, right: int|
38        0 <= left < values.len() && 0 <= right < values.len() && left != right
39            ==> #[trigger] values[left] != #[trigger] values[right]
40}
41
42/// Extending a considered prefix exposes exactly its new final value.
43pub proof fn lemma_contains_extend<T>(values: Seq<T>, end: int, value: T)
44    requires 0 <= end < values.len(),
45    ensures contains_up_to(values, end + 1, value)
46        == (contains_up_to(values, end, value) || values[end] == value),
47{
48    if contains_up_to(values, end + 1, value) {
49        let index = choose|index: int|
50            0 <= index < end + 1 && index < values.len() && values[index] == value;
51        assert(index < end || index == end);
52    }
53    if contains_up_to(values, end, value) {
54        let index = choose|index: int|
55            0 <= index < end && index < values.len() && values[index] == value;
56        assert(0 <= index < end + 1 && index < values.len());
57    }
58    if values[end] == value {
59        assert(0 <= end < end + 1 && end < values.len());
60    }
61}
62
63/// Appending one value extends membership by exactly that value.
64pub proof fn lemma_push_contains<T>(values: Seq<T>, added: T, value: T)
65    ensures contains_value(values.push(added), value)
66        == (contains_value(values, value) || value == added),
67{
68    let pushed = values.push(added);
69    if contains_value(pushed, value) {
70        let index = choose|index: int| 0 <= index < pushed.len() && pushed[index] == value;
71        if index < values.len() {
72            assert(pushed[index] == values[index]);
73        } else {
74            assert(index == values.len());
75        }
76    }
77    if contains_value(values, value) {
78        let index = choose|index: int| 0 <= index < values.len() && values[index] == value;
79        assert(pushed[index] == values[index]);
80    }
81    if value == added {
82        assert(pushed[values.len() as int] == value);
83    }
84}
85
86/// Every in-range retained position witnesses membership of its value.
87pub proof fn indexed_value_contained<T>(values: Seq<T>, index: int)
88    requires 0 <= index < values.len(),
89    ensures contains_value(values, values[index]),
90{
91    assert(0 <= index < values.len() && values[index] == values[index]);
92}
93
94/// Removing one position from a distinct sequence removes exactly that value.
95pub proof fn contains_remove_distinct<T>(values: Seq<T>, removed: int, value: T)
96    requires
97        all_distinct(values),
98        0 <= removed < values.len(),
99    ensures
100        contains_value(values.remove(removed), value)
101            == (contains_value(values, value) && value != values[removed]),
102{
103    values.remove_ensures(removed);
104    let reduced = values.remove(removed);
105    if contains_value(reduced, value) {
106        let index = choose|index: int|
107            0 <= index < reduced.len() && reduced[index] == value;
108        let old_index = if index < removed { index } else { index + 1 };
109        assert(0 <= old_index < values.len());
110        assert(old_index != removed);
111        assert(reduced[index] == values[old_index]);
112        assert(contains_value(values, value));
113        if value == values[removed] {
114            assert(values[old_index] == values[removed]);
115            assert(false);
116        }
117    }
118    if contains_value(values, value) && value != values[removed] {
119        let old_index = choose|index: int|
120            0 <= index < values.len() && values[index] == value;
121        assert(old_index != removed);
122        let index = if old_index < removed { old_index } else { old_index - 1 };
123        assert(0 <= index < reduced.len());
124        assert(reduced[index] == values[old_index]);
125    }
126}
127
128/// A bounded FIFO connective.
129pub struct Buffer<T> {
130    /// Maximum number of retained values.
131    pub capacity: usize,
132    /// Retained values in FIFO order.
133    pub values: Vec<T>,
134}
135
136impl<T> Buffer<T> {
137    /// Whether the retained FIFO contents fit within the configured capacity.
138    pub closed spec fn well_formed(&self) -> bool {
139        buffer_bounded(self.values@, self.capacity as nat)
140    }
141
142    /// Construct an empty FIFO with a fixed capacity.
143    pub fn new(capacity: usize) -> (buffer: Self)
144        ensures
145            buffer.well_formed(),
146            buffer.capacity == capacity,
147            buffer.values@.len() == 0,
148    {
149        Self { capacity, values: Vec::new() }
150    }
151
152    /// Fixed FIFO capacity.
153    pub fn capacity(&self) -> (capacity: usize)
154        ensures capacity == self.capacity,
155    {
156        self.capacity
157    }
158
159    /// Number of retained values.
160    pub fn len(&self) -> (length: usize)
161        ensures length == self.values@.len(),
162    {
163        self.values.len()
164    }
165
166    /// Whether no values are retained.
167    pub fn is_empty(&self) -> (empty: bool)
168        ensures empty == (self.values@.len() == 0),
169    {
170        self.values.is_empty()
171    }
172
173    /// Whether the FIFO is at capacity.
174    pub fn is_full(&self) -> (full: bool)
175        ensures full == (self.values@.len() == self.capacity),
176    {
177        self.values.len() == self.capacity
178    }
179
180    /// Push one value, returning it unchanged when the FIFO is full.
181    ///
182    /// # Errors
183    ///
184    /// Returns the supplied value when the buffer is full.
185    pub fn push(&mut self, value: T) -> (result: Result<(), T>)
186        requires old(self).well_formed(),
187        ensures
188            final(self).well_formed(),
189            final(self).capacity == old(self).capacity,
190            old(self).values@.len() < old(self).capacity ==> result is Ok,
191            old(self).values@.len() >= old(self).capacity ==> result == Err(value),
192            old(self).values@.len() < old(self).capacity ==>
193                final(self).values@ == old(self).values@.push(value),
194            old(self).values@.len() >= old(self).capacity ==>
195                final(self).values@ == old(self).values@,
196    {
197        if self.values.len() >= self.capacity { return Err(value); }
198        self.values.push(value);
199        Ok(())
200    }
201
202    /// Remove and return the oldest retained value.
203    pub fn pop(&mut self) -> (value: Option<T>)
204        requires old(self).well_formed(),
205        ensures
206            final(self).well_formed(),
207            final(self).capacity == old(self).capacity,
208            old(self).values@.len() == 0 ==> value is None,
209            old(self).values@.len() > 0 ==> value == Some(old(self).values@[0]),
210            old(self).values@.len() == 0 ==> final(self).values@ == old(self).values@,
211            old(self).values@.len() > 0 ==>
212                final(self).values@ == old(self).values@.skip(1),
213            all_distinct(old(self).values@) ==> all_distinct(final(self).values@),
214    {
215        if self.values.is_empty() { None } else { Some(self.values.remove(0)) }
216    }
217}
218
219/// Query membership in a retained sequence using its verified equality adapter.
220pub fn retained_contains<T: ValueEq + Copy>(values: &Vec<T>, value: T) -> (present: bool)
221    ensures present == contains_value(values@, value),
222{
223        let mut index: usize = 0;
224        while index < values.len()
225            invariant
226                index <= values.len(),
227                !contains_up_to(values@, index as int, value),
228            decreases values.len() - index,
229        {
230            if values[index].value_eq(&value) {
231                assert(contains_value(values@, value));
232                return true;
233            }
234            proof { lemma_contains_extend(values@, index as int, value); }
235            index = index + 1;
236        }
237        false
238    }
239
240impl<T: ValueEq + Copy> Buffer<T> {
241    /// Query retained membership through the Buffer owner.
242    pub fn contains(&self, value: T) -> (present: bool)
243        ensures present == contains_value(self.values@, value),
244    {
245        retained_contains(&self.values, value)
246    }
247
248    /// Append a value only when it is absent and capacity remains.
249    pub fn push_unique(&mut self, value: T) -> (accepted: bool)
250        requires
251            old(self).well_formed(),
252            all_distinct(old(self).values@),
253        ensures
254            final(self).well_formed(),
255            all_distinct(final(self).values@),
256            final(self).capacity == old(self).capacity,
257            accepted == (old(self).values@.len() < old(self).capacity
258                && !contains_value(old(self).values@, value)),
259            accepted ==> final(self).values@ == old(self).values@.push(value),
260            !accepted ==> final(self).values@ == old(self).values@,
261    {
262        if self.values.len() >= self.capacity || self.contains(value) {
263            return false;
264        }
265        let ghost before = self.values@;
266        self.values.push(value);
267        proof {
268            assert(all_distinct(self.values@)) by {
269                assert forall|left: int, right: int|
270                    0 <= left < self.values@.len()
271                        && 0 <= right < self.values@.len()
272                        && left != right
273                    implies #[trigger] self.values@[left] != #[trigger] self.values@[right] by {
274                    if left < before.len() && right < before.len() {
275                    } else if left == before.len() && right < before.len() {
276                        assert(self.values@[right] == before[right]);
277                        assert(contains_value(before, before[right]));
278                    } else if right == before.len() && left < before.len() {
279                        assert(self.values@[left] == before[left]);
280                        assert(contains_value(before, before[left]));
281                    }
282                }
283            }
284        }
285        true
286    }
287
288    /// Remove one distinct retained value wherever it occurs.
289    pub fn remove_value(&mut self, value: T) -> (removed: bool)
290        requires
291            old(self).well_formed(),
292            all_distinct(old(self).values@),
293        ensures
294            final(self).well_formed(),
295            all_distinct(final(self).values@),
296            final(self).capacity == old(self).capacity,
297            removed == contains_value(old(self).values@, value),
298            removed ==> exists|index: int|
299                0 <= index < old(self).values@.len()
300                    && old(self).values@[index] == value
301                    && final(self).values@ == old(self).values@.remove(index),
302            !removed ==> final(self).values@ == old(self).values@,
303            forall|candidate: T| #[trigger] contains_value(final(self).values@, candidate)
304                == (contains_value(old(self).values@, candidate) && candidate != value),
305    {
306        let ghost before = self.values@;
307        assert(before == old(self).values@);
308        assert(buffer_bounded(before, self.capacity as nat)) by {
309            reveal(Buffer::well_formed);
310        }
311        let mut index: usize = 0;
312        while index < self.values.len()
313            invariant
314                index <= self.values.len(),
315                self.values@ == before,
316                before == old(self).values@,
317                self.capacity == old(self).capacity,
318                buffer_bounded(before, self.capacity as nat),
319                all_distinct(before),
320                forall|prior: int| 0 <= prior < index ==>
321                    before[prior] != value,
322            decreases self.values.len() - index,
323        {
324            if self.values[index].value_eq(&value) {
325                proof {
326                    assert(before[index as int] == value);
327                    indexed_value_contained(before, index as int);
328                    assert(contains_value(before, value));
329                }
330                let _removed_value = self.values.remove(index);
331                assert(_removed_value == value);
332                proof { before.remove_ensures(index as int); }
333                assert(self.values@ == before.remove(index as int));
334                assert(self.values@.len() < before.len());
335                assert(self.well_formed()) by {
336                    reveal(Buffer::well_formed);
337                    reveal(buffer_bounded);
338                }
339                assert(all_distinct(self.values@)) by {
340                    before.remove_ensures(index as int);
341                    assert forall|left: int, right: int|
342                        0 <= left < self.values@.len()
343                            && 0 <= right < self.values@.len()
344                            && left != right
345                        implies #[trigger] self.values@[left] != #[trigger] self.values@[right] by {
346                        let old_left = if left < index { left } else { left + 1 };
347                        let old_right = if right < index { right } else { right + 1 };
348                        assert(0 <= old_left < before.len());
349                        assert(0 <= old_right < before.len());
350                        assert(old_left != old_right);
351                        assert(self.values@[left] == before[old_left]);
352                        assert(self.values@[right] == before[old_right]);
353                    }
354                }
355                assert forall|candidate: T|
356                    #[trigger] contains_value(self.values@, candidate)
357                        == (contains_value(before, candidate) && candidate != value) by {
358                    contains_remove_distinct(before, index as int, candidate);
359                    assert(before[index as int] == value);
360                }
361                assert(exists|old_index: int|
362                    0 <= old_index < before.len()
363                        && before[old_index] == value
364                        && self.values@ == before.remove(old_index)) by {
365                    assert(0 <= index as int);
366                    assert((index as int) < before.len());
367                }
368                return true;
369            }
370            index = index + 1;
371        }
372        assert(!contains_value(before, value)) by {
373            if contains_value(before, value) {
374                let present = choose|present: int|
375                    0 <= present < before.len() && before[present] == value;
376                assert(false);
377            }
378        }
379        false
380    }
381}
382
383}
384
385impl<T: core::fmt::Debug> core::fmt::Debug for Buffer<T> {
386    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
387        formatter
388            .debug_struct("Buffer")
389            .field("capacity", &self.capacity)
390            .field("values", &self.values)
391            .finish()
392    }
393}