]>
git.proxmox.com Git - cargo.git/blob - vendor/proptest/src/option.rs
2 // Copyright 2017 Jason Lingle
4 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7 // option. This file may not be copied, modified, or distributed
8 // except according to those terms.
10 //! Strategies for generating `std::Option` values.
12 #![cfg_attr(feature="cargo-clippy", allow(expl_impl_clone_on_copy))]
15 use core
::marker
::PhantomData
;
17 use crate::strategy
::*;
18 use crate::test_runner
::*;
20 //==============================================================================
22 //==============================================================================
24 /// Creates a `Probability` from some value that is convertible into it.
28 /// Panics if the converted to probability would lie
29 /// outside interval `[0.0, 1.0]`. Consult the `Into` (or `From`)
30 /// implementations for more details.
31 pub fn prob(from
: impl Into
<Probability
>) -> Probability
{
35 impl Default
for Probability
{
36 /// The default probability is 0.5, or 50% chance.
37 fn default() -> Self {
42 impl From
<f64> for Probability
{
43 /// Creates a `Probability` from a `f64`.
47 /// Panics if the probability is outside interval `[0.0, 1.0]`.
48 fn from(prob
: f64) -> Self {
49 Probability
::new(prob
)
54 /// Creates a `Probability` from a `f64`.
58 /// Panics if the probability is outside interval `[0.0, 1.0]`.
59 pub fn new(prob
: f64) -> Self {
60 assert
!(prob
>= 0.0 && prob
<= 1.0);
64 // Don't rely on these existing internally:
66 /// Merges self together with some other argument producing a product
67 /// type expected by some impelementations of `A: Arbitrary` in
68 /// `A::Parameters`. This can be more ergonomic to work with and may
69 /// help type inference.
70 pub fn with
<X
>(self, and
: X
) -> product_type
![Self, X
] {
71 product_pack
![self, and
]
74 /// Merges self together with some other argument generated with a
75 /// default value producing a product type expected by some
76 /// impelementations of `A: Arbitrary` in `A::Parameters`.
77 /// This can be more ergonomic to work with and may help type inference.
78 pub fn lift
<X
: Default
>(self) -> product_type
![Self, X
] {
79 self.with(Default
::default())
83 #[cfg(feature = "frunk")]
84 use frunk_core
::generic
::Generic
;
86 #[cfg(feature = "frunk")]
87 impl Generic
for Probability
{
90 /// Converts the `Probability` into an `f64`.
91 fn into(self) -> Self::Repr
{
95 /// Creates a `Probability` from a `f64`.
99 /// Panics if the probability is outside interval `[0.0, 1.0]`.
100 fn from(r
: Self::Repr
) -> Self {
105 impl From
<Probability
> for f64 {
106 fn from(p
: Probability
) -> Self {
111 /// A probability in the range `[0.0, 1.0]` with a default of `0.5`.
112 #[derive(Clone, Copy, PartialEq, Debug)]
113 pub struct Probability(f64);
115 //==============================================================================
116 // Strategies for Option
117 //==============================================================================
120 [] fn WrapSome
[<T
: fmt
::Debug
>](t
: T
) -> Option
<T
> {
125 #[must_use = "strategies do nothing unless used"]
126 struct NoneStrategy
<T
>(PhantomData
<T
>);
127 impl<T
> Clone
for NoneStrategy
<T
> {
128 fn clone(&self) -> Self {
132 impl<T
> Copy
for NoneStrategy
<T
> {}
133 impl<T
> fmt
::Debug
for NoneStrategy
<T
> {
134 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
135 write
!(f
, "NoneStrategy")
138 impl<T
: fmt
::Debug
> Strategy
for NoneStrategy
<T
> {
140 type Value
= Option
<T
>;
142 fn new_tree(&self, _
: &mut TestRunner
) -> NewTree
<Self> {
146 impl<T
: fmt
::Debug
> ValueTree
for NoneStrategy
<T
> {
147 type Value
= Option
<T
>;
149 fn current(&self) -> Option
<T
> {
152 fn simplify(&mut self) -> bool
{
155 fn complicate(&mut self) -> bool
{
160 opaque_strategy_wrapper
! {
161 /// Strategy which generates `Option` values whose inner `Some` values are
162 /// generated by another strategy.
164 /// Constructed by other functions in this module.
166 pub struct OptionStrategy
[<T
>][where T
: Strategy
]
167 (TupleUnion
<(W
<NoneStrategy
<T
::Value
>>,
168 W
<statics
::Map
<T
, WrapSome
>>)>)
169 -> OptionValueTree
<T
::Tree
>;
170 /// `ValueTree` type corresponding to `OptionStrategy`.
171 #[derive(Clone, Debug)]
172 pub struct OptionValueTree
[<T
>][where T
: ValueTree
]
173 (TupleUnionValueTree
<(NoneStrategy
<T
::Value
>,
174 Option
<statics
::Map
<T
, WrapSome
>>)>)
178 // XXX Unclear why this is necessary; #[derive(Debug)] *should* generate
179 // exactly this, but for some reason it adds a `T::Value : Debug` constraint as
181 impl<T
: Strategy
+ fmt
::Debug
> fmt
::Debug
for OptionStrategy
<T
> {
182 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
183 write
!(f
, "OptionStrategy({:?})", self.0)
187 /// Return a strategy producing `Optional` values wrapping values from the
188 /// given delegate strategy.
190 /// `Some` values shrink to `None`.
192 /// `Some` and `None` are each chosen with 50% probability.
193 pub fn of
<T
: Strategy
>(t
: T
) -> OptionStrategy
<T
> {
194 weighted(Probability
::default(), t
)
197 /// Return a strategy producing `Optional` values wrapping values from the
198 /// given delegate strategy.
200 /// `Some` values shrink to `None`.
202 /// `Some` is chosen with a probability given by `probability_of_some`, which
203 /// must be between 0.0 and 1.0, both exclusive.
204 pub fn weighted
<T
: Strategy
>(
205 probability_of_some
: impl Into
<Probability
>,
207 ) -> OptionStrategy
<T
> {
208 let prob
= probability_of_some
.into().into();
209 let (weight_some
, weight_none
) = float_to_weight(prob
);
211 OptionStrategy(TupleUnion
::new((
212 (weight_none
, NoneStrategy(PhantomData
)),
213 (weight_some
, statics
::Map
::new(t
, WrapSome
)),
221 fn count_some_of_1000(s
: OptionStrategy
<Just
<i32>>) -> u32 {
222 let mut runner
= TestRunner
::deterministic();
226 s
.new_tree(&mut runner
).unwrap().current().is_some() as u32;
233 fn probability_defaults_to_0p5() {
234 let count
= count_some_of_1000(of(Just(42i32)));
235 assert
!(count
> 450 && count
< 550);
239 fn probability_handled_correctly() {
240 let count
= count_some_of_1000(weighted(0.9, Just(42i32)));
241 assert
!(count
> 800 && count
< 950);
243 let count
= count_some_of_1000(weighted(0.1, Just(42i32)));
244 assert
!(count
> 50 && count
< 150);
249 check_strategy_sanity(of(0i32..1000i32), None
);