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}