arbitrary/foreign/core/
ops.rs

1use {
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}