Skip to content

Commit d12a83e

Browse files
committed
verify collections, but using a form factor similar to cargo tests
1 parent fe6eb8b commit d12a83e

2 files changed

Lines changed: 77 additions & 0 deletions

File tree

kernel/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,16 @@ version.workspace = true
88
authors.workspace = true
99
edition.workspace = true
1010

11+
[package.metadata.flux]
12+
enabled = true
13+
check_overflow = "lazy"
14+
include = [ "src/collections{*.rs}" ]
15+
1116
[dependencies]
1217
tock-registers = { path = "../libraries/tock-register-interface" }
1318
tock-cells = { path = "../libraries/tock-cells" }
1419
tock-tbf = { path = "../libraries/tock-tbf" }
20+
flux-rs = { git = "https://github.com/flux-rs/flux.git" }
1521

1622
# In general, Tock discourages the use of cargo features. However for certain
1723
# kernel crate configuration, we have not found reasonable alternatives to

kernel/src/collections/ring_buffer.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,3 +318,74 @@ mod test {
318318
assert_eq!(buf.dequeue(), None);
319319
}
320320
}
321+
322+
323+
// ===== Flux proof ========
324+
325+
// Need to tell Flux what slice.len() does
326+
#[flux_rs::extern_spec]
327+
impl<T> [T] {
328+
#[flux_rs::sig(fn(&[T][@len]) -> usize[len])]
329+
fn len(v: &[T]) -> usize;
330+
}
331+
332+
// Need to tell Flux what an Option<T> is
333+
// Here, we refine Option<T> with a bool, denoting whether it is Some or None
334+
#[flux_rs::extern_spec]
335+
#[flux_rs::refined_by(b: bool)]
336+
enum Option<T> {
337+
#[variant(Option<T>[false])]
338+
None,
339+
#[variant({T} -> Option<T>[true])]
340+
Some(T),
341+
}
342+
343+
#[flux::specs {
344+
mod collections {
345+
mod ring_buffer {
346+
// Specify well-formedness for RingBuffer<T>
347+
#[refined_by(ring_len: int, hd: int, tl: int)]
348+
struct RingBuffer<T> {
349+
ring: {&mut [T][ring_len] | ring_len > 1},
350+
head: {usize[hd] | hd < ring_len},
351+
tail: {usize[tl] | tl < ring_len},
352+
}
353+
354+
impl RingBuffer<T> {
355+
// Every time RingBuffer::new() is called,
356+
// Flux will ensure the slice passed in has length > 1.
357+
fn new({&mut [T][@ring_len] | ring_len > 1}) -> RingBuffer<T>[ring_len, 0, 0];
358+
}
359+
}
360+
361+
mod queue {
362+
impl Queue<T> for collections::ring_buffer::RingBuffer<T> {
363+
fn enqueue(self: &mut RingBuffer<T>, val: T) -> bool
364+
ensures self: RingBuffer<T>;
365+
366+
fn push(self: &mut RingBuffer<T>, val: T) -> Option<T>
367+
ensures self: RingBuffer<T>;
368+
369+
fn dequeue(self: &mut RingBuffer<T>) -> Option<T>
370+
ensures self: RingBuffer<T>;
371+
372+
fn remove_first_matching<F>(self: &mut RingBuffer<T>, _) -> Option<T>
373+
ensures self: RingBuffer<T>;
374+
375+
fn retain<F>(self: &mut RingBuffer<T>, _)
376+
ensures self: RingBuffer<T>;
377+
378+
fn empty(self: &mut RingBuffer<T>[@old])
379+
ensures self: RingBuffer<T>[old.ring_len, 0, 0];
380+
}
381+
}
382+
383+
mod list {
384+
impl Iterator for collections::list::ListIterator<T> {
385+
fn next(self: &mut ListIterator<T>) -> Option<&T>
386+
ensures self: ListIterator<T>;
387+
}
388+
}
389+
}
390+
}]
391+
const _: () = ();

0 commit comments

Comments
 (0)