predicates/function.rs
1// Copyright (c) 2018 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` for wrapping a `Fn(&T) -> bool`
10
11use std::fmt;
12use std::marker::PhantomData;
13
14use crate::reflection;
15use crate::utils;
16use crate::Predicate;
17
18/// Predicate that wraps a function over a reference that returns a `bool`.
19/// This type is returned by the `predicate::function` function.
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub struct FnPredicate<F, T>
22where
23 F: Fn(&T) -> bool,
24 T: ?Sized,
25{
26 function: F,
27 name: &'static str,
28 _phantom: PhantomData<T>,
29}
30
31impl<F, T> FnPredicate<F, T>
32where
33 F: Fn(&T) -> bool,
34 T: ?Sized,
35{
36 /// Provide a descriptive name for this function.
37 ///
38 /// # Examples
39 ///
40 /// ```
41 /// use predicates::prelude::*;
42 ///
43 /// struct Example {
44 /// string: String,
45 /// number: i32,
46 /// }
47 ///
48 /// let string_check = predicate::function(|x: &Example| x.string == "hello")
49 /// .fn_name("is_hello");
50 /// println!("predicate: {}", string_check);
51 /// ```
52 pub fn fn_name(mut self, name: &'static str) -> Self {
53 self.name = name;
54 self
55 }
56}
57
58impl<F, T> Predicate<T> for FnPredicate<F, T>
59where
60 F: Fn(&T) -> bool,
61 T: ?Sized,
62{
63 fn eval(&self, variable: &T) -> bool {
64 (self.function)(variable)
65 }
66
67 fn find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>> {
68 utils::default_find_case(self, expected, variable)
69 }
70}
71
72impl<F, T> reflection::PredicateReflection for FnPredicate<F, T>
73where
74 F: Fn(&T) -> bool,
75 T: ?Sized,
76{
77}
78
79impl<F, T> fmt::Display for FnPredicate<F, T>
80where
81 F: Fn(&T) -> bool,
82 T: ?Sized,
83{
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 write!(f, "{}(var)", self.name)
86 }
87}
88
89/// Creates a new predicate that wraps over the given function. The returned
90/// type implements `Predicate` and therefore has all combinators available to
91/// it.
92///
93/// # Examples
94///
95/// ```
96/// use predicates::prelude::*;
97///
98/// struct Example {
99/// string: String,
100/// number: i32,
101/// }
102///
103/// let string_check = predicate::function(|x: &Example| x.string == "hello");
104/// let number_check = predicate::function(|x: &Example| x.number == 42);
105/// let predicate_fn = string_check.and(number_check);
106/// let good_example = Example { string: "hello".into(), number: 42 };
107/// assert_eq!(true, predicate_fn.eval(&good_example));
108/// let bad_example = Example { string: "goodbye".into(), number: 0 };
109/// assert_eq!(false, predicate_fn.eval(&bad_example));
110/// ```
111pub fn function<F, T>(function: F) -> FnPredicate<F, T>
112where
113 F: Fn(&T) -> bool,
114 T: ?Sized,
115{
116 FnPredicate {
117 function,
118 name: "fn",
119 _phantom: PhantomData,
120 }
121}
122
123#[test]
124fn str_function() {
125 let f = function(|x: &str| x == "hello");
126 assert!(f.eval(&"hello"));
127 assert!(!f.eval(&"goodbye"));
128}