arbitrary/foreign/core/
ops.rs1use {
2 crate::{size_hint, Arbitrary, MaxRecursionReached, Result, Unstructured},
3 core::{
4 mem,
5 ops::{Bound, Range, RangeBounds, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive},
6 },
7};
8
9macro_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}
39impl_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);
49impl_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);
56impl_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);
66impl_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);
73impl_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
81pub(crate) fn bounded_range<CB, I, R>(bounds: (I, I), cb: CB) -> R
82where
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
94pub(crate) fn unbounded_range<CB, I, R>(bound: I, cb: CB) -> R
95where
96 CB: Fn(I) -> R,
97 R: RangeBounds<I>,
98{
99 cb(bound)
100}
101
102impl<'a, A> Arbitrary<'a> for Bound<A>
103where
104 A: Arbitrary<'a>,
105{
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]
116 fn size_hint(depth: usize) -> (usize, Option<usize>) {
117 Self::try_size_hint(depth).unwrap_or_default()
118 }
119
120 #[inline]
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}