diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fb42d8..11637c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,26 @@ Released YYYY-MM-DD. -------------------------------------------------------------------------------- +## 1.0.0-rc1 + +Unreleased. + +### Changed + +* The `Arbitrary` trait is now implemented for `&str`. [#63](https://github.com/rust-fuzz/arbitrary/pull/63) + +### Changed + +* The `Arbitrary` trait now has a lifetime parameter, allowing `Arbitrary` implementations that borrow from the raw input (e.g. the new `&str` implementaton). The `derive(Arbitrary)` macro also supports deriving `Arbitrary` on types with lifetimes now. [#63](https://github.com/rust-fuzz/arbitrary/pull/63) + +### Removed + +* The `shrink` method on the `Arbitrary` trait has been removed. + + We have found that, in practice, using [internal reduction](https://drmaciver.github.io/papers/reduction-via-generation-preview.pdf) via approaches like `cargo fuzz tmin`, where the raw input bytes are reduced rather than the `T: Arbitrary` type constructed from those raw bytes, has the best efficiency-to-maintenance ratio. To the best of our knowledge, no one is relying on or using the `Arbitrary::shrink` method. If you *are* using and relying on the `Arbitrary::shrink` method, please reach out by [dropping a comment here](https://github.com/rust-fuzz/arbitrary/issues/62) and explaining how you're using it and what your use case is. We'll figure out what the best solution is, including potentially adding shrinking functionality back to the `arbitrary` crate. + +-------------------------------------------------------------------------------- + ## 0.4.7 Released 2020-10-14. diff --git a/README.md b/README.md index 7c62e6f..66bf2d1 100644 --- a/README.md +++ b/README.md @@ -77,8 +77,8 @@ pub struct Rgb { pub b: u8, } -impl Arbitrary for Rgb { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a> Arbitrary<'a> for Rgb { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { let r = u8::arbitrary(u)?; let g = u8::arbitrary(u)?; let b = u8::arbitrary(u)?; @@ -87,33 +87,6 @@ impl Arbitrary for Rgb { } ``` -### Shrinking - -To assist with test case reduction, where you want to find the smallest and most -easily understandable test case that still demonstrates a bug you've discovered, -the `Arbitrary` trait has a `shrink` method. The `shrink` method returns an -iterator of "smaller" instances of `self`. The provided, default implementation -returns an empty iterator. - -We can override the default for our `Rgb` struct above by shrinking each of its -components and then gluing them back together again: - -```rust -impl Arbitrary for Rgb { - // ... - - fn shrink(&self) -> Box> { - let rs = self.r.shrink(); - let gs = self.g.shrink(); - let bs = self.b.shrink(); - Box::new(rs.zip(gs).zip(bs).map(|((r, g), b)| Rgb { r, g, b })) - } -} -``` - -Note that deriving `Arbitrary` will automatically derive a custom `shrink` -implementation for you. - ## License Licensed under dual MIT or Apache-2.0 at your choice. diff --git a/derive/src/lib.rs b/derive/src/lib.rs index e16212d..983bd68 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -1,51 +1,83 @@ extern crate proc_macro; -use proc_macro2::{Literal, TokenStream}; +use proc_macro2::{Span, TokenStream}; use quote::quote; use syn::*; +static ARBITRARY_LIFETIME_NAME: &str = "'arbitrary"; + #[proc_macro_derive(Arbitrary)] pub fn derive_arbitrary(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = syn::parse_macro_input!(tokens as syn::DeriveInput); + let (lifetime_without_bounds, lifetime_with_bounds) = + build_arbitrary_lifetime(input.generics.clone()); - let arbitrary_method = gen_arbitrary_method(&input); + let arbitrary_method = gen_arbitrary_method(&input, lifetime_without_bounds.clone()); let size_hint_method = gen_size_hint_method(&input); - let shrink_method = gen_shrink_method(&input); let name = input.ident; // Add a bound `T: Arbitrary` to every type parameter T. - let generics = add_trait_bounds(input.generics); - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + let generics = add_trait_bounds(input.generics, lifetime_without_bounds.clone()); + + // Build ImplGeneric with a lifetime (https://github.com/dtolnay/syn/issues/90) + let mut generics_with_lifetime = generics.clone(); + generics_with_lifetime + .params + .push(GenericParam::Lifetime(lifetime_with_bounds)); + let (impl_generics, _, _) = generics_with_lifetime.split_for_impl(); + + // Build TypeGenerics and WhereClause without a lifetime + let (_, ty_generics, where_clause) = generics.split_for_impl(); + (quote! { - impl #impl_generics arbitrary::Arbitrary for #name #ty_generics #where_clause { + impl #impl_generics arbitrary::Arbitrary<#lifetime_without_bounds> for #name #ty_generics #where_clause { #arbitrary_method #size_hint_method - #shrink_method } }) .into() } +// Returns: (lifetime without bounds, lifetime with bounds) +// Example: ("'arbitrary", "'arbitrary: 'a + 'b") +fn build_arbitrary_lifetime(generics: Generics) -> (LifetimeDef, LifetimeDef) { + let lifetime_without_bounds = + LifetimeDef::new(Lifetime::new(ARBITRARY_LIFETIME_NAME, Span::call_site())); + let mut lifetime_with_bounds = lifetime_without_bounds.clone(); + + for param in generics.params.iter() { + if let GenericParam::Lifetime(lifetime_def) = param { + lifetime_with_bounds + .bounds + .push(lifetime_def.lifetime.clone()); + } + } + + (lifetime_without_bounds, lifetime_with_bounds) +} + // Add a bound `T: Arbitrary` to every type parameter T. -fn add_trait_bounds(mut generics: Generics) -> Generics { +fn add_trait_bounds(mut generics: Generics, lifetime: LifetimeDef) -> Generics { for param in generics.params.iter_mut() { if let GenericParam::Type(type_param) = param { - type_param.bounds.push(parse_quote!(arbitrary::Arbitrary)); + type_param + .bounds + .push(parse_quote!(arbitrary::Arbitrary<#lifetime>)); } } generics } -fn gen_arbitrary_method(input: &DeriveInput) -> TokenStream { +fn gen_arbitrary_method(input: &DeriveInput, lifetime: LifetimeDef) -> TokenStream { let ident = &input.ident; let arbitrary_structlike = |fields| { let arbitrary = construct(fields, |_, _| quote!(arbitrary::Arbitrary::arbitrary(u)?)); let arbitrary_take_rest = construct_take_rest(fields); quote! { - fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result { + fn arbitrary(u: &mut arbitrary::Unstructured<#lifetime>) -> arbitrary::Result { Ok(#ident #arbitrary) } - fn arbitrary_take_rest(mut u: arbitrary::Unstructured<'_>) -> arbitrary::Result { + fn arbitrary_take_rest(mut u: arbitrary::Unstructured<#lifetime>) -> arbitrary::Result { Ok(#ident #arbitrary_take_rest) } } @@ -70,7 +102,7 @@ fn gen_arbitrary_method(input: &DeriveInput) -> TokenStream { }); let count = data.variants.len() as u64; quote! { - fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result { + fn arbitrary(u: &mut arbitrary::Unstructured<#lifetime>) -> arbitrary::Result { // Use a multiply + shift to generate a ranged random number // with slight bias. For details, see: // https://lemire.me/blog/2016/06/30/fast-random-shuffling @@ -80,7 +112,7 @@ fn gen_arbitrary_method(input: &DeriveInput) -> TokenStream { }) } - fn arbitrary_take_rest(mut u: arbitrary::Unstructured<'_>) -> arbitrary::Result { + fn arbitrary_take_rest(mut u: arbitrary::Unstructured<#lifetime>) -> arbitrary::Result { // Use a multiply + shift to generate a ranged random number // with slight bias. For details, see: // https://lemire.me/blog/2016/06/30/fast-random-shuffling @@ -162,87 +194,3 @@ fn gen_size_hint_method(input: &DeriveInput) -> TokenStream { } } } - -fn gen_shrink_method(input: &DeriveInput) -> TokenStream { - let ident = &input.ident; - let shrink_structlike = |fields| { - let inner = shrink("e!(#ident), fields, |i, field| match &field.ident { - Some(i) => quote!(&self.#i), - None => { - let i = Literal::usize_unsuffixed(i); - quote!(&self.#i) - } - }); - quote! { - fn shrink(&self) -> Box> { - #inner - } - } - }; - - return match &input.data { - Data::Struct(data) => shrink_structlike(&data.fields), - Data::Union(data) => shrink_structlike(&Fields::Named(data.fields.clone())), - Data::Enum(data) => { - let variants = data.variants.iter().map(|variant| { - let mut binding_names = Vec::new(); - let bindings = match &variant.fields { - Fields::Named(_) => { - let names = variant.fields.iter().map(|f| { - let name = f.ident.as_ref().unwrap(); - binding_names.push(quote!(#name)); - name - }); - quote!({#(#names),*}) - } - Fields::Unnamed(_) => { - let names = (0..variant.fields.len()).map(|i| { - let name = quote::format_ident!("f{}", i); - binding_names.push(quote!(#name)); - name - }); - quote!((#(#names),*)) - } - Fields::Unit => quote!(), - }; - let variant_name = &variant.ident; - let shrink = shrink("e!(#ident::#variant_name), &variant.fields, |i, _| { - binding_names[i].clone() - }); - quote!(#ident::#variant_name #bindings => { #shrink }) - }); - quote! { - fn shrink(&self) -> Box> { - match self { - #(#variants)* - } - } - } - } - }; - - fn shrink( - prefix: &TokenStream, - fields: &Fields, - access_field: impl Fn(usize, &Field) -> TokenStream, - ) -> TokenStream { - if fields.len() == 0 { - return quote!(Box::new(None.into_iter())); - } - let iters = fields.iter().enumerate().map(|(i, f)| { - let name = quote::format_ident!("field{}", i); - let field = access_field(i, f); - quote! { let mut #name = arbitrary::Arbitrary::shrink(#field); } - }); - let ctor = construct(fields, |i, _| { - let iter = quote::format_ident!("field{}", i); - quote!(#iter.next()?) - }); - quote! { - #(#iters)* - Box::new(std::iter::from_fn(move || { - Some(#prefix #ctor) - })) - } - } -} diff --git a/src/lib.rs b/src/lib.rs index f92850b..d3612d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,25 +45,14 @@ use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedL use std::ffi::{CString, OsString}; use std::path::PathBuf; use std::rc::Rc; -use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize}; use std::sync::{Arc, Mutex}; -fn empty() -> Box> { - Box::new(iter::empty()) -} - -fn once(val: T) -> Box> { - Box::new(iter::once(val)) -} - /// Generate arbitrary structured values from raw, unstructured data. /// /// The `Arbitrary` trait allows you to generate valid structured values, like /// `HashMap`s, or ASTs, or `MyTomlConfig`, or any other data structure from -/// raw, unstructured bytes provided by a fuzzer. It also features built-in -/// shrinking, so that if you find a test case that triggers a bug, you can find -/// the smallest, most easiest-to-understand test case that still triggers that -/// bug. +/// raw, unstructured bytes provided by a fuzzer. /// /// # Deriving `Arbitrary` /// @@ -118,11 +107,11 @@ fn once(val: T) -> Box> { /// # } /// use arbitrary::{Arbitrary, Result, Unstructured}; /// -/// impl Arbitrary for MyCollection +/// impl<'a, T> Arbitrary<'a> for MyCollection /// where -/// T: Arbitrary, +/// T: Arbitrary<'a>, /// { -/// fn arbitrary(u: &mut Unstructured<'_>) -> Result { +/// fn arbitrary(u: &mut Unstructured<'a>) -> Result { /// // Get an iterator of arbitrary `T`s. /// let iter = u.arbitrary_iter::()?; /// @@ -138,7 +127,7 @@ fn once(val: T) -> Box> { /// } /// # } /// ``` -pub trait Arbitrary: Sized + 'static { +pub trait Arbitrary<'a>: Sized { /// Generate an arbitrary value of `Self` from the given unstructured data. /// /// Calling `Arbitrary::arbitrary` requires that you have some raw data, @@ -179,14 +168,14 @@ pub trait Arbitrary: Sized + 'static { /// ``` /// /// See also the documentation for [`Unstructured`][crate::Unstructured]. - fn arbitrary(u: &mut Unstructured<'_>) -> Result; + fn arbitrary(u: &mut Unstructured<'a>) -> Result; /// Generate an arbitrary value of `Self` from the entirety of the given unstructured data. /// /// This is similar to Arbitrary::arbitrary, however it assumes that it is the /// last consumer of the given data, and is thus able to consume it all if it needs. /// See also the documentation for [`Unstructured`][crate::Unstructured]. - fn arbitrary_take_rest(mut u: Unstructured<'_>) -> Result { + fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result { Self::arbitrary(&mut u) } @@ -232,10 +221,10 @@ pub trait Arbitrary: Sized + 'static { /// Right(R), /// } /// - /// impl Arbitrary for MyEither + /// impl<'a, L, R> Arbitrary<'a> for MyEither /// where - /// L: Arbitrary, - /// R: Arbitrary, + /// L: Arbitrary<'a>, + /// R: Arbitrary<'a>, /// { /// fn arbitrary(u: &mut Unstructured) -> arbitrary::Result { /// // ... @@ -267,29 +256,10 @@ pub trait Arbitrary: Sized + 'static { let _ = depth; (0, None) } - - /// Generate an iterator of derived values which are "smaller" than the - /// original `self` instance. - /// - /// You can use this to help find the smallest test case that reproduces a - /// bug. - /// - /// Using `#[derive(Arbitrary)]` will automatically implement shrinking for - /// your type. - /// - /// However, if you are implementing `Arbirary` by hand and you want support - /// for shrinking your type, you must override the default provided - /// implementation of `shrink`, which just returns an empty iterator. You - /// should try pretty hard to have your `shrink` implementation return a - /// *lazy* iterator: one that computes the next value as it is needed, - /// rather than computing them up front when `shrink` is first called. - fn shrink(&self) -> Box> { - empty() - } } -impl Arbitrary for () { - fn arbitrary(_: &mut Unstructured<'_>) -> Result { +impl<'a> Arbitrary<'a> for () { + fn arbitrary(_: &mut Unstructured<'a>) -> Result { Ok(()) } @@ -299,26 +269,22 @@ impl Arbitrary for () { } } -impl Arbitrary for bool { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { - Ok(::arbitrary(u)? & 1 == 1) +impl<'a> Arbitrary<'a> for bool { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Ok(>::arbitrary(u)? & 1 == 1) } #[inline] fn size_hint(depth: usize) -> (usize, Option) { - ::size_hint(depth) - } - - fn shrink(&self) -> Box> { - Box::new(if *self { once(false) } else { empty() }) + >::size_hint(depth) } } macro_rules! impl_arbitrary_for_integers { ( $( $ty:ty: $unsigned:ty; )* ) => { $( - impl Arbitrary for $ty { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { + impl<'a> Arbitrary<'a> for $ty { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { let mut buf = [0; mem::size_of::<$ty>()]; u.fill_buffer(&mut buf)?; let mut x: $unsigned = 0; @@ -334,20 +300,6 @@ macro_rules! impl_arbitrary_for_integers { (n, Some(n)) } - fn shrink(&self) -> Box> { - let mut x = *self; - if x == 0 { - return empty(); - } - Box::new(iter::once(0).chain(std::iter::from_fn(move || { - x = x / 2; - if x == 0 { - None - } else { - Some(x) - } - }))) - } } )* } @@ -371,45 +323,14 @@ impl_arbitrary_for_integers! { macro_rules! impl_arbitrary_for_floats { ( $( $ty:ident : $unsigned:ty; )* ) => { $( - impl Arbitrary for $ty { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { - Ok(Self::from_bits(<$unsigned as Arbitrary>::arbitrary(u)?)) + impl<'a> Arbitrary<'a> for $ty { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Ok(Self::from_bits(<$unsigned as Arbitrary<'a>>::arbitrary(u)?)) } #[inline] fn size_hint(depth: usize) -> (usize, Option) { - <$unsigned as Arbitrary>::size_hint(depth) - } - - fn shrink(&self) -> Box> { - if *self == 0.0 { - empty() - } else if !self.is_finite() { - once(0.0) - } else { - let mut x = *self; - Box::new(iter::once(0.0).chain(iter::from_fn(move || { - // NB: do not test for zero like we do for integers - // because dividing by two until we reach a fixed - // point is NOT guaranteed to end at zero in - // non-default rounding modes of IEEE-754! - // - // For example, with 64-bit floats and the - // round-to-positive-infinity mode: - // - // 5e-324 / 2.0 == 5e-324 - // - // (5e-234 is the smallest postive number that can - // be precisely represented in a 64-bit float.) - let y = x; - x = x / 2.0; - if x == y { - None - } else { - Some(x) - } - }))) - } + <$unsigned as Arbitrary<'a>>::size_hint(depth) } } )* @@ -421,13 +342,13 @@ impl_arbitrary_for_floats! { f64: u64; } -impl Arbitrary for char { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a> Arbitrary<'a> for char { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { use std::char; const CHAR_END: u32 = 0x0011_000; // The size of the surrogate blocks const SURROGATES_START: u32 = 0xD800; - let mut c = ::arbitrary(u)? % CHAR_END; + let mut c = >::arbitrary(u)? % CHAR_END; if let Some(c) = char::from_u32(c) { return Ok(c); } else { @@ -440,66 +361,40 @@ impl Arbitrary for char { #[inline] fn size_hint(depth: usize) -> (usize, Option) { - ::size_hint(depth) - } - - fn shrink(&self) -> Box> { - let x = *self as u32; - Box::new(x.shrink().filter_map(|x| { - use std::convert::TryFrom; - char::try_from(x).ok() - })) + >::size_hint(depth) } } -impl Arbitrary for AtomicBool { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a> Arbitrary<'a> for AtomicBool { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { Arbitrary::arbitrary(u).map(Self::new) } #[inline] fn size_hint(depth: usize) -> (usize, Option) { - ::size_hint(depth) - } - - fn shrink(&self) -> Box> { - if self.load(Ordering::SeqCst) { - once(AtomicBool::new(false)) - } else { - empty() - } + >::size_hint(depth) } } -impl Arbitrary for AtomicIsize { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a> Arbitrary<'a> for AtomicIsize { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { Arbitrary::arbitrary(u).map(Self::new) } #[inline] fn size_hint(depth: usize) -> (usize, Option) { - ::size_hint(depth) - } - - fn shrink(&self) -> Box> { - let x = self.load(Ordering::SeqCst); - Box::new(x.shrink().map(Self::new)) + >::size_hint(depth) } } -impl Arbitrary for AtomicUsize { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a> Arbitrary<'a> for AtomicUsize { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { Arbitrary::arbitrary(u).map(Self::new) } #[inline] fn size_hint(depth: usize) -> (usize, Option) { - ::size_hint(depth) - } - - fn shrink(&self) -> Box> { - let x = self.load(Ordering::SeqCst); - Box::new(x.shrink().map(Self::new)) + >::size_hint(depth) } } @@ -511,11 +406,11 @@ macro_rules! impl_range { $fun:ident($fun_closure:expr), $size_hint_closure:expr ) => { - impl Arbitrary for $range + impl<'a, A> Arbitrary<'a> for $range where - A: Arbitrary + Clone + PartialOrd, + A: Arbitrary<'a> + Clone + PartialOrd, { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { let value: $value_ty = Arbitrary::arbitrary(u)?; Ok($fun(value, $fun_closure)) } @@ -524,11 +419,6 @@ macro_rules! impl_range { fn size_hint(depth: usize) -> (usize, Option) { $size_hint_closure(depth) } - - fn shrink(&self) -> Box> { - let value: $value_ty = $value_closure(self); - Box::new(value.shrink().map(|v| $fun(v, $fun_closure))) - } } }; } @@ -575,7 +465,7 @@ impl_range!( |depth| ::size_hint(depth) ); -fn bounded_range(bounds: (I, I), cb: CB) -> R +pub(crate) fn bounded_range(bounds: (I, I), cb: CB) -> R where CB: Fn((I, I)) -> R, I: PartialOrd, @@ -588,7 +478,7 @@ where cb((start, end)) } -fn unbounded_range(bound: I, cb: CB) -> R +pub(crate) fn unbounded_range(bound: I, cb: CB) -> R where CB: Fn(I) -> R, R: RangeBounds, @@ -596,8 +486,8 @@ where cb(bound) } -impl Arbitrary for Duration { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a> Arbitrary<'a> for Duration { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { Ok(Self::new( ::arbitrary(u)?, u.int_in_range(0..=999_999_999)?, @@ -611,19 +501,11 @@ impl Arbitrary for Duration { ::size_hint(depth), ) } - - fn shrink(&self) -> Box> { - Box::new( - (self.as_secs(), self.subsec_nanos()) - .shrink() - .map(|(secs, nanos)| Duration::new(secs, nanos % 1_000_000_000)), - ) - } } -impl Arbitrary for Option { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { - Ok(if ::arbitrary(u)? { +impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Option { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Ok(if >::arbitrary(u)? { Some(Arbitrary::arbitrary(u)?) } else { None @@ -637,19 +519,11 @@ impl Arbitrary for Option { crate::size_hint::or((0, Some(0)), ::size_hint(depth)), ) } - - fn shrink(&self) -> Box> { - if let Some(ref a) = *self { - Box::new(iter::once(None).chain(a.shrink().map(Some))) - } else { - empty() - } - } } -impl Arbitrary for std::result::Result { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { - Ok(if ::arbitrary(u)? { +impl<'a, A: Arbitrary<'a>, B: Arbitrary<'a>> Arbitrary<'a> for std::result::Result { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Ok(if >::arbitrary(u)? { Ok(::arbitrary(u)?) } else { Err(::arbitrary(u)?) @@ -666,13 +540,6 @@ impl Arbitrary for std::result::Result { ), ) } - - fn shrink(&self) -> Box> { - match *self { - Ok(ref a) => Box::new(a.shrink().map(Ok)), - Err(ref b) => Box::new(b.shrink().map(Err)), - } - } } macro_rules! arbitrary_tuple { @@ -680,13 +547,13 @@ macro_rules! arbitrary_tuple { ($last: ident $($xs: ident)*) => { arbitrary_tuple!($($xs)*); - impl<$($xs: Arbitrary,)* $last: Arbitrary> Arbitrary for ($($xs,)* $last,) { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { + impl<'a, $($xs: Arbitrary<'a>,)* $last: Arbitrary<'a>> Arbitrary<'a> for ($($xs,)* $last,) { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { Ok(($($xs::arbitrary(u)?,)* Arbitrary::arbitrary(u)?,)) } #[allow(unused_mut, non_snake_case)] - fn arbitrary_take_rest(mut u: Unstructured<'_>) -> Result { + fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result { $(let $xs = $xs::arbitrary(&mut u)?;)* let $last = $last::arbitrary_take_rest(u)?; Ok(($($xs,)* $last,)) @@ -699,15 +566,6 @@ macro_rules! arbitrary_tuple { $( <$xs as Arbitrary>::size_hint(depth) ),* ]) } - - #[allow(non_snake_case)] - fn shrink(&self) -> Box> { - let ( $( $xs, )* $last, ) = self; - let ( $( mut $xs, )* mut $last,) = ( $( $xs.shrink(), )* $last.shrink(),); - Box::new(iter::from_fn(move || { - Some(( $( $xs.next()? ,)* $last.next()?, )) - })) - } } }; } @@ -717,8 +575,8 @@ macro_rules! arbitrary_array { {$n:expr, ($t:ident, $a:ident) $(($ts:ident, $as:ident))*} => { arbitrary_array!{($n - 1), $(($ts, $as))*} - impl Arbitrary for [T; $n] { - fn arbitrary(u: &mut Unstructured<'_>) -> Result<[T; $n]> { + impl<'a, T: Arbitrary<'a>> Arbitrary<'a> for [T; $n] { + fn arbitrary(u: &mut Unstructured<'a>) -> Result<[T; $n]> { Ok([ Arbitrary::arbitrary(u)?, $(<$ts as Arbitrary>::arbitrary(u)?),* @@ -726,7 +584,7 @@ macro_rules! arbitrary_array { } #[allow(unused_mut)] - fn arbitrary_take_rest(mut u: Unstructured<'_>) -> Result<[T; $n]> { + fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result<[T; $n]> { $(let $as = $ts::arbitrary(&mut u)?;)* let last = Arbitrary::arbitrary_take_rest(u)?; @@ -742,41 +600,17 @@ macro_rules! arbitrary_array { $( <$ts as Arbitrary>::size_hint(depth) ),* ]) } - - #[allow(unused_mut)] // For the `[T; 1]` case. - fn shrink(&self) -> Box> { - let mut i = 0; - let mut shrinkers = [ - self[i].shrink(), - $({ - i += 1; - let t: &$ts = &self[i]; - t.shrink() - }),* - ]; - Box::new(iter::from_fn(move || { - let mut i = 0; - Some([ - shrinkers[i].next()?, - $({ - i += 1; - let t: $ts = shrinkers[i].next()?; - t - }),* - ]) - })) - } } }; ($n: expr,) => {}; } -impl Arbitrary for [T; 0] { - fn arbitrary(_: &mut Unstructured<'_>) -> Result<[T; 0]> { +impl<'a, T: Arbitrary<'a>> Arbitrary<'a> for [T; 0] { + fn arbitrary(_: &mut Unstructured<'a>) -> Result<[T; 0]> { Ok([]) } - fn arbitrary_take_rest(_: Unstructured<'_>) -> Result<[T; 0]> { + fn arbitrary_take_rest(_: Unstructured<'a>) -> Result<[T; 0]> { Ok([]) } @@ -784,10 +618,6 @@ impl Arbitrary for [T; 0] { fn size_hint(_: usize) -> (usize, Option) { crate::size_hint::and_all(&[]) } - - fn shrink(&self) -> Box> { - Box::new(iter::from_fn(|| None)) - } } arbitrary_array! { 32, (T, a) (T, b) (T, c) (T, d) (T, e) (T, f) (T, g) (T, h) @@ -796,41 +626,12 @@ arbitrary_array! { 32, (T, a) (T, b) (T, c) (T, d) (T, e) (T, f) (T, g) (T, h) (T, z) (T, aa) (T, ab) (T, ac) (T, ad) (T, ae) (T, af) (T, ag) } -fn shrink_collection<'a, T, A: Arbitrary>( - entries: impl Iterator, - f: impl Fn(&T) -> Box>, -) -> Box>> { - let entries: Vec<_> = entries.collect(); - if entries.is_empty() { - return empty(); - } - - let mut shrinkers: Vec> = vec![]; - let mut i = entries.len(); - loop { - shrinkers.push(entries.iter().take(i).map(&f).collect()); - i = i / 2; - if i == 0 { - break; - } - } - Box::new(iter::once(vec![]).chain(iter::from_fn(move || loop { - let mut shrinker = shrinkers.pop()?; - let x: Option> = shrinker.iter_mut().map(|s| s.next()).collect(); - if x.is_none() { - continue; - } - shrinkers.push(shrinker); - return x; - }))) -} - -impl Arbitrary for Vec { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Vec { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { u.arbitrary_iter()?.collect() } - fn arbitrary_take_rest(u: Unstructured<'_>) -> Result { + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { u.arbitrary_take_rest_iter()?.collect() } @@ -838,18 +639,14 @@ impl Arbitrary for Vec { fn size_hint(depth: usize) -> (usize, Option) { crate::size_hint::and(::size_hint(depth), (0, None)) } - - fn shrink(&self) -> Box> { - shrink_collection(self.iter(), |x| x.shrink()) - } } -impl Arbitrary for BTreeMap { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a, K: Arbitrary<'a> + Ord, V: Arbitrary<'a>> Arbitrary<'a> for BTreeMap { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { u.arbitrary_iter()?.collect() } - fn arbitrary_take_rest(u: Unstructured<'_>) -> Result { + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { u.arbitrary_take_rest_iter()?.collect() } @@ -857,20 +654,14 @@ impl Arbitrary for BTreeMap { fn size_hint(depth: usize) -> (usize, Option) { crate::size_hint::and(::size_hint(depth), (0, None)) } - - fn shrink(&self) -> Box> { - let collections = - shrink_collection(self.iter(), |(k, v)| Box::new(k.shrink().zip(v.shrink()))); - Box::new(collections.map(|entries| entries.into_iter().collect())) - } } -impl Arbitrary for BTreeSet { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a, A: Arbitrary<'a> + Ord> Arbitrary<'a> for BTreeSet { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { u.arbitrary_iter()?.collect() } - fn arbitrary_take_rest(u: Unstructured<'_>) -> Result { + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { u.arbitrary_take_rest_iter()?.collect() } @@ -878,19 +669,14 @@ impl Arbitrary for BTreeSet { fn size_hint(depth: usize) -> (usize, Option) { crate::size_hint::and(::size_hint(depth), (0, None)) } - - fn shrink(&self) -> Box> { - let collections = shrink_collection(self.iter(), |v| v.shrink()); - Box::new(collections.map(|entries| entries.into_iter().collect())) - } } -impl Arbitrary for BinaryHeap { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a, A: Arbitrary<'a> + Ord> Arbitrary<'a> for BinaryHeap { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { u.arbitrary_iter()?.collect() } - fn arbitrary_take_rest(u: Unstructured<'_>) -> Result { + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { u.arbitrary_take_rest_iter()?.collect() } @@ -898,19 +684,16 @@ impl Arbitrary for BinaryHeap { fn size_hint(depth: usize) -> (usize, Option) { crate::size_hint::and(::size_hint(depth), (0, None)) } - - fn shrink(&self) -> Box> { - let collections = shrink_collection(self.iter(), |v| v.shrink()); - Box::new(collections.map(|entries| entries.into_iter().collect())) - } } -impl Arbitrary for HashMap { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a, K: Arbitrary<'a> + Eq + ::std::hash::Hash, V: Arbitrary<'a>> Arbitrary<'a> + for HashMap +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { u.arbitrary_iter()?.collect() } - fn arbitrary_take_rest(u: Unstructured<'_>) -> Result { + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { u.arbitrary_take_rest_iter()?.collect() } @@ -918,20 +701,14 @@ impl Arbitrary for HashMap< fn size_hint(depth: usize) -> (usize, Option) { crate::size_hint::and(::size_hint(depth), (0, None)) } - - fn shrink(&self) -> Box> { - let collections = - shrink_collection(self.iter(), |(k, v)| Box::new(k.shrink().zip(v.shrink()))); - Box::new(collections.map(|entries| entries.into_iter().collect())) - } } -impl Arbitrary for HashSet { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a, A: Arbitrary<'a> + Eq + ::std::hash::Hash> Arbitrary<'a> for HashSet { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { u.arbitrary_iter()?.collect() } - fn arbitrary_take_rest(u: Unstructured<'_>) -> Result { + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { u.arbitrary_take_rest_iter()?.collect() } @@ -939,19 +716,14 @@ impl Arbitrary for HashSet { fn size_hint(depth: usize) -> (usize, Option) { crate::size_hint::and(::size_hint(depth), (0, None)) } - - fn shrink(&self) -> Box> { - let collections = shrink_collection(self.iter(), |v| v.shrink()); - Box::new(collections.map(|entries| entries.into_iter().collect())) - } } -impl Arbitrary for LinkedList { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for LinkedList { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { u.arbitrary_iter()?.collect() } - fn arbitrary_take_rest(u: Unstructured<'_>) -> Result { + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { u.arbitrary_take_rest_iter()?.collect() } @@ -959,19 +731,14 @@ impl Arbitrary for LinkedList { fn size_hint(depth: usize) -> (usize, Option) { crate::size_hint::and(::size_hint(depth), (0, None)) } - - fn shrink(&self) -> Box> { - let collections = shrink_collection(self.iter(), |v| v.shrink()); - Box::new(collections.map(|entries| entries.into_iter().collect())) - } } -impl Arbitrary for VecDeque { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for VecDeque { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { u.arbitrary_iter()?.collect() } - fn arbitrary_take_rest(u: Unstructured<'_>) -> Result { + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { u.arbitrary_take_rest_iter()?.collect() } @@ -979,19 +746,14 @@ impl Arbitrary for VecDeque { fn size_hint(depth: usize) -> (usize, Option) { crate::size_hint::and(::size_hint(depth), (0, None)) } - - fn shrink(&self) -> Box> { - let collections = shrink_collection(self.iter(), |v| v.shrink()); - Box::new(collections.map(|entries| entries.into_iter().collect())) - } } -impl Arbitrary for Cow<'static, A> +impl<'a, A> Arbitrary<'a> for Cow<'a, A> where A: ToOwned + ?Sized, - ::Owned: Arbitrary, + ::Owned: Arbitrary<'a>, { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { Arbitrary::arbitrary(u).map(Cow::Owned) } @@ -1001,22 +763,15 @@ where <::Owned as Arbitrary>::size_hint(depth) }) } - - fn shrink(&self) -> Box> { - match *self { - Cow::Owned(ref o) => Box::new(o.shrink().map(Cow::Owned)), - Cow::Borrowed(b) => Box::new(b.to_owned().shrink().map(Cow::Owned)), - } - } } -impl Arbitrary for String { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a> Arbitrary<'a> for &'a str { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { let size = u.arbitrary_len::()?; match str::from_utf8(&u.peek_bytes(size).unwrap()) { Ok(s) => { u.get_bytes(size).unwrap(); - Ok(s.into()) + Ok(s) } Err(e) => { let i = e.valid_up_to(); @@ -1025,12 +780,12 @@ impl Arbitrary for String { debug_assert!(str::from_utf8(valid).is_ok()); str::from_utf8_unchecked(valid) }; - Ok(s.into()) + Ok(s) } } } - fn arbitrary_take_rest(u: Unstructured<'_>) -> Result { + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { let bytes = u.take_rest(); str::from_utf8(bytes) .map_err(|_| Error::IncorrectFormat) @@ -1041,15 +796,25 @@ impl Arbitrary for String { fn size_hint(depth: usize) -> (usize, Option) { crate::size_hint::and(::size_hint(depth), (0, None)) } +} + +impl<'a> Arbitrary<'a> for String { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + <&str as Arbitrary>::arbitrary(u).map(Into::into) + } - fn shrink(&self) -> Box> { - let collections = shrink_collection(self.chars(), |ch| ch.shrink()); - Box::new(collections.map(|chars| chars.into_iter().collect())) + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + <&str as Arbitrary>::arbitrary_take_rest(u).map(Into::into) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + <&str as Arbitrary>::size_hint(depth) } } -impl Arbitrary for CString { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a> Arbitrary<'a> for CString { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { as Arbitrary>::arbitrary(u).map(|mut x| { x.retain(|&c| c != 0); Self::new(x).unwrap() @@ -1060,17 +825,10 @@ impl Arbitrary for CString { fn size_hint(depth: usize) -> (usize, Option) { as Arbitrary>::size_hint(depth) } - - fn shrink(&self) -> Box> { - let collections = shrink_collection(self.as_bytes().iter(), |b| { - Box::new(b.shrink().filter(|&b| b != 0)) - }); - Box::new(collections.map(|bytes| Self::new(bytes).unwrap())) - } } -impl Arbitrary for OsString { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a> Arbitrary<'a> for OsString { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { ::arbitrary(u).map(From::from) } @@ -1078,18 +836,10 @@ impl Arbitrary for OsString { fn size_hint(depth: usize) -> (usize, Option) { ::size_hint(depth) } - - fn shrink(&self) -> Box> { - match self.clone().into_string() { - Err(_) if self.is_empty() => empty(), - Err(_) => once(OsString::from("".to_string())), - Ok(s) => Box::new(s.shrink().map(From::from)), - } - } } -impl Arbitrary for PathBuf { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a> Arbitrary<'a> for PathBuf { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { ::arbitrary(u).map(From::from) } @@ -1097,15 +847,10 @@ impl Arbitrary for PathBuf { fn size_hint(depth: usize) -> (usize, Option) { ::size_hint(depth) } - - fn shrink(&self) -> Box> { - let s = self.clone().into_os_string(); - Box::new(s.shrink().map(From::from)) - } } -impl Arbitrary for Box { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Box { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { Arbitrary::arbitrary(u).map(Self::new) } @@ -1113,14 +858,10 @@ impl Arbitrary for Box { fn size_hint(depth: usize) -> (usize, Option) { crate::size_hint::recursion_guard(depth, |depth| ::size_hint(depth)) } - - fn shrink(&self) -> Box> { - Box::new((&**self).shrink().map(Self::new)) - } } -impl Arbitrary for Box<[A]> { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Box<[A]> { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { as Arbitrary>::arbitrary(u).map(|x| x.into_boxed_slice()) } @@ -1128,14 +869,10 @@ impl Arbitrary for Box<[A]> { fn size_hint(depth: usize) -> (usize, Option) { as Arbitrary>::size_hint(depth) } - - fn shrink(&self) -> Box> { - Box::new(shrink_collection(self.iter(), |x| x.shrink()).map(|v| v.into_boxed_slice())) - } } -impl Arbitrary for Box { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a> Arbitrary<'a> for Box { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { ::arbitrary(u).map(|x| x.into_boxed_str()) } @@ -1143,11 +880,6 @@ impl Arbitrary for Box { fn size_hint(depth: usize) -> (usize, Option) { ::size_hint(depth) } - - fn shrink(&self) -> Box> { - let collections = shrink_collection(self.chars(), |ch| ch.shrink()); - Box::new(collections.map(|chars| chars.into_iter().collect::().into_boxed_str())) - } } // impl Arbitrary for Box { @@ -1163,8 +895,8 @@ impl Arbitrary for Box { // } // } -impl Arbitrary for Arc { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Arc { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { Arbitrary::arbitrary(u).map(Self::new) } @@ -1172,14 +904,10 @@ impl Arbitrary for Arc { fn size_hint(depth: usize) -> (usize, Option) { crate::size_hint::recursion_guard(depth, |depth| ::size_hint(depth)) } - - fn shrink(&self) -> Box> { - Box::new((&**self).shrink().map(Self::new)) - } } -impl Arbitrary for Rc { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Rc { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { Arbitrary::arbitrary(u).map(Self::new) } @@ -1187,77 +915,54 @@ impl Arbitrary for Rc { fn size_hint(depth: usize) -> (usize, Option) { crate::size_hint::recursion_guard(depth, |depth| ::size_hint(depth)) } - - fn shrink(&self) -> Box> { - Box::new((&**self).shrink().map(Self::new)) - } } -impl Arbitrary for Cell { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Cell { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { Arbitrary::arbitrary(u).map(Self::new) } #[inline] fn size_hint(depth: usize) -> (usize, Option) { - ::size_hint(depth) + >::size_hint(depth) } - - // Note: can't implement `shrink` without either more trait bounds on `A` - // (copy or default) or `Cell::update`: - // https://github.com/rust-lang/rust/issues/50186 } -impl Arbitrary for RefCell { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for RefCell { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { Arbitrary::arbitrary(u).map(Self::new) } #[inline] fn size_hint(depth: usize) -> (usize, Option) { - ::size_hint(depth) - } - - fn shrink(&self) -> Box> { - let x = self.borrow(); - Box::new(x.shrink().map(Self::new)) + >::size_hint(depth) } } -impl Arbitrary for UnsafeCell { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for UnsafeCell { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { Arbitrary::arbitrary(u).map(Self::new) } #[inline] fn size_hint(depth: usize) -> (usize, Option) { - ::size_hint(depth) + >::size_hint(depth) } - - // We can't non-trivially (i.e. not an empty iterator) implement `shrink` in - // a safe way, since we don't have a safe way to get the inner value. } -impl Arbitrary for Mutex { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Mutex { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { Arbitrary::arbitrary(u).map(Self::new) } #[inline] fn size_hint(depth: usize) -> (usize, Option) { - ::size_hint(depth) - } - - fn shrink(&self) -> Box> { - match self.lock() { - Err(_) => empty(), - Ok(g) => Box::new(g.shrink().map(Self::new)), - } + >::size_hint(depth) } } -impl Arbitrary for iter::Empty { - fn arbitrary(_: &mut Unstructured<'_>) -> Result { +impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for iter::Empty { + fn arbitrary(_: &mut Unstructured<'a>) -> Result { Ok(iter::empty()) } @@ -1265,12 +970,10 @@ impl Arbitrary for iter::Empty { fn size_hint(_depth: usize) -> (usize, Option) { (0, Some(0)) } - - // Nothing to shrink here. } -impl Arbitrary for ::std::marker::PhantomData { - fn arbitrary(_: &mut Unstructured<'_>) -> Result { +impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for ::std::marker::PhantomData { + fn arbitrary(_: &mut Unstructured<'a>) -> Result { Ok(::std::marker::PhantomData) } @@ -1278,23 +981,16 @@ impl Arbitrary for ::std::marker::PhantomData { fn size_hint(_depth: usize) -> (usize, Option) { (0, Some(0)) } - - // Nothing to shrink here. } -impl Arbitrary for ::std::num::Wrapping { - fn arbitrary(u: &mut Unstructured<'_>) -> Result { +impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for ::std::num::Wrapping { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { Arbitrary::arbitrary(u).map(::std::num::Wrapping) } #[inline] fn size_hint(depth: usize) -> (usize, Option) { - ::size_hint(depth) - } - - fn shrink(&self) -> Box> { - let ref x = self.0; - Box::new(x.shrink().map(::std::num::Wrapping)) + >::size_hint(depth) } } @@ -1361,113 +1057,11 @@ mod test { } #[test] - fn shrink_tuple() { - let tup = (10, 20, 30); - assert_eq!( - tup.shrink().collect::>(), - [(0, 0, 0), (5, 10, 15), (2, 5, 7), (1, 2, 3)] - ); - } - - #[test] - fn shrink_array() { - let tup = [10, 20, 30]; - assert_eq!( - tup.shrink().collect::>(), - [[0, 0, 0], [5, 10, 15], [2, 5, 7], [1, 2, 3]] - ); - } - - #[test] - fn shrink_vec() { - let v = vec![4, 4, 4, 4]; - assert_eq!( - v.shrink().collect::>(), - [ - vec![], - vec![0], - vec![2], - vec![1], - vec![0, 0], - vec![2, 2], - vec![1, 1], - vec![0, 0, 0, 0], - vec![2, 2, 2, 2], - vec![1, 1, 1, 1] - ] - ); - } - - #[test] - fn shrink_string() { - let s = "aaaa".to_string(); - assert_eq!( - s.shrink().collect::>(), - [ - "", - "\u{0}", - "0", - "\u{18}", - "\u{c}", - "\u{6}", - "\u{3}", - "\u{1}", - "\u{0}\u{0}", - "00", - "\u{18}\u{18}", - "\u{c}\u{c}", - "\u{6}\u{6}", - "\u{3}\u{3}", - "\u{1}\u{1}", - "\u{0}\u{0}\u{0}\u{0}", - "0000", - "\u{18}\u{18}\u{18}\u{18}", - "\u{c}\u{c}\u{c}\u{c}", - "\u{6}\u{6}\u{6}\u{6}", - "\u{3}\u{3}\u{3}\u{3}", - "\u{1}\u{1}\u{1}\u{1}" - ] - .iter() - .map(|s| s.to_string()) - .collect::>(), - ); - } - - #[test] - fn shrink_cstring() { - let s = CString::new(b"aaaa".to_vec()).unwrap(); + fn size_hint_for_tuples() { assert_eq!( - s.shrink().collect::>(), - [ - &[][..], - &[b'0'][..], - &[0x18][..], - &[0x0c][..], - &[0x06][..], - &[0x03][..], - &[0x01][..], - &[b'0', b'0'][..], - &[0x18, 0x18][..], - &[0x0c, 0x0c][..], - &[0x06, 0x06][..], - &[0x03, 0x03][..], - &[0x01, 0x01][..], - &[b'0', b'0', b'0', b'0'][..], - &[0x18, 0x18, 0x18, 0x18][..], - &[0x0c, 0x0c, 0x0c, 0x0c][..], - &[0x06, 0x06, 0x06, 0x06][..], - &[0x03, 0x03, 0x03, 0x03][..], - &[0x01, 0x01, 0x01, 0x01][..], - ] - .iter() - .map(|s| CString::new(s.to_vec()).unwrap()) - .collect::>(), + (7, Some(7)), + <(bool, u16, i32) as Arbitrary<'_>>::size_hint(0) ); - } - - #[test] - fn size_hint_for_tuples() { - assert_eq!((7, Some(7)), <(bool, u16, i32) as Arbitrary>::size_hint(0)); assert_eq!( (1 + mem::size_of::(), None), <(u8, Vec) as Arbitrary>::size_hint(0) diff --git a/src/size_hint.rs b/src/size_hint.rs index e2aecc2..045c148 100644 --- a/src/size_hint.rs +++ b/src/size_hint.rs @@ -8,9 +8,6 @@ /// size hint. /// /// Otherwise, returns the default size hint: `(0, None)`. -/// -/// See the [docs for `Arbitrary::shrink`][crate::Arbitrary::shrink] for example -/// usage. #[inline] pub fn recursion_guard( depth: usize, diff --git a/src/unstructured.rs b/src/unstructured.rs index cffde0a..b7ee557 100644 --- a/src/unstructured.rs +++ b/src/unstructured.rs @@ -165,9 +165,9 @@ impl<'a> Unstructured<'a> { /// ``` pub fn arbitrary(&mut self) -> Result where - A: Arbitrary, + A: Arbitrary<'a>, { - ::arbitrary(self) + >::arbitrary(self) } /// Get the number of elements to insert when building up a collection of @@ -190,11 +190,11 @@ impl<'a> Unstructured<'a> { /// # pub fn insert(&mut self, element: T) {} /// # } /// - /// impl Arbitrary for MyCollection + /// impl<'a, T> Arbitrary<'a> for MyCollection /// where - /// T: Arbitrary, + /// T: Arbitrary<'a>, /// { - /// fn arbitrary(u: &mut Unstructured<'_>) -> Result { + /// fn arbitrary(u: &mut Unstructured<'a>) -> Result { /// // Get the number of `T`s we should insert into our collection. /// let len = u.arbitrary_len::()?; /// @@ -211,7 +211,7 @@ impl<'a> Unstructured<'a> { /// ``` pub fn arbitrary_len(&mut self) -> Result where - ElementType: Arbitrary, + ElementType: Arbitrary<'a>, { let byte_size = self.arbitrary_byte_size()?; let (lower, upper) = ::size_hint(0); @@ -480,7 +480,7 @@ impl<'a> Unstructured<'a> { /// /// This is useful for implementing [`Arbitrary::arbitrary`] on collections /// since the implementation is simply `u.arbitrary_iter()?.collect()` - pub fn arbitrary_iter<'b, ElementType: Arbitrary>( + pub fn arbitrary_iter<'b, ElementType: Arbitrary<'a>>( &'b mut self, ) -> Result> { Ok(ArbitraryIter { @@ -494,7 +494,7 @@ impl<'a> Unstructured<'a> { /// /// This is useful for implementing [`Arbitrary::arbitrary_take_rest`] on collections /// since the implementation is simply `u.arbitrary_take_rest_iter()?.collect()` - pub fn arbitrary_take_rest_iter( + pub fn arbitrary_take_rest_iter>( self, ) -> Result> { let (lower, upper) = ElementType::size_hint(0); @@ -516,7 +516,7 @@ pub struct ArbitraryIter<'a, 'b, ElementType> { _marker: PhantomData, } -impl<'a, 'b, ElementType: Arbitrary> Iterator for ArbitraryIter<'a, 'b, ElementType> { +impl<'a, 'b, ElementType: Arbitrary<'a>> Iterator for ArbitraryIter<'a, 'b, ElementType> { type Item = Result; fn next(&mut self) -> Option> { let keep_going = self.u.arbitrary().unwrap_or(false); @@ -535,7 +535,7 @@ pub struct ArbitraryTakeRestIter<'a, ElementType> { _marker: PhantomData, } -impl<'a, ElementType: Arbitrary> Iterator for ArbitraryTakeRestIter<'a, ElementType> { +impl<'a, ElementType: Arbitrary<'a>> Iterator for ArbitraryTakeRestIter<'a, ElementType> { type Item = Result; fn next(&mut self) -> Option> { if let Some(mut u) = self.u.take() { diff --git a/tests/derive.rs b/tests/derive.rs index 7f1e85e..9dfbbd5 100644 --- a/tests/derive.rs +++ b/tests/derive.rs @@ -2,7 +2,7 @@ use arbitrary::*; -fn arbitrary_from(input: &[u8]) -> T { +fn arbitrary_from<'a, T: Arbitrary<'a>>(input: &'a [u8]) -> T { let mut buf = Unstructured::new(input); T::arbitrary(&mut buf).expect("can create arbitrary instance OK") } @@ -21,15 +21,6 @@ fn struct_with_named_fields() { assert_eq!(rgb.g, 5); assert_eq!(rgb.b, 6); - assert_eq!( - rgb.shrink().collect::>(), - vec![ - Rgb { r: 0, g: 0, b: 0 }, - Rgb { r: 2, g: 2, b: 3 }, - Rgb { r: 1, g: 1, b: 1 } - ] - ); - assert_eq!((3, Some(3)), ::size_hint(0)); } @@ -46,11 +37,6 @@ fn tuple_struct() { assert_eq!(s.0, 42); assert_eq!(s.1, true); - for ((a, b), s) in 42.shrink().zip(true.shrink()).zip(s.shrink()) { - assert_eq!(a, s.0); - assert_eq!(b, s.1); - } - assert_eq!((2, Some(2)), ::size_hint(0)); } @@ -106,36 +92,16 @@ fn derive_enum() { match e { MyEnum::Unit => { saw_unit = true; - assert_eq!(e.shrink().count(), 0); } MyEnum::Tuple(a, b) => { saw_tuple = true; assert_eq!(a, arbitrary_from(&raw[4..5])); assert_eq!(b, arbitrary_from(&raw[5..])); - - for ((a, b), e) in a.shrink().zip(b.shrink()).zip(e.shrink()) { - match e { - MyEnum::Tuple(c, d) => { - assert_eq!(a, c); - assert_eq!(b, d); - } - _ => panic!("should never shrink to a different variant"), - } - } } MyEnum::Struct { a, b } => { saw_struct = true; assert_eq!(a, arbitrary_from(&raw[4..8])); assert_eq!(b, arbitrary_from(&raw[8..])); - for ((a, b), e) in a.shrink().zip(b.shrink()).zip(e.shrink()) { - match e { - MyEnum::Struct { a: c, b: d } => { - assert_eq!(a, c); - assert_eq!(b, d); - } - _ => panic!("should never shrink to a different variant"), - } - } } } } @@ -184,3 +150,39 @@ fn generics() { assert_eq!(lower, 4); assert_eq!(upper, Some(4)); } + +#[derive(Arbitrary, Debug)] +struct OneLifetime<'a> { + alpha: &'a str, +} + +#[test] +fn one_lifetime() { + // Last byte is used for length + let raw: Vec = vec![97, 98, 99, 100, 3]; + let lifetime: OneLifetime = arbitrary_from(&raw); + assert_eq!("abc", lifetime.alpha); + + let (lower, upper) = ::size_hint(0); + assert_eq!(lower, 8); + assert_eq!(upper, None); +} + +#[derive(Arbitrary, Debug)] +struct TwoLifetimes<'a, 'b> { + alpha: &'a str, + beta: &'b str, +} + +#[test] +fn two_lifetimes() { + // Last byte is used for length + let raw: Vec = vec![97, 98, 99, 100, 101, 102, 103, 3]; + let lifetime: TwoLifetimes = arbitrary_from(&raw); + assert_eq!("abc", lifetime.alpha); + assert_eq!("def", lifetime.beta); + + let (lower, upper) = ::size_hint(0); + assert_eq!(lower, 16); + assert_eq!(upper, None); +}