proptest_arbitrary/
params.rs

1//! Common types for parameters.
2
3use super::*;
4
5use std::ops::{Add, Range, RangeTo};
6use proptest::num::f64;
7
8//==============================================================================
9// Probability, default = 0.5.
10//==============================================================================
11
12default!(Probability, 0.5);
13
14/// Creates a `Probability` from some value that is convertible into it.
15///
16/// # Safety
17///
18/// Panics if the converted to probability would lie
19/// outside interval `[0.0, 1.0]`. Consult the `Into` (or `From`)
20/// implementation for more details.
21pub fn prob<X: Into<Probability>>(from: X) -> Probability {
22    from.into()
23}
24
25impl From<f64> for Probability {
26    /// Creates a `Probability` from a `f64`.
27    /// 
28    /// # Safety
29    ///
30    /// Panics if the probability is outside interval `[0.0, 1.0]`.
31    fn from(prob: f64) -> Self {
32        Probability::new(prob)
33    }
34}
35
36impl Probability {
37    /// Creates a `Probability` from a `f64`.
38    /// 
39    /// # Safety
40    ///
41    /// Panics if the probability is outside interval `[0.0, 1.0]`.
42    pub fn new(prob: f64) -> Self {
43        assert!(prob >= 0.0 && prob <= 1.0);
44        Probability(prob)
45    }
46
47    // Don't rely on these existing internally:
48
49    /// Merges self together with some other argument producing a product
50    /// type expected by some impelementations of `A: Arbitrary<'a>` in
51    /// `A::Parameters`. This can be more ergonomic to work with and may
52    /// help type inference.
53    pub fn with<X>(self, and: X) -> product_type![Self, X] {
54        product_pack![self, and]
55    }
56
57    /// Merges self together with some other argument generated with a
58    /// default value producing a product type expected by some
59    /// impelementations of `A: Arbitrary<'a>` in `A::Parameters`.
60    /// This can be more ergonomic to work with and may help type inference.
61    pub fn lift<X: Default>(self) -> product_type![Self, X] {
62        self.with(default())
63    }
64}
65
66arbitrary!(Probability, FromMapStrategy<Range<f64>, Self>;
67    from_map_strategy(0.0..1.0)
68);
69
70#[cfg(feature = "frunk")]
71use frunk_core::generic::Generic;
72
73#[cfg(feature = "frunk")]
74impl Generic for Probability {
75    type Repr = f64;
76
77    /// Converts the `Probability` into an `f64`.
78    fn into(self) -> Self::Repr { self.0 }
79
80    /// Creates a `Probability` from a `f64`.
81    /// 
82    /// # Safety
83    ///
84    /// Panics if the probability is outside interval `[0.0, 1.0]`.
85    fn from(r: Self::Repr) -> Self { prob(r) }
86}
87
88/// A probability in the range `[0.0, 1.0]` with a default of `0.5`.
89#[derive(Clone, Copy, PartialEq, Debug, Into)]
90pub struct Probability(f64);
91
92//==============================================================================
93// SizeBounds, default = 0..100.
94//==============================================================================
95
96default!(SizeBounds, 0..100);
97
98/// Creates a `SizeBounds` from some value that is convertible into it.
99pub fn size_bounds<X: Into<SizeBounds>>(from: X) -> SizeBounds {
100    from.into()
101}
102
103impl SizeBounds {
104    /// Creates a `SizeBounds` from a `Range<usize>`.
105    pub fn new(range: Range<usize>) -> Self {
106        SizeBounds(range)
107    }
108
109    // Don't rely on these existing internally:
110
111    /// Merges self together with some other argument producing a product
112    /// type expected by some impelementations of `A: Arbitrary<'a>` in
113    /// `A::Parameters`. This can be more ergonomic to work with and may
114    /// help type inference.
115    pub fn with<X>(self, and: X) -> product_type![Self, X] {
116        product_pack![self, and]
117    }
118
119    /// Merges self together with some other argument generated with a
120    /// default value producing a product type expected by some
121    /// impelementations of `A: Arbitrary<'a>` in `A::Parameters`.
122    /// This can be more ergonomic to work with and may help type inference.
123    pub fn lift<X: Default>(self) -> product_type![Self, X] {
124        self.with(default())
125    }
126}
127
128/// Given `(low: usize, high: usize)`, then a range `[low..high)` is the result.
129impl From<(usize, usize)> for SizeBounds {
130    fn from(x: (usize, usize)) -> Self {
131        (x.0..x.1).into()
132    }
133}
134
135/// Given `exact`, then a range `[exact..exact + 1)` is the result.
136impl From<usize> for SizeBounds {
137    fn from(exact: usize) -> Self {
138        size_bounds(exact..exact + 1)
139    }
140}
141
142/// Given `..high`, then a range `[0..high)` is the result.
143impl From<RangeTo<usize>> for SizeBounds {
144    fn from(high: RangeTo<usize>) -> Self {
145        size_bounds(0..high.end)
146    }
147}
148
149/// Adds `usize` to both start and end of the bounds.
150impl Add<usize> for SizeBounds {
151    type Output = SizeBounds;
152
153    fn add(self, rhs: usize) -> Self::Output {
154        let Range { start, end } = self.0;
155        size_bounds((start + rhs)..(end + rhs))
156    }
157}
158
159arbitrary!(SizeBounds, FMapped<'a, Range<usize>, Self>;
160    any_sinto::<Range<usize>, _>()
161);
162
163/// The minimum and maximum bounds on the size of a collection.
164/// The interval must form a subset of `[0, std::usize::MAX)`.
165#[derive(Clone, PartialEq, Eq, Hash, Debug, From, Into)]
166#[cfg_attr(feature = "frunk", derive(Generic))]
167pub struct SizeBounds(Range<usize>);
168
169#[cfg(test)]
170mod test {
171    no_panic_test!(
172        probability => Probability,
173        size_bounds => SizeBounds
174    );
175}