1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
// Copyright (c) 2018 The predicates-rs Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/license/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Composable first-order predicate functions.
//!
//! This library implements an interface to "predicates" - boolean-valued
//! functions of one argument. This allows combinatorial logic to be created and
//! assembled at runtime and then used one or more times for evaluating values.
//! This sort of object is really useful when creating filters and checks that
//! can be changed at runtime with user interaction - it allows a clean
//! separation of concerns where the configuration code can be used to build up
//! a predicate, and then that predicate can be given to the code that does the
//! actual filtering without the filtering code knowing anything about user
//! configuration. See the examples for how this can work.
//!
//! ## Installation
//!
//! Add this to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! predicates = "2.1.5"
//! ```
//!
//! A [prelude] is available to bring in all extension traits as well as providing
//! `prelude::predicate` which focuses on the 90% case of the API.
//! ```rust
//! use predicates::prelude::*;
//! ```
//!
//! ## Examples
//!
//! The simplest predicates are [`predicate::always`] and [`predicate::never`], which always
//! returns `true` and always returns `false`, respectively. The values are simply ignored when
//! evaluating against these predicates:
//! ```rust
//! use predicates::prelude::*;
//!
//! let always_true = predicate::always();
//! assert_eq!(true, always_true.eval(&5));
//! let always_false = predicate::never();
//! assert_eq!(false, always_false.eval(&5));
//! ```
//!
//! Pre-made predicates are available for types that implement the `PartialOrd` and
//! `PartialEq` traits. The following example uses `lt`, but `eq`, `ne`, `le`, `gt`,
//! `ge` are also available.
//! ```rust
//! use predicates::prelude::*;
//!
//! let less_than_ten = predicate::lt(10);
//! assert_eq!(true, less_than_ten.eval(&9));
//! assert_eq!(false, less_than_ten.eval(&11));
//! ```
//!
//! Any function over a reference to the desired `Item` that returns `bool`
//! can easily be made into a `Predicate` using the [`predicate::function`]
//! function.
//! ```rust
//! use predicates::prelude::*;
//!
//! let bound = 5;
//! let predicate_fn = predicate::function(|&x| x >= bound);
//! let between_5_and_10 = predicate_fn.and(predicate::le(10));
//! assert_eq!(true, between_5_and_10.eval(&7));
//! assert_eq!(false, between_5_and_10.eval(&3));
//! ```
//!
//! The `Predicate` type is actually a trait, and that trait implements a
//! number of useful combinator functions. For example, evaluating for a value
//! between two other values can be accomplished as follows:
//! ```rust
//! use predicates::prelude::*;
//!
//! let between_5_and_10 = predicate::ge(5).and(predicate::le(10));
//! assert_eq!(true, between_5_and_10.eval(&7));
//! assert_eq!(false, between_5_and_10.eval(&11));
//! assert_eq!(false, between_5_and_10.eval(&4));
//! ```
//!
//! The `Predicate` trait is pretty simple, the core of it is an
//! implementation of a `eval` function that takes a single argument and
//! returns a `bool`. Implementing a custom `Predicate` still allows all the
//! usual combinators of the `Predicate` trait to work!
//! ```rust
//! use std::fmt;
//!
//! use predicates::prelude::*;
//!
//! struct IsTheAnswer;
//! impl Predicate<i32> for IsTheAnswer {
//! fn eval(&self, variable: &i32) -> bool {
//! *variable == 42
//! }
//! }
//! impl predicates::reflection::PredicateReflection for IsTheAnswer {}
//! impl fmt::Display for IsTheAnswer {
//! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
//! write!(f, "var.is_the_answer()")
//! }
//! }
//!
//! assert_eq!(true, IsTheAnswer.eval(&42));
//! let almost_the_answer = IsTheAnswer.or(predicate::in_iter(vec![41, 43]));
//! assert_eq!(true, almost_the_answer.eval(&41));
//! ```
//!
//! ## Choosing a Predicate
//!
//! General predicates
//! - [`predicate::always`]
//! - [`predicate::never`]
//! - [`predicate::function`]
//! - [`predicate::in_iter`]: Specified value must be in the `Iterator`.
//! - [`predicate::in_iter(...).sort`]: Optimization for repeatedly called predicates.
//! - [`predicate::in_hash`]: Optimization for repeatedly called predicates.
//! - [`predicate::eq`]
//! - [`predicate::float::is_close`]: Use this instead of `eq` for floating point values.
//! - [`predicate::ne`]
//! - [`predicate::ge`]
//! - [`predicate::gt`]
//! - [`predicate::le`]
//! - [`predicate::lt`]
//! - [`predicate::name`]: Improve readability of failure reporting by providing a meaningful name.
//!
//! Combinators
//! - [`pred_a.and(pred_b)`]: Both predicates must succeed.
//! - [`pred_a.or(pred_b)`]: One or both predicates must succeed.
//! - [`pred_a.not()`]: The predicate must fail.
//!
//! `String` predicates
//! - [`predicate::str::is_empty`]: Specified string must be empty
//! - [`str_pred = predicate::path::eq_file(...).utf8`]: Specified string must equal the contents
//! of the given file.
//! - [`predicate::str::diff`]: Same as `eq` except report a diff. See [`DifferencePredicate`]
//! for more features.
//! - [`predicate::str::starts_with`]: Specified string must start with the given needle.
//! - [`predicate::str::ends_with`]: Specified string must end with the given needle.
//! - [`predicate::str::contains`]: Specified string must contain the given needle.
//! - [`predicate::str::contains(...).count`]: Required number of times the needle must show up.
//! - [`predicate::str::is_match`]: Specified string must match the given regex.
//! - [`predicate::str::is_match(...).count`]: Required number of times the match must show up.
//! - [`str_pred.trim`]: Trim whitespace before passing it to `str_pred`.
//! - [`str_pred.normalize`]: Normalize the line endings before passing it to `str_pred`.
//! - [`bytes_pred = str_pred.from_utf8()`]: Reuse string predicates in other contexts, like the
//! file system.
//!
//! File system predicates
//! - [`predicate::path::exists`]: Specified path must exist on disk.
//! - [`predicate::path::missing`]: Specified path must not exist on disk.
//! - [`predicate::path::is_dir`]: Specified path is a directory.
//! - [`predicate::path::is_file`]: Specified path is a file.
//! - [`predicate::path::is_symlink`]: Specified path is a symlink.
//! - [`path_pred = predicate::path::eq_file`]: Specified path's contents must equal the contents of the given
//! file.
//! - [`path_pred = bytes_pred.from_file_path`]: Specified path's contents must equal the `bytes_pred`.
//!
//! [`DifferencePredicate`]: crate::str::DifferencePredicate
//! [`bytes_pred = str_pred.from_utf8()`]: prelude::PredicateStrExt::from_utf8()
//! [`path_pred = bytes_pred.from_file_path`]: prelude::PredicateFileContentExt::from_file_path()
//! [`path_pred = predicate::path::eq_file`]: prelude::predicate::path::eq_file()
//! [`pred_a.and(pred_b)`]: boolean::PredicateBooleanExt::and()
//! [`pred_a.not()`]: boolean::PredicateBooleanExt::not()
//! [`pred_a.or(pred_b)`]: boolean::PredicateBooleanExt::or()
//! [`predicate::always`]: constant::always()
//! [`predicate::eq`]: ord::eq()
//! [`predicate::float::is_close`]: prelude::predicate::float::is_close()
//! [`predicate::function`]: function::function()
//! [`predicate::ge`]: ord::ge()
//! [`predicate::gt`]: ord::gt()
//! [`predicate::in_hash`]: iter::in_hash()
//! [`predicate::in_iter(...).sort`]: iter::InPredicate::sort()
//! [`predicate::in_iter`]: iter::in_iter()
//! [`predicate::le`]: ord::le()
//! [`predicate::lt`]: ord::lt()
//! [`predicate::name`]: name::PredicateNameExt::name()
//! [`predicate::ne`]: ord::ne()
//! [`predicate::never`]: constant::never()
//! [`predicate::path::exists`]: prelude::predicate::path::exists()
//! [`predicate::path::is_dir`]: prelude::predicate::path::is_dir()
//! [`predicate::path::is_file`]: prelude::predicate::path::is_file()
//! [`predicate::path::is_symlink`]: prelude::predicate::path::is_symlink()
//! [`predicate::path::missing`]: prelude::predicate::path::missing()
//! [`predicate::str::contains(...).count`]: str::ContainsPredicate::count()
//! [`predicate::str::contains`]: prelude::predicate::str::contains()
//! [`predicate::str::diff`]: prelude::predicate::str::diff()
//! [`predicate::str::ends_with`]: prelude::predicate::str::ends_with()
//! [`predicate::str::is_empty`]: prelude::predicate::str::is_empty()
//! [`predicate::str::is_match(...).count`]: str::RegexPredicate::count()
//! [`predicate::str::is_match`]: prelude::predicate::str::is_match()
//! [`predicate::str::starts_with`]: prelude::predicate::str::starts_with()
//! [`str_pred = predicate::path::eq_file(...).utf8`]: path::BinaryFilePredicate::utf8()
//! [`str_pred.normalize`]: prelude::PredicateStrExt::normalize()
//! [`str_pred.trim`]: prelude::PredicateStrExt::trim()
#![warn(missing_docs, missing_debug_implementations)]
pub mod prelude;
pub use predicates_core::*;
mod boxed;
pub use crate::boxed::*;
// core predicates
pub mod constant;
pub mod function;
pub mod iter;
pub mod name;
pub mod ord;
// combinators
pub mod boolean;
// specialized primitive `Predicate` types
pub mod float;
pub mod path;
pub mod str;
mod color;
use color::Palette;
mod utils;