diff --git a/CHANGELOG.md b/CHANGELOG.md index 1807c8a4..f09d2be9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,17 +2,18 @@ ### Potential Breaking Changes -- Instead of returning `-> Result`, strategies are expected - to return `-> Result` instead. `Rejection` reduces - the amount of heap allocations, especially for `.prop_filter(..)` where - you may now also pass in `&'static str` as well as `Rc`. - You will only experience breaks if you've written your own strategy types - or if you've used `TestCaseError::Reject` or `TestCaseError::Fail` expliclty. +- Instead of returning `-> Result`, strategies are + expected to return `-> Result` instead. `Reason` reduces + the amount of heap allocations, especially for `.prop_filter(..)` where you + may now also pass in `&'static str`. You will only experience breaks if + you've written your own strategy types or if you've used + `TestCaseError::Reject` or `TestCaseError::Fail` explicitly. ### New Additions -- Added `proptest::test_runner::Rejection` which allows you to avoid heap - allocation in some places or share allocation with string-interning. +- Added `proptest::test_runner::Reason` which allows you to avoid heap + allocation in some places and may be used to make the API richer in the + future without incurring more breaking changes. - Added a type alias `proptest::strategy::NewTree` where `S: Strategy` defined as: `type NewTree = Result<::Value, Rejection>`. diff --git a/src/strategy/filter.rs b/src/strategy/filter.rs index a34b61e4..7f4a608c 100644 --- a/src/strategy/filter.rs +++ b/src/strategy/filter.rs @@ -18,12 +18,12 @@ use test_runner::*; /// See `Strategy::prop_filter()`. pub struct Filter { pub(super) source: S, - pub(super) whence: Rejection, + pub(super) whence: Reason, pub(super) fun: Arc, } impl Filter { - pub (super) fn new(source: S, whence: Rejection, fun: F) -> Self { + pub (super) fn new(source: S, whence: Reason, fun: F) -> Self { Self { source, whence, fun: Arc::new(fun) } } } diff --git a/src/strategy/flatten.rs b/src/strategy/flatten.rs index 6d87f3bb..9857e91a 100644 --- a/src/strategy/flatten.rs +++ b/src/strategy/flatten.rs @@ -91,7 +91,7 @@ where S::Value : Strategy, } impl FlattenValueTree where S::Value : Strategy { - fn new(runner: &mut TestRunner, meta: S) -> Result { + fn new(runner: &mut TestRunner, meta: S) -> Result { let current = meta.current().new_value(runner)?; Ok(FlattenValueTree { meta: Fuse::new(meta), diff --git a/src/strategy/statics.rs b/src/strategy/statics.rs index a681dd6d..5370fb20 100644 --- a/src/strategy/statics.rs +++ b/src/strategy/statics.rs @@ -39,15 +39,15 @@ pub trait FilterFn { #[derive(Clone)] pub struct Filter { source: S, - whence: Rejection, + whence: Reason, fun: F, } impl Filter { /// Adapt strategy `source` to reject values which do not pass `filter`, /// using `whence` as the reported reason/location. - pub fn new(source: S, whence: Rejection, filter: F) -> Self { - // NOTE: We don't use universal quantification R: Into + pub fn new(source: S, whence: Reason, filter: F) -> Self { + // NOTE: We don't use universal quantification R: Into // since the module is not conviniently exposed. Filter { source, whence, fun: filter } } diff --git a/src/strategy/traits.rs b/src/strategy/traits.rs index 1d266498..83b2fd38 100644 --- a/src/strategy/traits.rs +++ b/src/strategy/traits.rs @@ -25,7 +25,7 @@ use test_runner::*; /// [`ValueTree`]: trait.ValueTree.html /// [`Ok`]: https://doc.rust-lang.org/nightly/std/result/enum.Result.html#variant.Ok /// [`Err`]: https://doc.rust-lang.org/nightly/std/result/enum.Result.html#variant.Err -pub type NewTree = Result<::Value, Rejection>; +pub type NewTree = Result<::Value, Reason>; /// The value that functions under test use for a particular `Strategy`. pub type ValueFor = <::Value as ValueTree>::Value; @@ -259,7 +259,7 @@ pub trait Strategy : fmt::Debug { /// whole-input rejections. /// /// `whence` is used to record where and why the rejection occurred. - fn prop_filter, F : Fn (&ValueFor) -> bool> + fn prop_filter, F : Fn (&ValueFor) -> bool> (self, whence: R, fun: F) -> Filter where Self : Sized { Filter::new(self, whence.into(), fun) diff --git a/src/test_runner.rs b/src/test_runner.rs index ea764ce4..7c88c944 100644 --- a/src/test_runner.rs +++ b/src/test_runner.rs @@ -287,40 +287,40 @@ impl FailurePersistence { /// The reason for why something, such as a generated value, was rejected. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Rejection(Cow<'static, str>); +pub struct Reason(Cow<'static, str>); -impl From<&'static str> for Rejection { +impl From<&'static str> for Reason { fn from(s: &'static str) -> Self { - Rejection(s.into()) + Reason(s.into()) } } -impl From for Rejection { +impl From for Reason { fn from(s: String) -> Self { - Rejection(s.into()) + Reason(s.into()) } } -impl From> for Rejection { +impl From> for Reason { fn from(s: Box) -> Self { - Rejection(String::from(s).into()) + Reason(String::from(s).into()) } } -impl ops::Deref for Rejection { +impl ops::Deref for Reason { type Target = str; fn deref(&self) -> &Self::Target { self.0.deref() } } -impl AsRef for Rejection { +impl AsRef for Reason { fn as_ref(&self) -> &str { &*self } } -impl Borrow for Rejection { +impl Borrow for Reason { fn borrow(&self) -> &str { &*self } } -impl fmt::Display for Rejection { +impl fmt::Display for Reason { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self.as_ref(), f) } @@ -343,12 +343,12 @@ pub enum TestCaseError { /// /// The string gives the location and context of the rejection, and /// should be suitable for formatting like `Foo did X at {whence}`. - Reject(Rejection), + Reject(Reason), /// The code under test failed the test. /// /// The string should indicate the location of the failure, but may /// generally be any string. - Fail(Rejection), + Fail(Reason), } /// Convenience for the type returned by test cases. @@ -361,7 +361,7 @@ impl TestCaseError { /// /// The string gives the location and context of the rejection, and /// should be suitable for formatting like `Foo did X at {whence}`. - pub fn reject>(reason: R) -> Self { + pub fn reject>(reason: R) -> Self { TestCaseError::Reject(reason.into()) } @@ -369,7 +369,7 @@ impl TestCaseError { /// /// The string should indicate the location of the failure, but may /// generally be any string. - pub fn fail>(reason: R) -> Self { + pub fn fail>(reason: R) -> Self { TestCaseError::Fail(reason.into()) } } @@ -396,11 +396,11 @@ impl From for TestCaseError { pub enum TestError { /// The test was aborted for the given reason, for example, due to too many /// inputs having been rejected. - Abort(Rejection), + Abort(Reason), /// A failing test case was found. The string indicates where and/or why /// the test failed. The `T` is the minimal input found to reproduce the /// failure. - Fail(Rejection, T), + Fail(Reason, T), } impl fmt::Display for TestError { @@ -424,7 +424,7 @@ impl ::std::error::Error for TestError { } } -type RejectionDetail = BTreeMap; +type RejectionDetail = BTreeMap; /// State used when running a proptest test. #[derive(Clone)] @@ -856,9 +856,9 @@ impl TestRunner { /// Update the state to account for a local rejection from `whence`, and /// return `Ok` if the caller should keep going or `Err` to abort. - pub fn reject_local(&mut self, whence: R) -> Result<(), Rejection> + pub fn reject_local(&mut self, whence: R) -> Result<(), Reason> where - R: Into + R: Into { if self.local_rejects >= self.config.max_local_rejects { Err("Too many local rejects".into()) @@ -872,7 +872,7 @@ impl TestRunner { /// Update the state to account for a global rejection from `whence`, and /// return `Ok` if the caller should keep going or `Err` to abort. - fn reject_global(&mut self, whence: Rejection) -> Result<(),TestError> { + fn reject_global(&mut self, whence: Reason) -> Result<(),TestError> { if self.global_rejects >= self.config.max_global_rejects { Err(TestError::Abort("Too many global rejects".into())) } else { @@ -883,7 +883,7 @@ impl TestRunner { } /// Insert 1 or increment the rejection detail at key for whence. - fn insert_or_increment(into: &mut RejectionDetail, whence: Rejection) { + fn insert_or_increment(into: &mut RejectionDetail, whence: Reason) { use std::collections::btree_map::Entry::*; match into.entry(whence) { Occupied(oe) => { *oe.into_mut() += 1; },