Skip to content

Commit

Permalink
implement a generator based on Arbitrary for compatibility
Browse files Browse the repository at this point in the history
  • Loading branch information
Ekleog committed Jan 7, 2023
1 parent 724818c commit 0831c0f
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 3 deletions.
1 change: 1 addition & 0 deletions bolero-generator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ std = ["alloc", "either/use_std"]
alloc = ["rand_core/alloc"]

[dependencies]
arbitrary = "1.2"
bolero-generator-derive = { version = "0.8.0", path = "../bolero-generator-derive" }
either = { version = "1.5", default-features = false, optional = true }
rand_core = { version = "^0.6", default-features = false }
Expand Down
64 changes: 64 additions & 0 deletions bolero-generator/src/arbitrary.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use core::{marker::PhantomData, cmp};

use arbitrary::{Arbitrary, Unstructured};

use crate::{gen_with, ValueGenerator, Driver};

pub struct ArbitraryGenerator<T>(PhantomData<T>);

const ABUSIVE_SIZE: usize = 1024 * 1024;
const MIN_INCREASE: usize = 32;

impl<T> ValueGenerator for ArbitraryGenerator<T>
where
T: for<'a> Arbitrary<'a>,
{
type Output = T;

fn generate<D: Driver>(&self, driver: &mut D) -> Option<T> {
let size = T::size_hint(0);
let mut data = match T::size_hint(0) {
(min, Some(max)) if max < ABUSIVE_SIZE => gen_with::<Vec<u8>>().len(min..=max).generate(&mut *driver)?,
(min, _) => gen_with::<Vec<u8>>().len(min).generate(&mut *driver)?,
};
loop {
match Unstructured::new(&data).arbitrary() {
Ok(res) => return Some(res),
Err(arbitrary::Error::NotEnoughData) => (), // fall-through to another iter
Err(_) => return None,
}
let mut additional_size = cmp::max(data.len(), MIN_INCREASE); // exponential growth
if let Some(max) = size.1 {
let max_increase = max.saturating_sub(data.len());
if max_increase == 0 {
return None; // bug in the size_hint impl
}
if max_increase < additional_size || max_increase < ABUSIVE_SIZE {
additional_size = max_increase;
}
}
data.extend_from_slice(&gen_with::<Vec<u8>>().len(additional_size).generate(&mut *driver)?);
}
}
}

#[inline]
pub fn gen_arbitrary<T>() -> ArbitraryGenerator<T>
where
T: for<'a> Arbitrary<'a>,
{
ArbitraryGenerator(PhantomData)
}

#[cfg(test)]
mod tests {
#[test]
fn tuple() {
let _ = generator_test!(gen_arbitrary::<(u8, u32, u64)>());
}

#[test]
fn vec() {
let _ = generator_test!(gen_arbitrary::<Vec<usize>>());
}
}
6 changes: 4 additions & 2 deletions bolero-generator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub mod std_generators;

pub use bolero_generator_derive::*;

pub mod arbitrary;
pub mod array;
pub mod atomic;
pub mod bool;
Expand All @@ -43,7 +44,8 @@ pub mod result;
pub mod time;
pub mod tuple;

pub use driver::Driver;
pub use crate::arbitrary::gen_arbitrary;
pub use crate::driver::Driver;

/// Generate a value for a given type
pub trait TypeGenerator: Sized {
Expand Down Expand Up @@ -252,7 +254,7 @@ pub fn constant<T: Clone>(value: T) -> Constant<T> {

pub mod prelude {
pub use crate::{
constant, gen, gen_with,
constant, gen, gen_arbitrary, gen_with,
one_of::{one_of, one_value_of, OneOfExt, OneValueOfExt},
TypeGenerator, TypeGeneratorWithParams, ValueGenerator,
};
Expand Down
2 changes: 1 addition & 1 deletion rust-toolchain
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.57.0
1.63.0

0 comments on commit 0831c0f

Please sign in to comment.