#![cfg(feature = "proptest")]
use core::fmt::Debug;
use core::num::NonZeroUsize;
extern crate alloc;
use alloc::{boxed::Box, vec::Vec};
use proptest::strategy::{NewTree, Strategy, ValueTree};
use proptest::test_runner::TestRunner;
use bit_vec::BitVec;
#[derive(Debug)]
pub struct BufferStrategy<C, T>
where C: Strategy<Value = NonZeroUsize>, T: Strategy {
capacity: C,
items: T,
}
impl<C, T> BufferStrategy<C, T>
where C: Strategy<Value = NonZeroUsize>, T: Strategy {
pub fn new(capacity: C, items: T) -> Self {
Self { capacity, items }
}
}
impl<C, T> Strategy for BufferStrategy<C, T>
where C: Strategy<Value = NonZeroUsize>, T: Strategy {
type Tree = BufferValueTree<C::Tree, T::Tree>;
type Value = (NonZeroUsize, Vec<T::Value>);
fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
let capacity = self.capacity.new_tree(runner)?;
let max_capacity = capacity.current().get();
let items = (0 .. max_capacity)
.map(|_| self.items.new_tree(runner))
.collect::<Result<Vec<T::Tree>, _>>()?
.into_boxed_slice();
Ok(BufferValueTree {
capacity,
items,
in_use: BitVec::from_elem(max_capacity, true),
next_step: Some(BufferShrink::Capacity),
prev_step: None,
})
}
}
#[derive(Debug)]
pub struct BufferValueTree<C, T>
where C: ValueTree<Value = NonZeroUsize>, T: ValueTree {
capacity: C,
items: Box<[T]>,
in_use: BitVec,
next_step: Option<BufferShrink>,
prev_step: Option<BufferShrink>,
}
impl<C, T> ValueTree for BufferValueTree<C, T>
where C: ValueTree<Value = NonZeroUsize>, T: ValueTree {
type Value = (NonZeroUsize, Vec<T::Value>);
fn current(&self) -> Self::Value {
(self.capacity.current(), self.items.iter()
.zip(self.in_use.iter())
.filter_map(|(i, u)| u.then(|| i.current()))
.collect())
}
fn simplify(&mut self) -> bool {
if let Some(BufferShrink::Capacity) = self.next_step {
let old_cap = self.capacity.current();
if self.capacity.simplify() && self.capacity.current() < old_cap {
let new_cap = self.capacity.current();
for i in new_cap.get() .. old_cap.get() {
self.in_use.set(i, false);
}
self.prev_step = Some(BufferShrink::Capacity);
return true;
} else {
self.next_step = Some(BufferShrink::Remove(0));
}
}
if let Some(BufferShrink::Remove(i)) = self.next_step {
if let Some(true) = self.in_use.get(i) {
self.in_use.set(i, false);
self.prev_step = Some(BufferShrink::Remove(i));
self.next_step = Some(BufferShrink::Remove(i + 1));
return true;
} else {
self.next_step = Some(BufferShrink::Shrink(0));
}
}
while let Some(BufferShrink::Shrink(i)) = self.next_step {
if let Some(true) = self.in_use.get(i) {
if self.items[i].simplify() {
self.prev_step = Some(BufferShrink::Shrink(i));
return true;
} else {
self.next_step = Some(BufferShrink::Shrink(i + 1));
}
} else {
self.next_step = None;
return false;
}
}
false
}
fn complicate(&mut self) -> bool {
match self.prev_step.take() {
None => false,
Some(BufferShrink::Capacity) => {
let old = self.capacity.current();
if self.capacity.complicate() && old < self.capacity.current() {
for i in old.get() .. self.capacity.current().get() {
self.in_use.set(i, true);
}
self.prev_step = Some(BufferShrink::Capacity);
true
} else {
self.prev_step = None;
false
}
},
Some(BufferShrink::Remove(i)) => {
self.in_use.set(i, true);
self.prev_step = None;
true
},
Some(BufferShrink::Shrink(i)) => {
if self.items[i].complicate() {
self.prev_step = Some(BufferShrink::Shrink(i));
true
} else {
self.prev_step = None;
false
}
},
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum BufferShrink {
Capacity,
Remove(usize),
Shrink(usize),
}