diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
commit | 9835e2ae736235810b4ea1c162ca5e65c547e770 (patch) | |
tree | 3fcebf40ed70e581d776a8a4c65923e8ec20e026 /vendor/proptest/src/option.rs | |
parent | Releasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff) | |
download | rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip |
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/proptest/src/option.rs')
-rw-r--r-- | vendor/proptest/src/option.rs | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/vendor/proptest/src/option.rs b/vendor/proptest/src/option.rs new file mode 100644 index 000000000..466ada687 --- /dev/null +++ b/vendor/proptest/src/option.rs @@ -0,0 +1,271 @@ +//- +// Copyright 2017 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Strategies for generating `std::Option` values. + +#![cfg_attr(feature = "cargo-clippy", allow(expl_impl_clone_on_copy))] + +use core::fmt; +use core::marker::PhantomData; + +use crate::std_facade::Arc; +use crate::strategy::*; +use crate::test_runner::*; + +//============================================================================== +// Probability +//============================================================================== + +/// Creates a `Probability` from some value that is convertible into it. +/// +/// # Panics +/// +/// Panics if the converted to probability would lie +/// outside interval `[0.0, 1.0]`. Consult the `Into` (or `From`) +/// implementations for more details. +pub fn prob(from: impl Into<Probability>) -> Probability { + from.into() +} + +impl Default for Probability { + /// The default probability is 0.5, or 50% chance. + fn default() -> Self { + prob(0.5) + } +} + +impl From<f64> for Probability { + /// Creates a `Probability` from a `f64`. + /// + /// # Panics + /// + /// Panics if the probability is outside interval `[0.0, 1.0]`. + fn from(prob: f64) -> Self { + Probability::new(prob) + } +} + +impl Probability { + /// Creates a `Probability` from a `f64`. + /// + /// # Panics + /// + /// Panics if the probability is outside interval `[0.0, 1.0]`. + pub fn new(prob: f64) -> Self { + assert!(prob >= 0.0 && prob <= 1.0); + Probability(prob) + } + + // Don't rely on these existing internally: + + /// Merges self together with some other argument producing a product + /// type expected by some implementations of `A: Arbitrary` in + /// `A::Parameters`. This can be more ergonomic to work with and may + /// help type inference. + pub fn with<X>(self, and: X) -> product_type![Self, X] { + product_pack![self, and] + } + + /// Merges self together with some other argument generated with a + /// default value producing a product type expected by some + /// implementations of `A: Arbitrary` in `A::Parameters`. + /// This can be more ergonomic to work with and may help type inference. + pub fn lift<X: Default>(self) -> product_type![Self, X] { + self.with(Default::default()) + } +} + +#[cfg(feature = "frunk")] +use frunk_core::generic::Generic; + +#[cfg(feature = "frunk")] +impl Generic for Probability { + type Repr = f64; + + /// Converts the `Probability` into an `f64`. + fn into(self) -> Self::Repr { + self.0 + } + + /// Creates a `Probability` from a `f64`. + /// + /// # Panics + /// + /// Panics if the probability is outside interval `[0.0, 1.0]`. + fn from(r: Self::Repr) -> Self { + r.into() + } +} + +impl From<Probability> for f64 { + fn from(p: Probability) -> Self { + p.0 + } +} + +/// A probability in the range `[0.0, 1.0]` with a default of `0.5`. +#[derive(Clone, Copy, PartialEq, Debug)] +pub struct Probability(f64); + +//============================================================================== +// Strategies for Option +//============================================================================== + +mapfn! { + [] fn WrapSome[<T : fmt::Debug>](t: T) -> Option<T> { + Some(t) + } +} + +#[must_use = "strategies do nothing unless used"] +struct NoneStrategy<T>(PhantomData<T>); +impl<T> Clone for NoneStrategy<T> { + fn clone(&self) -> Self { + *self + } +} +impl<T> Copy for NoneStrategy<T> {} +impl<T> fmt::Debug for NoneStrategy<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "NoneStrategy") + } +} +impl<T: fmt::Debug> Strategy for NoneStrategy<T> { + type Tree = Self; + type Value = Option<T>; + + fn new_tree(&self, _: &mut TestRunner) -> NewTree<Self> { + Ok(*self) + } +} +impl<T: fmt::Debug> ValueTree for NoneStrategy<T> { + type Value = Option<T>; + + fn current(&self) -> Option<T> { + None + } + fn simplify(&mut self) -> bool { + false + } + fn complicate(&mut self) -> bool { + false + } +} + +opaque_strategy_wrapper! { + /// Strategy which generates `Option` values whose inner `Some` values are + /// generated by another strategy. + /// + /// Constructed by other functions in this module. + #[derive(Clone)] + pub struct OptionStrategy[<T>][where T : Strategy] + (TupleUnion<(WA<NoneStrategy<T::Value>>, + WA<statics::Map<T, WrapSome>>)>) + -> OptionValueTree<T>; + /// `ValueTree` type corresponding to `OptionStrategy`. + pub struct OptionValueTree[<T>][where T : Strategy] + (TupleUnionValueTree<( + LazyValueTree<NoneStrategy<T::Value>>, + Option<LazyValueTree<statics::Map<T, WrapSome>>>, + )>) + -> Option<T::Value>; +} + +// XXX Unclear why this is necessary; #[derive(Debug)] *should* generate +// exactly this, but for some reason it adds a `T::Value : Debug` constraint as +// well. +impl<T: Strategy + fmt::Debug> fmt::Debug for OptionStrategy<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "OptionStrategy({:?})", self.0) + } +} + +impl<T: Strategy> Clone for OptionValueTree<T> +where + T::Tree: Clone, +{ + fn clone(&self) -> Self { + OptionValueTree(self.0.clone()) + } +} + +impl<T: Strategy> fmt::Debug for OptionValueTree<T> +where + T::Tree: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "OptionValueTree({:?})", self.0) + } +} + +/// Return a strategy producing `Optional` values wrapping values from the +/// given delegate strategy. +/// +/// `Some` values shrink to `None`. +/// +/// `Some` and `None` are each chosen with 50% probability. +pub fn of<T: Strategy>(t: T) -> OptionStrategy<T> { + weighted(Probability::default(), t) +} + +/// Return a strategy producing `Optional` values wrapping values from the +/// given delegate strategy. +/// +/// `Some` values shrink to `None`. +/// +/// `Some` is chosen with a probability given by `probability_of_some`, which +/// must be between 0.0 and 1.0, both exclusive. +pub fn weighted<T: Strategy>( + probability_of_some: impl Into<Probability>, + t: T, +) -> OptionStrategy<T> { + let prob = probability_of_some.into().into(); + let (weight_some, weight_none) = float_to_weight(prob); + + OptionStrategy(TupleUnion::new(( + (weight_none, Arc::new(NoneStrategy(PhantomData))), + (weight_some, Arc::new(statics::Map::new(t, WrapSome))), + ))) +} + +#[cfg(test)] +mod test { + use super::*; + + fn count_some_of_1000(s: OptionStrategy<Just<i32>>) -> u32 { + let mut runner = TestRunner::deterministic(); + let mut count = 0; + for _ in 0..1000 { + count += + s.new_tree(&mut runner).unwrap().current().is_some() as u32; + } + + count + } + + #[test] + fn probability_defaults_to_0p5() { + let count = count_some_of_1000(of(Just(42i32))); + assert!(count > 450 && count < 550); + } + + #[test] + fn probability_handled_correctly() { + let count = count_some_of_1000(weighted(0.9, Just(42i32))); + assert!(count > 800 && count < 950); + + let count = count_some_of_1000(weighted(0.1, Just(42i32))); + assert!(count > 50 && count < 150); + } + + #[test] + fn test_sanity() { + check_strategy_sanity(of(0i32..1000i32), None); + } +} |