| 1 | // Copyright (c) 2018, 2022 The predicates-rs Project Developers. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
| 4 | // http://www.apache.org/license/LICENSE-2.0> or the MIT license |
| 5 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
| 6 | // option. This file may not be copied, modified, or distributed |
| 7 | // except according to those terms. |
| 8 | |
| 9 | //! Definition of `Predicate`s for comparisons over `Ord` and `Eq` types. |
| 10 | |
| 11 | use std::fmt; |
| 12 | |
| 13 | use crate::reflection; |
| 14 | use crate::utils; |
| 15 | use crate::Predicate; |
| 16 | |
| 17 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
| 18 | enum EqOps { |
| 19 | Equal, |
| 20 | NotEqual, |
| 21 | } |
| 22 | |
| 23 | impl fmt::Display for EqOps { |
| 24 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 25 | let op = match *self { |
| 26 | EqOps::Equal => "==" , |
| 27 | EqOps::NotEqual => "!=" , |
| 28 | }; |
| 29 | write!(f, "{}" , op) |
| 30 | } |
| 31 | } |
| 32 | |
| 33 | /// Predicate that returns `true` if `variable` matches the pre-defined `Eq` |
| 34 | /// value, otherwise returns `false`. |
| 35 | /// |
| 36 | /// This is created by the `predicate::{eq, ne}` functions. |
| 37 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 38 | pub struct EqPredicate<T> { |
| 39 | constant: T, |
| 40 | op: EqOps, |
| 41 | } |
| 42 | |
| 43 | impl<P, T> Predicate<P> for EqPredicate<T> |
| 44 | where |
| 45 | T: std::borrow::Borrow<P> + fmt::Debug, |
| 46 | P: fmt::Debug + PartialEq + ?Sized, |
| 47 | { |
| 48 | fn eval(&self, variable: &P) -> bool { |
| 49 | match self.op { |
| 50 | EqOps::Equal => variable.eq(self.constant.borrow()), |
| 51 | EqOps::NotEqual => variable.ne(self.constant.borrow()), |
| 52 | } |
| 53 | } |
| 54 | |
| 55 | fn find_case<'a>(&'a self, expected: bool, variable: &P) -> Option<reflection::Case<'a>> { |
| 56 | utils::default_find_case(self, expected, variable).map(|case| { |
| 57 | case.add_product(reflection::Product::new( |
| 58 | "var" , |
| 59 | utils::DebugAdapter::new(variable).to_string(), |
| 60 | )) |
| 61 | }) |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | impl<T> reflection::PredicateReflection for EqPredicate<T> where T: fmt::Debug {} |
| 66 | |
| 67 | impl<T> fmt::Display for EqPredicate<T> |
| 68 | where |
| 69 | T: fmt::Debug, |
| 70 | { |
| 71 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 72 | let palette = crate::Palette::current(); |
| 73 | write!( |
| 74 | f, |
| 75 | "{} {} {}" , |
| 76 | palette.var.paint("var" ), |
| 77 | palette.description.paint(self.op), |
| 78 | palette |
| 79 | .expected |
| 80 | .paint(utils::DebugAdapter::new(&self.constant)), |
| 81 | ) |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | /// Creates a new predicate that will return `true` when the given `variable` is |
| 86 | /// equal to a pre-defined value. |
| 87 | /// |
| 88 | /// # Examples |
| 89 | /// |
| 90 | /// ``` |
| 91 | /// use predicates::prelude::*; |
| 92 | /// |
| 93 | /// let predicate_fn = predicate::eq(5); |
| 94 | /// assert_eq!(true, predicate_fn.eval(&5)); |
| 95 | /// assert_eq!(false, predicate_fn.eval(&10)); |
| 96 | /// |
| 97 | /// let predicate_fn = predicate::eq("Hello" ); |
| 98 | /// assert_eq!(true, predicate_fn.eval("Hello" )); |
| 99 | /// assert_eq!(false, predicate_fn.eval("Goodbye" )); |
| 100 | /// |
| 101 | /// let predicate_fn = predicate::eq(String::from("Hello" )); |
| 102 | /// assert_eq!(true, predicate_fn.eval("Hello" )); |
| 103 | /// assert_eq!(false, predicate_fn.eval("Goodbye" )); |
| 104 | /// ``` |
| 105 | pub fn eq<T>(constant: T) -> EqPredicate<T> |
| 106 | where |
| 107 | T: fmt::Debug + PartialEq, |
| 108 | { |
| 109 | EqPredicate { |
| 110 | constant, |
| 111 | op: EqOps::Equal, |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | /// Creates a new predicate that will return `true` when the given `variable` is |
| 116 | /// _not_ equal to a pre-defined value. |
| 117 | /// |
| 118 | /// # Examples |
| 119 | /// |
| 120 | /// ``` |
| 121 | /// use predicates::prelude::*; |
| 122 | /// |
| 123 | /// let predicate_fn = predicate::ne(5); |
| 124 | /// assert_eq!(false, predicate_fn.eval(&5)); |
| 125 | /// assert_eq!(true, predicate_fn.eval(&10)); |
| 126 | /// ``` |
| 127 | pub fn ne<T>(constant: T) -> EqPredicate<T> |
| 128 | where |
| 129 | T: PartialEq + fmt::Debug, |
| 130 | { |
| 131 | EqPredicate { |
| 132 | constant, |
| 133 | op: EqOps::NotEqual, |
| 134 | } |
| 135 | } |
| 136 | |
| 137 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
| 138 | enum OrdOps { |
| 139 | LessThan, |
| 140 | LessThanOrEqual, |
| 141 | GreaterThanOrEqual, |
| 142 | GreaterThan, |
| 143 | } |
| 144 | |
| 145 | impl fmt::Display for OrdOps { |
| 146 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 147 | let op = match *self { |
| 148 | OrdOps::LessThan => "<" , |
| 149 | OrdOps::LessThanOrEqual => "<=" , |
| 150 | OrdOps::GreaterThanOrEqual => ">=" , |
| 151 | OrdOps::GreaterThan => ">" , |
| 152 | }; |
| 153 | write!(f, "{}" , op) |
| 154 | } |
| 155 | } |
| 156 | |
| 157 | /// Predicate that returns `true` if `variable` matches the pre-defined `Ord` |
| 158 | /// value, otherwise returns `false`. |
| 159 | /// |
| 160 | /// This is created by the `predicate::{gt, ge, lt, le}` functions. |
| 161 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 162 | pub struct OrdPredicate<T> { |
| 163 | constant: T, |
| 164 | op: OrdOps, |
| 165 | } |
| 166 | |
| 167 | impl<P, T> Predicate<P> for OrdPredicate<T> |
| 168 | where |
| 169 | T: std::borrow::Borrow<P> + fmt::Debug, |
| 170 | P: fmt::Debug + PartialOrd + ?Sized, |
| 171 | { |
| 172 | fn eval(&self, variable: &P) -> bool { |
| 173 | match self.op { |
| 174 | OrdOps::LessThan => variable.lt(self.constant.borrow()), |
| 175 | OrdOps::LessThanOrEqual => variable.le(self.constant.borrow()), |
| 176 | OrdOps::GreaterThanOrEqual => variable.ge(self.constant.borrow()), |
| 177 | OrdOps::GreaterThan => variable.gt(self.constant.borrow()), |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | fn find_case<'a>(&'a self, expected: bool, variable: &P) -> Option<reflection::Case<'a>> { |
| 182 | utils::default_find_case(self, expected, variable).map(|case| { |
| 183 | case.add_product(reflection::Product::new( |
| 184 | "var" , |
| 185 | utils::DebugAdapter::new(variable).to_string(), |
| 186 | )) |
| 187 | }) |
| 188 | } |
| 189 | } |
| 190 | |
| 191 | impl<T> reflection::PredicateReflection for OrdPredicate<T> where T: fmt::Debug {} |
| 192 | |
| 193 | impl<T> fmt::Display for OrdPredicate<T> |
| 194 | where |
| 195 | T: fmt::Debug, |
| 196 | { |
| 197 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 198 | let palette = crate::Palette::current(); |
| 199 | write!( |
| 200 | f, |
| 201 | "{} {} {}" , |
| 202 | palette.var.paint("var" ), |
| 203 | palette.description.paint(self.op), |
| 204 | palette |
| 205 | .expected |
| 206 | .paint(utils::DebugAdapter::new(&self.constant)), |
| 207 | ) |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | /// Creates a new predicate that will return `true` when the given `variable` is |
| 212 | /// less than a pre-defined value. |
| 213 | /// |
| 214 | /// # Examples |
| 215 | /// |
| 216 | /// ``` |
| 217 | /// use predicates::prelude::*; |
| 218 | /// |
| 219 | /// let predicate_fn = predicate::lt(5); |
| 220 | /// assert_eq!(true, predicate_fn.eval(&4)); |
| 221 | /// assert_eq!(false, predicate_fn.eval(&6)); |
| 222 | /// |
| 223 | /// let predicate_fn = predicate::lt("b" ); |
| 224 | /// assert_eq!(true, predicate_fn.eval("a" )); |
| 225 | /// assert_eq!(false, predicate_fn.eval("c" )); |
| 226 | /// |
| 227 | /// let predicate_fn = predicate::lt(String::from("b" )); |
| 228 | /// assert_eq!(true, predicate_fn.eval("a" )); |
| 229 | /// assert_eq!(false, predicate_fn.eval("c" )); |
| 230 | /// ``` |
| 231 | pub fn lt<T>(constant: T) -> OrdPredicate<T> |
| 232 | where |
| 233 | T: fmt::Debug + PartialOrd, |
| 234 | { |
| 235 | OrdPredicate { |
| 236 | constant, |
| 237 | op: OrdOps::LessThan, |
| 238 | } |
| 239 | } |
| 240 | |
| 241 | /// Creates a new predicate that will return `true` when the given `variable` is |
| 242 | /// less than or equal to a pre-defined value. |
| 243 | /// |
| 244 | /// # Examples |
| 245 | /// |
| 246 | /// ``` |
| 247 | /// use predicates::prelude::*; |
| 248 | /// |
| 249 | /// let predicate_fn = predicate::le(5); |
| 250 | /// assert_eq!(true, predicate_fn.eval(&4)); |
| 251 | /// assert_eq!(true, predicate_fn.eval(&5)); |
| 252 | /// assert_eq!(false, predicate_fn.eval(&6)); |
| 253 | /// ``` |
| 254 | pub fn le<T>(constant: T) -> OrdPredicate<T> |
| 255 | where |
| 256 | T: PartialOrd + fmt::Debug, |
| 257 | { |
| 258 | OrdPredicate { |
| 259 | constant, |
| 260 | op: OrdOps::LessThanOrEqual, |
| 261 | } |
| 262 | } |
| 263 | |
| 264 | /// Creates a new predicate that will return `true` when the given `variable` is |
| 265 | /// greater than or equal to a pre-defined value. |
| 266 | /// |
| 267 | /// # Examples |
| 268 | /// |
| 269 | /// ``` |
| 270 | /// use predicates::prelude::*; |
| 271 | /// |
| 272 | /// let predicate = predicate::ge(5); |
| 273 | /// assert_eq!(false, predicate.eval(&4)); |
| 274 | /// assert_eq!(true, predicate.eval(&5)); |
| 275 | /// assert_eq!(true, predicate.eval(&6)); |
| 276 | /// ``` |
| 277 | pub fn ge<T>(constant: T) -> OrdPredicate<T> |
| 278 | where |
| 279 | T: PartialOrd + fmt::Debug, |
| 280 | { |
| 281 | OrdPredicate { |
| 282 | constant, |
| 283 | op: OrdOps::GreaterThanOrEqual, |
| 284 | } |
| 285 | } |
| 286 | |
| 287 | /// Creates a new predicate that will return `true` when the given `variable` is |
| 288 | /// greater than a pre-defined value. |
| 289 | /// |
| 290 | /// # Examples |
| 291 | /// |
| 292 | /// ``` |
| 293 | /// use predicates::prelude::*; |
| 294 | /// |
| 295 | /// let predicate_fn = predicate::gt(5); |
| 296 | /// assert_eq!(false, predicate_fn.eval(&4)); |
| 297 | /// assert_eq!(false, predicate_fn.eval(&5)); |
| 298 | /// assert_eq!(true, predicate_fn.eval(&6)); |
| 299 | /// ``` |
| 300 | pub fn gt<T>(constant: T) -> OrdPredicate<T> |
| 301 | where |
| 302 | T: PartialOrd + fmt::Debug, |
| 303 | { |
| 304 | OrdPredicate { |
| 305 | constant, |
| 306 | op: OrdOps::GreaterThan, |
| 307 | } |
| 308 | } |
| 309 | |