Skip to content

Commit a3855f2

Browse files
committed
Introduce SizeHint and Context replacing Result<(usize, Option<usize>)>.
Introducing the `SizeHint` type provides these advantages: * Easier to construct by composition, using `+` and `|` or methods. * More self-explanatory. * Distinguishes between “unknown size” and “known to be unbounded” to aid debugging. The `Context` instead of `depth` provides these advantages: * Fully bounded computation with no dependence on the recursion breadth. * Elimination of `Result`, making `size_hint()` implementors simpler and allowing reporting of partially-known lower bounds rather than discarding all information on error. Since there are no longer any `Result`s, `try_size_hint()` is of course gone, making it easier to correctly implement the trait. But that could also have been done by adding the `Result` return to `size_hint()` if we were keeping it. Also, while I was touching the macro code, I made all the crate paths absolute (`::arbitrary`), as they should be for the maximum compatibility.
1 parent d36482c commit a3855f2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+709
-603
lines changed

derive/src/lib.rs

Lines changed: 24 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ fn expand_derive_arbitrary(input: syn::DeriveInput) -> Result<TokenStream> {
6464
}
6565

6666
#[automatically_derived]
67-
impl #impl_generics arbitrary::Arbitrary<#lifetime_without_bounds> for #name #ty_generics #where_clause {
67+
impl #impl_generics ::arbitrary::Arbitrary<#lifetime_without_bounds> for #name #ty_generics #where_clause {
6868
#arbitrary_method
6969
#size_hint_method
7070
}
@@ -141,7 +141,7 @@ fn add_trait_bounds(mut generics: Generics, lifetime: LifetimeParam) -> Generics
141141
if let GenericParam::Type(type_param) = param {
142142
type_param
143143
.bounds
144-
.push(parse_quote!(arbitrary::Arbitrary<#lifetime>));
144+
.push(parse_quote!(::arbitrary::Arbitrary<#lifetime>));
145145
}
146146
}
147147
generics
@@ -156,7 +156,7 @@ fn with_recursive_count_guard(
156156
if guard_against_recursion {
157157
#recursive_count.with(|count| {
158158
if count.get() > 0 {
159-
return Err(arbitrary::Error::NotEnoughData);
159+
return Err(::arbitrary::Error::NotEnoughData);
160160
}
161161
count.set(count.get() + 1);
162162
Ok(())
@@ -194,11 +194,11 @@ fn gen_arbitrary_method(
194194
with_recursive_count_guard(recursive_count, quote! { Ok(#ident #arbitrary_take_rest) });
195195

196196
Ok(quote! {
197-
fn arbitrary(u: &mut arbitrary::Unstructured<#lifetime>) -> arbitrary::Result<Self> {
197+
fn arbitrary(u: &mut ::arbitrary::Unstructured<#lifetime>) -> ::arbitrary::Result<Self> {
198198
#body
199199
}
200200

201-
fn arbitrary_take_rest(mut u: arbitrary::Unstructured<#lifetime>) -> arbitrary::Result<Self> {
201+
fn arbitrary_take_rest(mut u: ::arbitrary::Unstructured<#lifetime>) -> ::arbitrary::Result<Self> {
202202
#take_rest_body
203203
}
204204
})
@@ -225,7 +225,7 @@ fn gen_arbitrary_method(
225225
// Use a multiply + shift to generate a ranged random number
226226
// with slight bias. For details, see:
227227
// https://lemire.me/blog/2016/06/30/fast-random-shuffling
228-
Ok(match (u64::from(<u32 as arbitrary::Arbitrary>::arbitrary(#unstructured)?) * #count) >> 32 {
228+
Ok(match (u64::from(<u32 as ::arbitrary::Arbitrary>::arbitrary(#unstructured)?) * #count) >> 32 {
229229
#(#variants,)*
230230
_ => unreachable!()
231231
})
@@ -279,11 +279,11 @@ fn gen_arbitrary_method(
279279
let arbitrary_take_rest = arbitrary_enum_method(recursive_count, quote! { &mut u }, &variants_take_rest);
280280

281281
quote! {
282-
fn arbitrary(u: &mut arbitrary::Unstructured<#lifetime>) -> arbitrary::Result<Self> {
282+
fn arbitrary(u: &mut ::arbitrary::Unstructured<#lifetime>) -> ::arbitrary::Result<Self> {
283283
#arbitrary
284284
}
285285

286-
fn arbitrary_take_rest(mut u: arbitrary::Unstructured<#lifetime>) -> arbitrary::Result<Self> {
286+
fn arbitrary_take_rest(mut u: ::arbitrary::Unstructured<#lifetime>) -> ::arbitrary::Result<Self> {
287287
#arbitrary_take_rest
288288
}
289289
}
@@ -344,9 +344,9 @@ fn construct_take_rest(fields: &Fields) -> Result<TokenStream> {
344344
FieldConstructor::Default => quote!(::core::default::Default::default()),
345345
FieldConstructor::Arbitrary => {
346346
if idx + 1 == fields.len() {
347-
quote! { arbitrary::Arbitrary::arbitrary_take_rest(u)? }
347+
quote! { ::arbitrary::Arbitrary::arbitrary_take_rest(u)? }
348348
} else {
349-
quote! { arbitrary::Arbitrary::arbitrary(&mut u)? }
349+
quote! { ::arbitrary::Arbitrary::arbitrary(&mut u)? }
350350
}
351351
}
352352
FieldConstructor::With(function_or_closure) => quote!((#function_or_closure)(&mut u)?),
@@ -364,41 +364,36 @@ fn gen_size_hint_method(input: &DeriveInput) -> Result<TokenStream> {
364364
determine_field_constructor(f).map(|field_constructor| {
365365
match field_constructor {
366366
FieldConstructor::Default | FieldConstructor::Value(_) => {
367-
quote!(Ok((0, Some(0))))
367+
quote!(::arbitrary::SizeHint::exactly(0))
368368
}
369369
FieldConstructor::Arbitrary => {
370-
quote! { <#ty as arbitrary::Arbitrary>::try_size_hint(depth) }
370+
quote! { context.get::<#ty>() }
371371
}
372372

373373
// Note that in this case it's hard to determine what size_hint must be, so size_of::<T>() is
374374
// just an educated guess, although it's gonna be inaccurate for dynamically
375375
// allocated types (Vec, HashMap, etc.).
376376
FieldConstructor::With(_) => {
377-
quote! { Ok((::core::mem::size_of::<#ty>(), None)) }
377+
quote! { ::arbitrary::SizeHint::at_least(::core::mem::size_of::<#ty>()) }
378378
}
379379
}
380380
})
381381
})
382382
.collect::<Result<Vec<TokenStream>>>()
383383
.map(|hints| {
384384
quote! {
385-
Ok(arbitrary::size_hint::and_all(&[
386-
#( #hints? ),*
387-
]))
385+
::arbitrary::SizeHint::and_all(&[
386+
#( #hints ),*
387+
])
388388
}
389389
})
390390
};
391391
let size_hint_structlike = |fields: &Fields| {
392392
size_hint_fields(fields).map(|hint| {
393393
quote! {
394394
#[inline]
395-
fn size_hint(depth: usize) -> (usize, ::core::option::Option<usize>) {
396-
Self::try_size_hint(depth).unwrap_or_default()
397-
}
398-
399-
#[inline]
400-
fn try_size_hint(depth: usize) -> ::core::result::Result<(usize, ::core::option::Option<usize>), arbitrary::MaxRecursionReached> {
401-
arbitrary::size_hint::try_recursion_guard(depth, |depth| #hint)
395+
fn size_hint(context: &::arbitrary::size_hint::Context) -> ::arbitrary::size_hint::SizeHint {
396+
#hint
402397
}
403398
}
404399
})
@@ -418,17 +413,12 @@ fn gen_size_hint_method(input: &DeriveInput) -> Result<TokenStream> {
418413
.collect::<Result<Vec<TokenStream>>>()
419414
.map(|variants| {
420415
quote! {
421-
fn size_hint(depth: usize) -> (usize, ::core::option::Option<usize>) {
422-
Self::try_size_hint(depth).unwrap_or_default()
423-
}
424416
#[inline]
425-
fn try_size_hint(depth: usize) -> ::core::result::Result<(usize, ::core::option::Option<usize>), arbitrary::MaxRecursionReached> {
426-
Ok(arbitrary::size_hint::and(
427-
<u32 as arbitrary::Arbitrary>::try_size_hint(depth)?,
428-
arbitrary::size_hint::try_recursion_guard(depth, |depth| {
429-
Ok(arbitrary::size_hint::or_all(&[ #( #variants? ),* ]))
430-
})?,
431-
))
417+
fn size_hint(context: &::arbitrary::size_hint::Context) -> ::arbitrary::size_hint::SizeHint {
418+
::arbitrary::SizeHint::and(
419+
<u32 as ::arbitrary::Arbitrary>::size_hint(context),
420+
::arbitrary::SizeHint::or_all(&[ #( #variants ),* ])
421+
)
432422
}
433423
}
434424
}),
@@ -438,7 +428,7 @@ fn gen_size_hint_method(input: &DeriveInput) -> Result<TokenStream> {
438428
fn gen_constructor_for_field(field: &Field) -> Result<TokenStream> {
439429
let ctor = match determine_field_constructor(field)? {
440430
FieldConstructor::Default => quote!(::core::default::Default::default()),
441-
FieldConstructor::Arbitrary => quote!(arbitrary::Arbitrary::arbitrary(u)?),
431+
FieldConstructor::Arbitrary => quote!(::arbitrary::Arbitrary::arbitrary(u)?),
442432
FieldConstructor::With(function_or_closure) => quote!((#function_or_closure)(u)?),
443433
FieldConstructor::Value(value) => quote!(#value),
444434
};

src/foreign/alloc/borrow.rs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,7 @@ where
1313
}
1414

1515
#[inline]
16-
fn size_hint(depth: usize) -> (usize, Option<usize>) {
17-
Self::try_size_hint(depth).unwrap_or_default()
18-
}
19-
20-
#[inline]
21-
fn try_size_hint(depth: usize) -> Result<(usize, Option<usize>), crate::MaxRecursionReached> {
22-
size_hint::try_recursion_guard(depth, |depth| {
23-
<<A as ToOwned>::Owned as Arbitrary>::try_size_hint(depth)
24-
})
16+
fn size_hint(context: &size_hint::Context) -> size_hint::SizeHint {
17+
<<A as ToOwned>::Owned as Arbitrary>::size_hint(context)
2518
}
2619
}

src/foreign/alloc/boxed.rs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,8 @@ where
1212
}
1313

1414
#[inline]
15-
fn size_hint(depth: usize) -> (usize, Option<usize>) {
16-
Self::try_size_hint(depth).unwrap_or_default()
17-
}
18-
19-
#[inline]
20-
fn try_size_hint(depth: usize) -> Result<(usize, Option<usize>), crate::MaxRecursionReached> {
21-
size_hint::try_recursion_guard(depth, <A as Arbitrary>::try_size_hint)
15+
fn size_hint(context: &size_hint::Context) -> size_hint::SizeHint {
16+
context.get::<A>()
2217
}
2318
}
2419

@@ -35,8 +30,8 @@ where
3530
}
3631

3732
#[inline]
38-
fn size_hint(_depth: usize) -> (usize, Option<usize>) {
39-
(0, None)
33+
fn size_hint(_context: &size_hint::Context) -> size_hint::SizeHint {
34+
size_hint::SizeHint::at_least(0)
4035
}
4136
}
4237

@@ -46,7 +41,8 @@ impl<'a> Arbitrary<'a> for Box<str> {
4641
}
4742

4843
#[inline]
49-
fn size_hint(depth: usize) -> (usize, Option<usize>) {
50-
<String as Arbitrary>::size_hint(depth)
44+
fn size_hint(context: &size_hint::Context) -> size_hint::SizeHint {
45+
// known non-recursive
46+
<String as Arbitrary>::size_hint(context)
5147
}
5248
}

src/foreign/alloc/collections/binary_heap.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use {
2-
crate::{Arbitrary, Result, Unstructured},
2+
crate::{size_hint, Arbitrary, Result, Unstructured},
33
std::collections::binary_heap::BinaryHeap,
44
};
55

@@ -16,7 +16,7 @@ where
1616
}
1717

1818
#[inline]
19-
fn size_hint(_depth: usize) -> (usize, Option<usize>) {
20-
(0, None)
19+
fn size_hint(_context: &size_hint::Context) -> size_hint::SizeHint {
20+
size_hint::SizeHint::at_least(0)
2121
}
2222
}

src/foreign/alloc/collections/btree_map.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use {
2-
crate::{Arbitrary, Result, Unstructured},
2+
crate::{size_hint, Arbitrary, Result, Unstructured},
33
std::collections::btree_map::BTreeMap,
44
};
55

@@ -17,7 +17,7 @@ where
1717
}
1818

1919
#[inline]
20-
fn size_hint(_depth: usize) -> (usize, Option<usize>) {
21-
(0, None)
20+
fn size_hint(_context: &size_hint::Context) -> size_hint::SizeHint {
21+
size_hint::SizeHint::at_least(0)
2222
}
2323
}

src/foreign/alloc/collections/btree_set.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use {
2-
crate::{Arbitrary, Result, Unstructured},
2+
crate::{size_hint, Arbitrary, Result, Unstructured},
33
std::collections::btree_set::BTreeSet,
44
};
55

@@ -16,7 +16,7 @@ where
1616
}
1717

1818
#[inline]
19-
fn size_hint(_depth: usize) -> (usize, Option<usize>) {
20-
(0, None)
19+
fn size_hint(_context: &size_hint::Context) -> size_hint::SizeHint {
20+
size_hint::SizeHint::at_least(0)
2121
}
2222
}

src/foreign/alloc/collections/linked_list.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use {
2-
crate::{Arbitrary, Result, Unstructured},
2+
crate::{size_hint, Arbitrary, Result, Unstructured},
33
std::collections::linked_list::LinkedList,
44
};
55

@@ -16,7 +16,7 @@ where
1616
}
1717

1818
#[inline]
19-
fn size_hint(_depth: usize) -> (usize, Option<usize>) {
20-
(0, None)
19+
fn size_hint(_context: &size_hint::Context) -> size_hint::SizeHint {
20+
size_hint::SizeHint::at_least(0)
2121
}
2222
}

src/foreign/alloc/collections/vec_deque.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use {
2-
crate::{Arbitrary, Result, Unstructured},
2+
crate::{size_hint, Arbitrary, Result, Unstructured},
33
std::collections::vec_deque::VecDeque,
44
};
55

@@ -16,7 +16,7 @@ where
1616
}
1717

1818
#[inline]
19-
fn size_hint(_depth: usize) -> (usize, Option<usize>) {
20-
(0, None)
19+
fn size_hint(_context: &size_hint::Context) -> size_hint::SizeHint {
20+
size_hint::SizeHint::at_least(0)
2121
}
2222
}

src/foreign/alloc/ffi/c_str.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use {
2-
crate::{Arbitrary, Result, Unstructured},
2+
crate::{size_hint, Arbitrary, Result, Unstructured},
33
std::ffi::CString,
44
};
55

@@ -13,7 +13,8 @@ impl<'a> Arbitrary<'a> for CString {
1313
}
1414

1515
#[inline]
16-
fn size_hint(depth: usize) -> (usize, Option<usize>) {
17-
<Vec<u8> as Arbitrary>::size_hint(depth)
16+
fn size_hint(context: &size_hint::Context) -> size_hint::SizeHint {
17+
// known non-recursive
18+
<Vec<u8> as Arbitrary>::size_hint(context)
1819
}
1920
}

src/foreign/alloc/rc.rs

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,8 @@ where
1212
}
1313

1414
#[inline]
15-
fn size_hint(depth: usize) -> (usize, Option<usize>) {
16-
Self::try_size_hint(depth).unwrap_or_default()
17-
}
18-
19-
#[inline]
20-
fn try_size_hint(depth: usize) -> Result<(usize, Option<usize>), crate::MaxRecursionReached> {
21-
size_hint::try_recursion_guard(depth, <A as Arbitrary>::try_size_hint)
15+
fn size_hint(context: &size_hint::Context) -> size_hint::SizeHint {
16+
context.get::<A>()
2217
}
2318
}
2419

@@ -35,8 +30,8 @@ where
3530
}
3631

3732
#[inline]
38-
fn size_hint(_depth: usize) -> (usize, Option<usize>) {
39-
(0, None)
33+
fn size_hint(_context: &size_hint::Context) -> size_hint::SizeHint {
34+
size_hint::SizeHint::at_least(0)
4035
}
4136
}
4237

@@ -46,7 +41,7 @@ impl<'a> Arbitrary<'a> for Rc<str> {
4641
}
4742

4843
#[inline]
49-
fn size_hint(depth: usize) -> (usize, Option<usize>) {
50-
<&str as Arbitrary>::size_hint(depth)
44+
fn size_hint(context: &size_hint::Context) -> size_hint::SizeHint {
45+
<&str as Arbitrary>::size_hint(context)
5146
}
5247
}

0 commit comments

Comments
 (0)