• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Utilities for working with and combining the results of
2 //! [`Arbitrary::size_hint`][crate::Arbitrary::size_hint].
3 
4 pub(crate) const MAX_DEPTH: usize = 20;
5 
6 /// Protects against potential infinite recursion when calculating size hints
7 /// due to indirect type recursion.
8 ///
9 /// When the depth is not too deep, calls `f` with `depth + 1` to calculate the
10 /// size hint.
11 ///
12 /// Otherwise, returns the default size hint: `(0, None)`.
13 ///
14 /// <div class="warning">This method is deprecated. Users should instead implement <a href="../trait.Arbitrary.html#method.try_size_hint"><code>try_size_hint</code></a> and use <a href="fn.try_recursion_guard.html"><code>try_recursion_guard</code></a></div>
15 #[inline]
16 #[deprecated(note = "use `try_recursion_guard` instead")]
recursion_guard( depth: usize, f: impl FnOnce(usize) -> (usize, Option<usize>), ) -> (usize, Option<usize>)17 pub fn recursion_guard(
18     depth: usize,
19     f: impl FnOnce(usize) -> (usize, Option<usize>),
20 ) -> (usize, Option<usize>) {
21     if depth > MAX_DEPTH {
22         (0, None)
23     } else {
24         f(depth + 1)
25     }
26 }
27 
28 /// Protects against potential infinite recursion when calculating size hints
29 /// due to indirect type recursion.
30 ///
31 /// When the depth is not too deep, calls `f` with `depth + 1` to calculate the
32 /// size hint.
33 ///
34 /// Otherwise, returns an error.
35 ///
36 /// This should be used when implementing [`try_size_hint`](crate::Arbitrary::try_size_hint)
37 #[inline]
try_recursion_guard( depth: usize, f: impl FnOnce(usize) -> Result<(usize, Option<usize>), crate::MaxRecursionReached>, ) -> Result<(usize, Option<usize>), crate::MaxRecursionReached>38 pub fn try_recursion_guard(
39     depth: usize,
40     f: impl FnOnce(usize) -> Result<(usize, Option<usize>), crate::MaxRecursionReached>,
41 ) -> Result<(usize, Option<usize>), crate::MaxRecursionReached> {
42     if depth > MAX_DEPTH {
43         Err(crate::MaxRecursionReached {})
44     } else {
45         f(depth + 1)
46     }
47 }
48 
49 /// Take the sum of the `lhs` and `rhs` size hints.
50 #[inline]
and(lhs: (usize, Option<usize>), rhs: (usize, Option<usize>)) -> (usize, Option<usize>)51 pub fn and(lhs: (usize, Option<usize>), rhs: (usize, Option<usize>)) -> (usize, Option<usize>) {
52     let lower = lhs.0 + rhs.0;
53     let upper = lhs.1.and_then(|lhs| rhs.1.map(|rhs| lhs + rhs));
54     (lower, upper)
55 }
56 
57 /// Take the sum of all of the given size hints.
58 ///
59 /// If `hints` is empty, returns `(0, Some(0))`, aka the size of consuming
60 /// nothing.
61 #[inline]
and_all(hints: &[(usize, Option<usize>)]) -> (usize, Option<usize>)62 pub fn and_all(hints: &[(usize, Option<usize>)]) -> (usize, Option<usize>) {
63     hints.iter().copied().fold((0, Some(0)), and)
64 }
65 
66 /// Take the minimum of the lower bounds and maximum of the upper bounds in the
67 /// `lhs` and `rhs` size hints.
68 #[inline]
or(lhs: (usize, Option<usize>), rhs: (usize, Option<usize>)) -> (usize, Option<usize>)69 pub fn or(lhs: (usize, Option<usize>), rhs: (usize, Option<usize>)) -> (usize, Option<usize>) {
70     let lower = std::cmp::min(lhs.0, rhs.0);
71     let upper = lhs
72         .1
73         .and_then(|lhs| rhs.1.map(|rhs| std::cmp::max(lhs, rhs)));
74     (lower, upper)
75 }
76 
77 /// Take the maximum of the `lhs` and `rhs` size hints.
78 ///
79 /// If `hints` is empty, returns `(0, Some(0))`, aka the size of consuming
80 /// nothing.
81 #[inline]
or_all(hints: &[(usize, Option<usize>)]) -> (usize, Option<usize>)82 pub fn or_all(hints: &[(usize, Option<usize>)]) -> (usize, Option<usize>) {
83     if let Some(head) = hints.first().copied() {
84         hints[1..].iter().copied().fold(head, or)
85     } else {
86         (0, Some(0))
87     }
88 }
89 
90 #[cfg(test)]
91 mod tests {
92     #[test]
and()93     fn and() {
94         assert_eq!((5, Some(5)), super::and((2, Some(2)), (3, Some(3))));
95         assert_eq!((5, None), super::and((2, Some(2)), (3, None)));
96         assert_eq!((5, None), super::and((2, None), (3, Some(3))));
97         assert_eq!((5, None), super::and((2, None), (3, None)));
98     }
99 
100     #[test]
or()101     fn or() {
102         assert_eq!((2, Some(3)), super::or((2, Some(2)), (3, Some(3))));
103         assert_eq!((2, None), super::or((2, Some(2)), (3, None)));
104         assert_eq!((2, None), super::or((2, None), (3, Some(3))));
105         assert_eq!((2, None), super::or((2, None), (3, None)));
106     }
107 
108     #[test]
and_all()109     fn and_all() {
110         assert_eq!((0, Some(0)), super::and_all(&[]));
111         assert_eq!(
112             (7, Some(7)),
113             super::and_all(&[(1, Some(1)), (2, Some(2)), (4, Some(4))])
114         );
115         assert_eq!(
116             (7, None),
117             super::and_all(&[(1, Some(1)), (2, Some(2)), (4, None)])
118         );
119         assert_eq!(
120             (7, None),
121             super::and_all(&[(1, Some(1)), (2, None), (4, Some(4))])
122         );
123         assert_eq!(
124             (7, None),
125             super::and_all(&[(1, None), (2, Some(2)), (4, Some(4))])
126         );
127     }
128 
129     #[test]
or_all()130     fn or_all() {
131         assert_eq!((0, Some(0)), super::or_all(&[]));
132         assert_eq!(
133             (1, Some(4)),
134             super::or_all(&[(1, Some(1)), (2, Some(2)), (4, Some(4))])
135         );
136         assert_eq!(
137             (1, None),
138             super::or_all(&[(1, Some(1)), (2, Some(2)), (4, None)])
139         );
140         assert_eq!(
141             (1, None),
142             super::or_all(&[(1, Some(1)), (2, None), (4, Some(4))])
143         );
144         assert_eq!(
145             (1, None),
146             super::or_all(&[(1, None), (2, Some(2)), (4, Some(4))])
147         );
148     }
149 }
150