• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use {
2     crate::{size_hint, Arbitrary, MaxRecursionReached, Result, Unstructured},
3     core::{
4         mem,
5         ops::{Bound, Range, RangeBounds, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive},
6     },
7 };
8 
9 macro_rules! impl_range {
10     (
11         $range:ty,
12         $value_closure:expr,
13         $value_ty:ty,
14         $fun:ident($fun_closure:expr),
15         $size_hint_closure:expr
16     ) => {
17         impl<'a, A> Arbitrary<'a> for $range
18         where
19             A: Arbitrary<'a> + Clone + PartialOrd,
20         {
21             fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
22                 let value: $value_ty = Arbitrary::arbitrary(u)?;
23                 Ok($fun(value, $fun_closure))
24             }
25 
26             #[inline]
27             fn size_hint(depth: usize) -> (usize, Option<usize>) {
28                 Self::try_size_hint(depth).unwrap_or_default()
29             }
30 
31             #[inline]
32             fn try_size_hint(depth: usize) -> Result<(usize, Option<usize>), MaxRecursionReached> {
33                 #[allow(clippy::redundant_closure_call)]
34                 $size_hint_closure(depth)
35             }
36         }
37     };
38 }
39 impl_range!(
40     Range<A>,
41     |r: &Range<A>| (r.start.clone(), r.end.clone()),
42     (A, A),
43     bounded_range(|(a, b)| a..b),
44     |depth| Ok(crate::size_hint::and(
45         <A as Arbitrary>::try_size_hint(depth)?,
46         <A as Arbitrary>::try_size_hint(depth)?,
47     ))
48 );
49 impl_range!(
50     RangeFrom<A>,
51     |r: &RangeFrom<A>| r.start.clone(),
52     A,
53     unbounded_range(|a| a..),
54     |depth| <A as Arbitrary>::try_size_hint(depth)
55 );
56 impl_range!(
57     RangeInclusive<A>,
58     |r: &RangeInclusive<A>| (r.start().clone(), r.end().clone()),
59     (A, A),
60     bounded_range(|(a, b)| a..=b),
61     |depth| Ok(crate::size_hint::and(
62         <A as Arbitrary>::try_size_hint(depth)?,
63         <A as Arbitrary>::try_size_hint(depth)?,
64     ))
65 );
66 impl_range!(
67     RangeTo<A>,
68     |r: &RangeTo<A>| r.end.clone(),
69     A,
70     unbounded_range(|b| ..b),
71     |depth| <A as Arbitrary>::try_size_hint(depth)
72 );
73 impl_range!(
74     RangeToInclusive<A>,
75     |r: &RangeToInclusive<A>| r.end.clone(),
76     A,
77     unbounded_range(|b| ..=b),
78     |depth| <A as Arbitrary>::try_size_hint(depth)
79 );
80 
bounded_range<CB, I, R>(bounds: (I, I), cb: CB) -> R where CB: Fn((I, I)) -> R, I: PartialOrd, R: RangeBounds<I>,81 pub(crate) fn bounded_range<CB, I, R>(bounds: (I, I), cb: CB) -> R
82 where
83     CB: Fn((I, I)) -> R,
84     I: PartialOrd,
85     R: RangeBounds<I>,
86 {
87     let (mut start, mut end) = bounds;
88     if start > end {
89         mem::swap(&mut start, &mut end);
90     }
91     cb((start, end))
92 }
93 
unbounded_range<CB, I, R>(bound: I, cb: CB) -> R where CB: Fn(I) -> R, R: RangeBounds<I>,94 pub(crate) fn unbounded_range<CB, I, R>(bound: I, cb: CB) -> R
95 where
96     CB: Fn(I) -> R,
97     R: RangeBounds<I>,
98 {
99     cb(bound)
100 }
101 
102 impl<'a, A> Arbitrary<'a> for Bound<A>
103 where
104     A: Arbitrary<'a>,
105 {
arbitrary(u: &mut Unstructured<'a>) -> Result<Self>106     fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
107         match u.int_in_range::<u8>(0..=2)? {
108             0 => Ok(Bound::Included(A::arbitrary(u)?)),
109             1 => Ok(Bound::Excluded(A::arbitrary(u)?)),
110             2 => Ok(Bound::Unbounded),
111             _ => unreachable!(),
112         }
113     }
114 
115     #[inline]
size_hint(depth: usize) -> (usize, Option<usize>)116     fn size_hint(depth: usize) -> (usize, Option<usize>) {
117         Self::try_size_hint(depth).unwrap_or_default()
118     }
119 
120     #[inline]
try_size_hint(depth: usize) -> Result<(usize, Option<usize>), MaxRecursionReached>121     fn try_size_hint(depth: usize) -> Result<(usize, Option<usize>), MaxRecursionReached> {
122         Ok(size_hint::or(
123             size_hint::and((1, Some(1)), A::try_size_hint(depth)?),
124             (1, Some(1)),
125         ))
126     }
127 }
128