Skip to content

Commit

Permalink
add structural method to driver (#222)
Browse files Browse the repository at this point in the history
  • Loading branch information
camshaft authored Jun 3, 2024
1 parent 78d1cc2 commit 966e81a
Show file tree
Hide file tree
Showing 15 changed files with 557 additions and 391 deletions.
122 changes: 88 additions & 34 deletions lib/bolero-generator-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,21 @@ fn generate_struct_type_gen(
let generate_method = quote!(
#[inline]
fn generate<__BOLERO_DRIVER: #krate::driver::Driver>(__bolero_driver: &mut __BOLERO_DRIVER) -> Option<Self> {
Some(#value)
__bolero_driver.enter_product::<Self, _, _>(
|__bolero_driver| Some(#value)
)
}
);
let mutate_method = quote!(
#[inline]
fn mutate<__BOLERO_DRIVER: #krate::driver::Driver>(&mut self, __bolero_driver: &mut __BOLERO_DRIVER) -> Option<()> {
let #destructure = self;
#mutate_body
Some(())
__bolero_driver.enter_product::<Self, _, _>(
|__bolero_driver| {
let #destructure = self;
#mutate_body
Some(())
}
)
}

#[inline]
Expand All @@ -119,7 +125,18 @@ fn generate_enum_type_gen(
data_enum: DataEnum,
) -> (TokenStream2, TokenStream2) {
let variant_max = data_enum.variants.len();
let variant_upper = lower_type_index(variant_max, variant_max, name.span());
let base_case: usize = 0;

let variant_names: Vec<_> = data_enum
.variants
.iter()
.map(|variant| {
let span = variant.span();
let name = variant.ident.to_string();
quote_spanned!(span=> #name,)
})
.collect();
let variant_names = quote_spanned!(name.span()=> &[#(#variant_names)*]);

let gen_variants: Vec<_> = data_enum
.variants
Expand Down Expand Up @@ -186,37 +203,48 @@ fn generate_enum_type_gen(
let generate_method = quote!(
#[inline]
fn generate<__BOLERO_DRIVER: #krate::driver::Driver>(__bolero_driver: &mut __BOLERO_DRIVER) -> Option<Self> {
let __bolero_selection = __bolero_driver.gen_variant(#variant_upper, 0)?;
Some(match __bolero_selection {
#(#gen_variants)*
_ => unreachable!("Value outside of range"),
})
__bolero_driver.enter_sum::<Self, _, _>(
Some(#variant_names),
#variant_max,
#base_case,
|__bolero_driver, __bolero_selection| {
Some(match __bolero_selection {
#(#gen_variants)*
_ => unreachable!("Value outside of range"),
})
}
)
}
);

let mutate_method = quote!(
#[inline]
fn mutate<__BOLERO_DRIVER: #krate::driver::Driver>(&mut self, __bolero_driver: &mut __BOLERO_DRIVER) -> Option<()> {
let __bolero_new_selection = __bolero_driver.gen_variant(#variant_upper, 0)?;

let __bolero_prev_selection = match self {
#(#gen_lookup)*
};

if __bolero_prev_selection == __bolero_new_selection {
match self {
#(#gen_mutate)*
}
} else {
let next = match __bolero_new_selection {
#(#gen_variants)*
_ => unreachable!("Value outside of range"),
};
match ::core::mem::replace(self, next) {
#(#gen_driver_cache)*
__bolero_driver.enter_sum::<Self, _, _>(
Some(#variant_names),
#variant_max,
#base_case,
|__bolero_driver, __bolero_new_selection| {
let __bolero_prev_selection = match self {
#(#gen_lookup)*
};

if __bolero_prev_selection == __bolero_new_selection {
match self {
#(#gen_mutate)*
}
} else {
let next = match __bolero_new_selection {
#(#gen_variants)*
_ => unreachable!("Value outside of range"),
};
match ::core::mem::replace(self, next) {
#(#gen_driver_cache)*
}
Some(())
}
}
Some(())
}
)
}

#[inline]
Expand All @@ -239,6 +267,25 @@ fn generate_union_type_gen(
let field_max = data_union.fields.named.len();
let field_upper = lower_type_index(field_max, field_max, name.span());

let base_case: usize = 0;

let variant_names: Vec<_> = data_union
.fields
.named
.iter()
.enumerate()
.map(|(idx, variant)| {
let span = variant.span();
let name = if let Some(name) = variant.ident.as_ref() {
name.to_string()
} else {
format!("<UnnamedUnionVariant{idx}>")
};
quote_spanned!(span=> #name,)
})
.collect();
let variant_names = quote_spanned!(name.span()=> &[#(#variant_names)*]);

let fields: Vec<_> = data_union
.fields
.named
Expand All @@ -256,18 +303,25 @@ fn generate_union_type_gen(
let span = generator.span();
let value = generator.value_generate();
quote_spanned!(span=>
#idx => Some(#name { #field_name: #value })
#idx => Some(#name { #field_name: #value }),
)
})
.collect();

let generate_method = quote!(
#[inline]
fn generate<__BOLERO_DRIVER: #krate::driver::Driver>(__bolero_driver: &mut __BOLERO_DRIVER) -> Option<Self> {
match __bolero_driver.gen_variant(#field_upper, 0)? {
#(#fields,)*
_ => unreachable!("Value outside of range"),
}
__bolero_driver.enter_sum::<Self, _, _>(
Some(#variant_names),
#field_upper,
#base_case,
|__bolero_driver, __bolero_selection| {
match __bolero_selection {
#(#fields)*
_ => unreachable!("Value outside of range"),
}
}
)
}
);

Expand Down
22 changes: 7 additions & 15 deletions lib/bolero-generator/src/alloc/collections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,7 @@ macro_rules! impl_values_collection_generator {

#[inline]
fn mutate<D: $crate::Driver>(&self, driver: &mut D, value: &mut Self::Output) -> Option<()> {
driver.depth_guard(|driver| {
let len = $crate::ValueGenerator::generate(&self.len, driver)?.into();

driver.enter_list::<Self::Output, _, _, _>(&self.len, |driver, len| {
$crate::alloc_generators::CollectionGenerator::mutate_collection(value, driver, len, &self.values)?;

if value.len() != len {
Expand Down Expand Up @@ -124,9 +122,7 @@ macro_rules! impl_values_collection_generator {

#[inline]
fn mutate<D: $crate::Driver>(&mut self, driver: &mut D) -> Option<()> {
driver.depth_guard(|driver| {
let len = $crate::ValueGenerator::generate(&$default_len_range, driver)?.into();

driver.enter_list::<Self, _, _, _>(&$default_len_range, |driver, len| {
$crate::alloc_generators::CollectionGenerator::mutate_collection(self, driver, len, &V::gen())?;

if self.len() != len {
Expand Down Expand Up @@ -170,8 +166,8 @@ macro_rules! impl_values_collection_generator {

#[inline]
fn mutate<D: $crate::Driver>(&self, driver: &mut D, value: &mut Self::Output) -> Option<()> {
driver.depth_guard(|driver| {
let len = $crate::ValueGenerator::generate(&$default_len_range, driver)?;
driver.enter_list::<Self::Output, _, _, _>(&$default_len_range, |driver, len| {
// TODO remove the allocation here
let generators: $crate::alloc_generators::Vec<_> = self.iter().collect();
let gen_item = $crate::one_of(&generators[..]);

Expand Down Expand Up @@ -281,9 +277,8 @@ macro_rules! impl_key_values_collection_generator {

#[inline]
fn generate<D: $crate::Driver>(&self, driver: &mut D) -> Option<Self::Output> {
driver.depth_guard(|driver| {
driver.enter_list::<Self::Output, _, _, _>(&self.len, |driver, len| {
use $crate::ValueGenerator;
let len = ValueGenerator::generate(&self.len, driver)?.into();
Iterator::map(0..len, |_| {
Some((
ValueGenerator::generate(&self.keys, driver)?,
Expand All @@ -302,9 +297,7 @@ macro_rules! impl_key_values_collection_generator {
{
#[inline]
fn generate<D: $crate::Driver>(driver: &mut D) -> Option<Self> {
driver.depth_guard(|driver| {
use $crate::ValueGenerator;
let len = ValueGenerator::generate(&$default_len_range, driver)?;
driver.enter_list::<Self, _, _, _>(&$default_len_range, |driver, len| {
Iterator::map(0..len, |_|
Some((K::generate(driver)?, V::generate(driver)?))
).collect()
Expand Down Expand Up @@ -340,12 +333,11 @@ macro_rules! impl_key_values_collection_generator {

#[inline]
fn generate<D: $crate::Driver>(&self, driver: &mut D) -> Option<Self::Output> {
driver.depth_guard(|driver| {
driver.enter_list::<Self::Output, _, _, _>(&$default_len_range, |driver, len| {
use $crate::ValueGenerator;

assert!(!self.is_empty());

let len = ValueGenerator::generate(&$default_len_range, driver)?;
let generators: $crate::alloc_generators::Vec<_> = self.iter().collect();
let generators_len = 0..generators.len();

Expand Down
22 changes: 10 additions & 12 deletions lib/bolero-generator/src/alloc/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,14 @@ impl<C, L> StringGenerator<C, L> {
}
}

pub fn len<Gen: ValueGenerator<Output = Len>, Len: Into<usize>>(
self,
len: Gen,
) -> StringGenerator<C, Gen> {
pub fn len<Gen: ValueGenerator<Output = usize>>(self, len: Gen) -> StringGenerator<C, Gen> {
StringGenerator {
chars: self.chars,
len,
}
}

pub fn map_len<Gen: ValueGenerator<Output = Len>, F: Fn(L) -> Gen, Len: Into<usize>>(
pub fn map_len<Gen: ValueGenerator<Output = usize>, F: Fn(L) -> Gen>(
self,
map: F,
) -> StringGenerator<C, Gen> {
Expand All @@ -49,20 +46,21 @@ impl<C, L> StringGenerator<C, L> {
}
}

impl<G: ValueGenerator<Output = char>, L: ValueGenerator<Output = Len>, Len: Into<usize>>
ValueGenerator for StringGenerator<G, L>
impl<G: ValueGenerator<Output = char>, L: ValueGenerator<Output = usize>> ValueGenerator
for StringGenerator<G, L>
{
type Output = String;

fn generate<D: Driver>(&self, driver: &mut D) -> Option<Self::Output> {
let len = ValueGenerator::generate(&self.len, driver)?.into();

Iterator::map(0..len, |_| ValueGenerator::generate(&self.chars, driver)).collect()
let mut value = String::default();
self.mutate(driver, &mut value)?;
Some(value)
}

fn mutate<D: Driver>(&self, driver: &mut D, value: &mut Self::Output) -> Option<()> {
let len = ValueGenerator::generate(&self.len, driver)?.into();
CollectionGenerator::mutate_collection(value, driver, len, &self.chars)
driver.enter_list::<Self::Output, _, _, _>(&self.len, |driver, len| {
CollectionGenerator::mutate_collection(value, driver, len, &self.chars)
})
}
}

Expand Down
56 changes: 32 additions & 24 deletions lib/bolero-generator/src/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,55 @@ use crate::{Driver, TypeGenerator, TypeGeneratorWithParams, TypeValueGenerator,

impl<T: TypeGenerator, const LEN: usize> TypeGenerator for [T; LEN] {
fn generate<D: Driver>(driver: &mut D) -> Option<Self> {
// TODO use core::array::try_from_fn once stable
// see: https://github.com/rust-lang/rust/issues/89379
// see: https://github.com/camshaft/bolero/issues/133
let mut maybe_init: [Option<T>; LEN] = [(); LEN].map(|_| None);
driver.enter_product::<Self, _, _>(|driver| {
// TODO use core::array::try_from_fn once stable
// see: https://github.com/rust-lang/rust/issues/89379
// see: https://github.com/camshaft/bolero/issues/133
let mut maybe_init: [Option<T>; LEN] = [(); LEN].map(|_| None);

for value in &mut maybe_init {
*value = Some(T::generate(driver)?);
}
for value in &mut maybe_init {
*value = Some(T::generate(driver)?);
}

Some(maybe_init.map(|t| t.unwrap()))
Some(maybe_init.map(|t| t.unwrap()))
})
}

fn mutate<D: Driver>(&mut self, driver: &mut D) -> Option<()> {
for item in self {
item.mutate(driver)?;
}
Some(())
driver.enter_product::<Self, _, _>(|driver| {
for item in self.iter_mut() {
item.mutate(driver)?;
}
Some(())
})
}
}

impl<G: ValueGenerator, const LEN: usize> ValueGenerator for [G; LEN] {
type Output = [G::Output; LEN];

fn generate<D: Driver>(&self, driver: &mut D) -> Option<Self::Output> {
// TODO use core::array::try_from_fn once stable
// see: https://github.com/rust-lang/rust/issues/89379
// see: https://github.com/camshaft/bolero/issues/133
let mut maybe_init: [Option<G::Output>; LEN] = [(); LEN].map(|_| None);
driver.enter_product::<Self::Output, _, _>(|driver| {
// TODO use core::array::try_from_fn once stable
// see: https://github.com/rust-lang/rust/issues/89379
// see: https://github.com/camshaft/bolero/issues/133
let mut maybe_init: [Option<G::Output>; LEN] = [(); LEN].map(|_| None);

for (generator, value) in self.iter().zip(&mut maybe_init) {
*value = Some(generator.generate(driver)?);
}
for (generator, value) in self.iter().zip(&mut maybe_init) {
*value = Some(generator.generate(driver)?);
}

Some(maybe_init.map(|t| t.unwrap()))
Some(maybe_init.map(|t| t.unwrap()))
})
}

fn mutate<D: Driver>(&self, driver: &mut D, value: &mut Self::Output) -> Option<()> {
for (generator, value) in self.iter().zip(value) {
generator.mutate(driver, value)?;
}
Some(())
driver.enter_product::<Self::Output, _, _>(|driver| {
for (generator, value) in self.iter().zip(value.iter_mut()) {
generator.mutate(driver, value)?;
}
Some(())
})
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/bolero-generator/src/bounded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ impl<T> BoundExt<T> for Bound<T> {
}
}

pub trait BoundedValue<B = Self>: Sized {
pub trait BoundedValue<B = Self>: 'static + Sized {
fn gen_bounded<D: Driver>(driver: &mut D, min: Bound<&B>, max: Bound<&B>) -> Option<Self>;

fn mutate_bounded<D: Driver>(
Expand Down
Loading

0 comments on commit 966e81a

Please sign in to comment.