use crate::Encode;
use arbitrary::{Arbitrary, Unstructured};
use commonware_conformance::Conformance;
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha8Rng;
use std::{fmt::Debug, marker::PhantomData};
const INITIAL_BUFFER_SIZE: usize = 4096;
const MAX_BUFFER_SIZE: usize = 16 * 1024 * 1024;
pub fn generate_value<T>(seed: u64) -> T
where
T: for<'a> Arbitrary<'a>,
{
let mut buffer_size = INITIAL_BUFFER_SIZE;
loop {
let mut rng = ChaCha8Rng::seed_from_u64(seed);
let mut buffer = vec![0u8; buffer_size];
rng.fill(&mut buffer[..]);
let mut unstructured = Unstructured::new(&buffer);
loop {
match T::arbitrary(&mut unstructured) {
Ok(value) => return value,
Err(arbitrary::Error::IncorrectFormat) => continue,
Err(arbitrary::Error::NotEnoughData) => break,
Err(e) => panic!("failed to generate arbitrary value: {e}"),
}
}
if buffer_size >= MAX_BUFFER_SIZE {
panic!("failed to generate arbitrary value: NotEnoughData with {buffer_size} bytes");
}
buffer_size = (buffer_size * 2).min(MAX_BUFFER_SIZE);
}
}
#[derive(Debug, Clone, Copy)]
pub struct CodecConformance<T>(PhantomData<T>);
impl<T> Conformance for CodecConformance<T>
where
T: Encode + for<'a> Arbitrary<'a> + Send + Sync,
{
async fn commit(seed: u64) -> Vec<u8> {
let value: T = generate_value(seed);
value.encode().to_vec()
}
}