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
31unsafe impl<F, T> Send for FnPredicate<F, T>
32where
33 F: Send + Fn(&T) -> bool,
34 T: ?Sized,
35{
36}
37
38unsafe impl<F, T> Sync for FnPredicate<F, T>
39where
40 F: Sync + Fn(&T) -> bool,
41 T: ?Sized,
42{
43}
44
45impl<F, T> FnPredicate<F, T>
46where
47 F: Fn(&T) -> bool,
48 T: ?Sized,
49{
50 /// Provide a descriptive name for this function.
51 ///
52 /// # Examples
53 ///
54 /// ```
55 /// use predicates::prelude::*;
56 ///
57 /// struct Example {
58 /// string: String,
59 /// number: i32,
60 /// }
61 ///
62 /// let string_check = predicate::function(|x: &Example| x.string == "hello")
63 /// .fn_name("is_hello");
64 /// println!("predicate: {}", string_check);
65 /// ```
66 pub fn fn_name(mut self, name: &'static str) -> Self {
67 self.name = name;
68 self
69 }
70}
71
72impl<F, T> Predicate<T> for FnPredicate<F, T>
73where
74 F: Fn(&T) -> bool,
75 T: ?Sized,
76{
77 fn eval(&self, variable: &T) -> bool {
78 (self.function)(variable)
79 }
80
81 fn find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>> {
82 utils::default_find_case(self, expected, variable)
83 }
84}
85
86impl<F, T> reflection::PredicateReflection for FnPredicate<F, T>
87where
88 F: Fn(&T) -> bool,
89 T: ?Sized,
90{
91}
92
93impl<F, T> fmt::Display for FnPredicate<F, T>
94where
95 F: Fn(&T) -> bool,
96 T: ?Sized,
97{
98 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99 let palette = crate::Palette::current();
100 write!(
101 f,
102 "{}({})",
103 palette.description.paint(self.name),
104 palette.var.paint("var"),
105 )
106 }
107}
108
109/// Creates a new predicate that wraps over the given function. The returned
110/// type implements `Predicate` and therefore has all combinators available to
111/// it.
112///
113/// # Examples
114///
115/// ```
116/// use predicates::prelude::*;
117///
118/// struct Example {
119/// string: String,
120/// number: i32,
121/// }
122///
123/// let string_check = predicate::function(|x: &Example| x.string == "hello");
124/// let number_check = predicate::function(|x: &Example| x.number == 42);
125/// let predicate_fn = string_check.and(number_check);
126/// let good_example = Example { string: "hello".into(), number: 42 };
127/// assert_eq!(true, predicate_fn.eval(&good_example));
128/// let bad_example = Example { string: "goodbye".into(), number: 0 };
129/// assert_eq!(false, predicate_fn.eval(&bad_example));
130/// ```
131pub fn function<F, T>(function: F) -> FnPredicate<F, T>
132where
133 F: Fn(&T) -> bool,
134 T: ?Sized,
135{
136 FnPredicate {
137 function,
138 name: "fn",
139 _phantom: PhantomData,
140 }
141}
142
143#[test]
144fn str_function() {
145 let f = function(|x: &str| x == "hello");
146 assert!(f.eval("hello"));
147 assert!(!f.eval("goodbye"));
148}
149