Skip to content

Commit

Permalink
Support #[arbitrary(with = ...)] with closures
Browse files Browse the repository at this point in the history
  • Loading branch information
greyblake committed Oct 20, 2022
1 parent 9dd430d commit 727ab88
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 9 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ This can be particular handy if your structure uses a type that does not impleme

```rust
#[derive(Arbitrary)]
pub struct Rgb {
pub struct Rgba {
// set `r` to Default::default()
#[arbitrary(default)]
pub r: u8,
Expand All @@ -83,6 +83,10 @@ pub struct Rgb {
// where `T` is the field's type.
#[arbitrary(with = arbitrary_b)]
pub b: u8,

// Generate `a` with a custom closure (shortuct to avoid a custom funciton)
#[arbitrary(with = |u: &mut Unstructured| u.int_in_range(0..=64))]
pub a: u8,
}

fn arbitrary_b(u: &mut Unstructured) -> arbitrary::Result<u8> {
Expand Down
6 changes: 3 additions & 3 deletions derive/src/field_attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ pub enum FieldConstructor {
/// Places `Default::default()` as a field value.
Default,

/// Use custom function to generate a value for a field.
WithFunction(TokenStream),
/// Use custom function or closure to generate a value for a field.
With(TokenStream),

/// Set a field always to the given value.
Value(TokenStream),
Expand Down Expand Up @@ -71,7 +71,7 @@ fn parse_attribute_internals(stream: TokenStream) -> FieldConstructor {
"default" => FieldConstructor::Default,
"with" => {
let func_path = parse_assigned_value("with", tokens_iter);
FieldConstructor::WithFunction(func_path)
FieldConstructor::With(func_path)
}
"value" => {
let value = parse_assigned_value("value", tokens_iter);
Expand Down
6 changes: 3 additions & 3 deletions derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ fn construct_take_rest(fields: &Fields) -> TokenStream {
quote! { arbitrary::Arbitrary::arbitrary(&mut u)? }
}
}
FieldConstructor::WithFunction(func_path) => quote!(#func_path(&mut u)?),
FieldConstructor::With(function_or_closure) => quote!((#function_or_closure)(&mut u)?),
FieldConstructor::Value(value) => quote!(#value),
}
})
Expand All @@ -247,7 +247,7 @@ fn gen_size_hint_method(input: &DeriveInput) -> TokenStream {
// Note that in this case it's hard to determine what size_hint must be, so size_of::<T>() is
// just an educated guess, although it's gonna be inaccurate for dynamically
// allocated types (Vec, HashMap, etc.).
FieldConstructor::WithFunction(_) => {
FieldConstructor::With(_) => {
quote! { (::core::mem::size_of::<#ty>(), None) }
}
}
Expand Down Expand Up @@ -291,7 +291,7 @@ fn gen_constructor_for_field(field: &Field) -> TokenStream {
match determine_field_constructor(field) {
FieldConstructor::Default => quote!(Default::default()),
FieldConstructor::Arbitrary => quote!(arbitrary::Arbitrary::arbitrary(u)?),
FieldConstructor::WithFunction(func_path) => quote!(#func_path(u)?),
FieldConstructor::With(function_or_closure) => quote!((#function_or_closure)(u)?),
FieldConstructor::Value(value) => quote!(#value),
}
}
10 changes: 8 additions & 2 deletions tests/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,13 +250,16 @@ fn test_field_attributes() {
length: u8,

height: u8,

#[arbitrary(with = |u: &mut Unstructured| u.int_in_range(0..=100))]
price: u8,
}

fn arbitrary_weight(u: &mut Unstructured) -> arbitrary::Result<Weight> {
u.int_in_range(45..=56).map(Weight)
}

let parcel: Parcel = arbitrary_from(&[6, 199]);
let parcel: Parcel = arbitrary_from(&[6, 199, 17]);

// 45 + 6 = 51
assert_eq!(parcel.weight.0, 51);
Expand All @@ -267,6 +270,9 @@ fn test_field_attributes() {
// 2 + 2 = 4
assert_eq!(parcel.length, 4);

// 199 is the second byte, used by arbitrary
// 199 is the 2nd byte used by arbitrary
assert_eq!(parcel.height, 199);

// 17 is the 3rd byte used by arbitrary
assert_eq!(parcel.price, 17);
}

0 comments on commit 727ab88

Please sign in to comment.