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/licenses/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//! Name predicate expressions.
10
11use std::fmt;
12use std::marker::PhantomData;
13
14use crate::reflection;
15use crate::Predicate;
16
17/// Augment an existing predicate with a name.
18///
19/// This is created by the `PredicateNameExt::name` function.
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub struct NamePredicate<M, Item>
22where
23 M: Predicate<Item>,
24 Item: ?Sized,
25{
26 inner: M,
27 name: &'static str,
28 _phantom: PhantomData<Item>,
29}
30
31unsafe impl<M, Item> Send for NamePredicate<M, Item>
32where
33 M: Predicate<Item> + Send,
34 Item: ?Sized,
35{
36}
37
38unsafe impl<M, Item> Sync for NamePredicate<M, Item>
39where
40 M: Predicate<Item> + Sync,
41 Item: ?Sized,
42{
43}
44
45impl<M, Item> Predicate<Item> for NamePredicate<M, Item>
46where
47 M: Predicate<Item>,
48 Item: ?Sized,
49{
50 fn eval(&self, item: &Item) -> bool {
51 self.inner.eval(item)
52 }
53
54 fn find_case<'a>(&'a self, expected: bool, variable: &Item) -> Option<reflection::Case<'a>> {
55 self.inner
56 .find_case(expected, variable)
57 .map(|child_case| reflection::Case::new(Some(self), expected).add_child(child_case))
58 }
59}
60
61impl<M, Item> reflection::PredicateReflection for NamePredicate<M, Item>
62where
63 M: Predicate<Item>,
64 Item: ?Sized,
65{
66 fn children<'a>(&'a self) -> Box<dyn Iterator<Item = reflection::Child<'a>> + 'a> {
67 let params = vec![reflection::Child::new(self.name, &self.inner)];
68 Box::new(params.into_iter())
69 }
70}
71
72impl<M, Item> fmt::Display for NamePredicate<M, Item>
73where
74 M: Predicate<Item>,
75 Item: ?Sized,
76{
77 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78 let palette = crate::Palette::current();
79 write!(f, "{}", palette.description.paint(self.name))
80 }
81}
82
83/// `Predicate` extension that adds naming predicate expressions.
84pub trait PredicateNameExt<Item: ?Sized>
85where
86 Self: Predicate<Item>,
87{
88 /// Name a predicate expression.
89 ///
90 /// # Examples
91 ///
92 /// ```
93 /// use predicates::prelude::*;
94 ///
95 /// let predicate_fn = predicate::str::is_empty().not().name("non-empty");
96 /// println!("{}", predicate_fn);
97 /// ```
98 fn name(self, name: &'static str) -> NamePredicate<Self, Item>
99 where
100 Self: Sized,
101 {
102 NamePredicate {
103 inner: self,
104 name,
105 _phantom: PhantomData,
106 }
107 }
108}
109
110impl<P, Item> PredicateNameExt<Item> for P
111where
112 P: Predicate<Item>,
113 Item: ?Sized,
114{
115}
116