From c589b0cd77c54d29d83adb1cddb371a109748316 Mon Sep 17 00:00:00 2001 From: Rob Shearman Date: Tue, 27 Dec 2022 15:30:40 +0000 Subject: [PATCH] feat: Allow predicates to own object and evaluate against borrowed types It is very useful to be able to dynamically construct an object and have that object owned by the predicate, yet evaluate against an unowned type related to the owned one. An obvious example is a String being owned by the predicate but being compared against &strs. Therefore, implement Predicate for Eq/OrdPredicate that store an object that implements Borrow for the predicate type, replacing existing impls of Predicate for Eq/OrdPredicate and Eq/OrdPredicate<&T>. This is backwards compatible as there are blanket implementations of Borrow for T and Borrow for &T. Note that Borrow imposes more requirements than are actually required and AsRef would be sufficient. However, AsRef doesn't have a blanket implementation for T and thus the existing impl of Predicate for EqPredicate is still required, but results in a conflict since T may also implement AsRef. Requiring Borrow instead of AsRef is sufficient for common use cases though. This addresses #20 more completely. --- src/ord.rs | 102 ++++++++++++++++------------------------------------- 1 file changed, 31 insertions(+), 71 deletions(-) diff --git a/src/ord.rs b/src/ord.rs index aa768cb..0629736 100644 --- a/src/ord.rs +++ b/src/ord.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2018 The predicates-rs Project Developers. +// Copyright (c) 2018, 2022 The predicates-rs Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license @@ -35,26 +35,24 @@ impl fmt::Display for EqOps { /// /// This is created by the `predicate::{eq, ne}` functions. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct EqPredicate -where - T: fmt::Debug + PartialEq, -{ +pub struct EqPredicate { constant: T, op: EqOps, } -impl Predicate for EqPredicate +impl Predicate

for EqPredicate where - T: fmt::Debug + PartialEq, + T: std::borrow::Borrow

+ fmt::Debug, + P: fmt::Debug + PartialEq + ?Sized, { - fn eval(&self, variable: &T) -> bool { + fn eval(&self, variable: &P) -> bool { match self.op { - EqOps::Equal => variable.eq(&self.constant), - EqOps::NotEqual => variable.ne(&self.constant), + EqOps::Equal => variable.eq(self.constant.borrow()), + EqOps::NotEqual => variable.ne(self.constant.borrow()), } } - fn find_case<'a>(&'a self, expected: bool, variable: &T) -> Option> { + fn find_case<'a>(&'a self, expected: bool, variable: &P) -> Option> { utils::default_find_case(self, expected, variable).map(|case| { case.add_product(reflection::Product::new( "var", @@ -64,32 +62,11 @@ where } } -impl<'a, T> Predicate for EqPredicate<&'a T> -where - T: fmt::Debug + PartialEq + ?Sized, -{ - fn eval(&self, variable: &T) -> bool { - match self.op { - EqOps::Equal => variable.eq(self.constant), - EqOps::NotEqual => variable.ne(self.constant), - } - } - - fn find_case<'b>(&'b self, expected: bool, variable: &T) -> Option> { - utils::default_find_case(self, expected, variable).map(|case| { - case.add_product(reflection::Product::new( - "var", - utils::DebugAdapter::new(variable).to_string(), - )) - }) - } -} - -impl reflection::PredicateReflection for EqPredicate where T: fmt::Debug + PartialEq {} +impl reflection::PredicateReflection for EqPredicate where T: fmt::Debug {} impl fmt::Display for EqPredicate where - T: fmt::Debug + PartialEq, + T: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let palette = crate::Palette::current(); @@ -120,6 +97,10 @@ where /// let predicate_fn = predicate::eq("Hello"); /// assert_eq!(true, predicate_fn.eval("Hello")); /// assert_eq!(false, predicate_fn.eval("Goodbye")); +/// +/// let predicate_fn = predicate::eq(String::from("Hello")); +/// assert_eq!(true, predicate_fn.eval("Hello")); +/// assert_eq!(false, predicate_fn.eval("Goodbye")); /// ``` pub fn eq(constant: T) -> EqPredicate where @@ -178,28 +159,26 @@ impl fmt::Display for OrdOps { /// /// This is created by the `predicate::{gt, ge, lt, le}` functions. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct OrdPredicate -where - T: fmt::Debug + PartialOrd, -{ +pub struct OrdPredicate { constant: T, op: OrdOps, } -impl Predicate for OrdPredicate +impl Predicate

for OrdPredicate where - T: fmt::Debug + PartialOrd, + T: std::borrow::Borrow

+ fmt::Debug, + P: fmt::Debug + PartialOrd + ?Sized, { - fn eval(&self, variable: &T) -> bool { + fn eval(&self, variable: &P) -> bool { match self.op { - OrdOps::LessThan => variable.lt(&self.constant), - OrdOps::LessThanOrEqual => variable.le(&self.constant), - OrdOps::GreaterThanOrEqual => variable.ge(&self.constant), - OrdOps::GreaterThan => variable.gt(&self.constant), + OrdOps::LessThan => variable.lt(self.constant.borrow()), + OrdOps::LessThanOrEqual => variable.le(self.constant.borrow()), + OrdOps::GreaterThanOrEqual => variable.ge(self.constant.borrow()), + OrdOps::GreaterThan => variable.gt(self.constant.borrow()), } } - fn find_case<'a>(&'a self, expected: bool, variable: &T) -> Option> { + fn find_case<'a>(&'a self, expected: bool, variable: &P) -> Option> { utils::default_find_case(self, expected, variable).map(|case| { case.add_product(reflection::Product::new( "var", @@ -209,34 +188,11 @@ where } } -impl<'a, T> Predicate for OrdPredicate<&'a T> -where - T: fmt::Debug + PartialOrd + ?Sized, -{ - fn eval(&self, variable: &T) -> bool { - match self.op { - OrdOps::LessThan => variable.lt(self.constant), - OrdOps::LessThanOrEqual => variable.le(self.constant), - OrdOps::GreaterThanOrEqual => variable.ge(self.constant), - OrdOps::GreaterThan => variable.gt(self.constant), - } - } - - fn find_case<'b>(&'b self, expected: bool, variable: &T) -> Option> { - utils::default_find_case(self, expected, variable).map(|case| { - case.add_product(reflection::Product::new( - "var", - utils::DebugAdapter::new(variable).to_string(), - )) - }) - } -} - -impl reflection::PredicateReflection for OrdPredicate where T: fmt::Debug + PartialOrd {} +impl reflection::PredicateReflection for OrdPredicate where T: fmt::Debug {} impl fmt::Display for OrdPredicate where - T: fmt::Debug + PartialOrd, + T: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let palette = crate::Palette::current(); @@ -267,6 +223,10 @@ where /// let predicate_fn = predicate::lt("b"); /// assert_eq!(true, predicate_fn.eval("a")); /// assert_eq!(false, predicate_fn.eval("c")); +/// +/// let predicate_fn = predicate::lt(String::from("b")); +/// assert_eq!(true, predicate_fn.eval("a")); +/// assert_eq!(false, predicate_fn.eval("c")); /// ``` pub fn lt(constant: T) -> OrdPredicate where