use alloc::vec::Vec;
use arbitrary::{Arbitrary, Unstructured};
#[derive(Debug, Clone, Default)]
pub struct ControlPlane {
data: Vec<u8>,
fuel: Option<u8>,
tmp: Vec<u8>,
}
impl Arbitrary<'_> for ControlPlane {
fn arbitrary<'a>(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
Ok(Self::new(u.arbitrary()?))
}
}
impl ControlPlane {
fn new(data: Vec<u8>) -> Self {
Self {
data,
fuel: None,
tmp: Vec::new(),
}
}
pub fn set_fuel(&mut self, fuel: u8) {
self.fuel = (fuel != 0).then_some(fuel)
}
fn consume_fuel(&mut self) -> bool {
match self.fuel {
None => true, Some(f) if f == 0 => false, Some(ref mut f) => {
*f -= 1;
true
}
}
}
pub fn get_decision(&mut self) -> bool {
self.consume_fuel() && self.data.pop().unwrap_or_default() & 1 == 1
}
pub fn get_arbitrary<T: for<'a> Arbitrary<'a> + Default>(&mut self) -> T {
if !self.consume_fuel() || self.data.is_empty() {
return T::default();
}
let mut u = Unstructured::new(&self.data);
let res = u.arbitrary().unwrap_or_default();
let rest = u.take_rest();
self.tmp.resize(rest.len(), 0); self.tmp.copy_from_slice(rest);
core::mem::swap(&mut self.data, &mut self.tmp);
res
}
pub fn shuffle<T>(&mut self, slice: &mut [T]) {
if !self.consume_fuel() || self.data.is_empty() {
return;
}
let mut u = Unstructured::new(&self.data);
let mut to_permute = &mut slice[..];
while to_permute.len() > 1 {
if let Ok(idx) = u.choose_index(to_permute.len()) {
to_permute.swap(0, idx);
to_permute = &mut to_permute[1..];
} else {
break;
}
}
let rest = u.take_rest();
self.tmp.resize(rest.len(), 0); self.tmp.copy_from_slice(rest);
core::mem::swap(&mut self.data, &mut self.tmp);
}
pub fn shuffled<T>(&mut self, iter: impl Iterator<Item = T>) -> impl Iterator<Item = T> {
let mut slice: Vec<_> = iter.collect();
self.shuffle(&mut slice);
slice.into_iter()
}
}