predicates-3.1.0/.cargo_vcs_info.json0000644000000001360000000000100131600ustar { "git": { "sha1": "d16d9cb4af2202ea8eafde1f2cb5f281729a4d85" }, "path_in_vcs": "" }predicates-3.1.0/Cargo.lock0000644000000063540000000000100111430ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "aho-corasick" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a" dependencies = [ "memchr", ] [[package]] name = "anstyle" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "difflib" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" [[package]] name = "float-cmp" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" dependencies = [ "num-traits", ] [[package]] name = "memchr" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "normalize-line-endings" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" [[package]] name = "num-traits" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", ] [[package]] name = "predicates" version = "3.1.0" dependencies = [ "anstyle", "difflib", "float-cmp", "normalize-line-endings", "predicates-core", "predicates-tree", "regex", ] [[package]] name = "predicates-core" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" [[package]] name = "predicates-tree" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" dependencies = [ "predicates-core", "termtree", ] [[package]] name = "regex" version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" [[package]] name = "termtree" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" predicates-3.1.0/Cargo.toml0000644000000056150000000000100111650ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.70" name = "predicates" version = "3.1.0" authors = ["Nick Stevens "] include = [ "build.rs", "src/**/*", "Cargo.toml", "LICENSE*", "README.md", "benches/**/*", "examples/**/*", ] description = "An implementation of boolean-valued predicate functions." homepage = "https://github.com/assert-rs/predicates-rs" documentation = "https://docs.rs/predicates" readme = "README.md" keywords = [ "predicate", "boolean", "combinatorial", "match", "logic", ] categories = [ "data-structures", "rust-patterns", ] license = "MIT OR Apache-2.0" repository = "https://github.com/assert-rs/predicates-rs" [package.metadata.docs.rs] all-features = true rustdoc-args = [ "--cfg", "docsrs", ] [[package.metadata.release.pre-release-replacements]] exactly = 1 file = "src/lib.rs" replace = "predicates = \"{{version}}\"" search = "predicates = \".*\"" [[package.metadata.release.pre-release-replacements]] exactly = 1 file = "README.md" replace = "predicates = \"{{version}}\"" search = "predicates = \".*\"" [[package.metadata.release.pre-release-replacements]] file = "CHANGELOG.md" min = 1 replace = "{{version}}" search = "Unreleased" [[package.metadata.release.pre-release-replacements]] exactly = 1 file = "CHANGELOG.md" replace = "...{{tag_name}}" search = '\.\.\.HEAD' [[package.metadata.release.pre-release-replacements]] file = "CHANGELOG.md" min = 1 replace = "{{date}}" search = "ReleaseDate" [[package.metadata.release.pre-release-replacements]] exactly = 1 file = "CHANGELOG.md" replace = """ ## [Unreleased] - ReleaseDate """ search = "" [[package.metadata.release.pre-release-replacements]] exactly = 1 file = "CHANGELOG.md" replace = """ [Unreleased]: https://github.com/assert-rs/predicates-rs/compare/{{tag_name}}...HEAD""" search = "" [dependencies.anstyle] version = "1.0.0" [dependencies.difflib] version = "0.4" optional = true [dependencies.float-cmp] version = "0.9" optional = true [dependencies.normalize-line-endings] version = "0.3.0" optional = true [dependencies.predicates-core] version = "1.0" [dependencies.regex] version = "1.0" optional = true [dev-dependencies.predicates-tree] version = "1.0" [features] color = [] default = [ "diff", "regex", "float-cmp", "normalize-line-endings", "color", ] diff = ["dep:difflib"] unstable = [] predicates-3.1.0/Cargo.toml.orig000064400000000000000000000043161046102023000146430ustar 00000000000000[workspace] members = ["crates/*"] resolver = "2" [workspace.package] license = "MIT OR Apache-2.0" edition = "2021" rust-version = "1.70" # MSRV include = [ "build.rs", "src/**/*", "Cargo.toml", "LICENSE*", "README.md", "benches/**/*", "examples/**/*" ] [package] name = "predicates" version = "3.1.0" description = "An implementation of boolean-valued predicate functions." authors = ["Nick Stevens "] repository = "https://github.com/assert-rs/predicates-rs" homepage = "https://github.com/assert-rs/predicates-rs" documentation = "https://docs.rs/predicates" readme = "README.md" categories = ["data-structures", "rust-patterns"] keywords = ["predicate", "boolean", "combinatorial", "match", "logic"] license.workspace = true edition.workspace = true rust-version.workspace = true include.workspace = true [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] [package.metadata.release] pre-release-replacements = [ {file="src/lib.rs", search="predicates = \".*\"", replace="predicates = \"{{version}}\"", exactly=1}, {file="README.md", search="predicates = \".*\"", replace="predicates = \"{{version}}\"", exactly=1}, {file="CHANGELOG.md", search="Unreleased", replace="{{version}}", min=1}, {file="CHANGELOG.md", search="\\.\\.\\.HEAD", replace="...{{tag_name}}", exactly=1}, {file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}", min=1}, {file="CHANGELOG.md", search="", replace="\n## [Unreleased] - ReleaseDate\n", exactly=1}, {file="CHANGELOG.md", search="", replace="\n[Unreleased]: https://github.com/assert-rs/predicates-rs/compare/{{tag_name}}...HEAD", exactly=1}, ] [dependencies] predicates-core = { version = "1.0", path = "crates/core" } difflib = { version = "0.4", optional = true } normalize-line-endings = { version = "0.3.0", optional = true } regex = { version="1.0", optional = true } float-cmp = { version="0.9", optional = true } anstyle = "1.0.0" [dev-dependencies] predicates-tree = { version = "1.0", path = "crates/tree" } [features] default = ["diff", "regex", "float-cmp", "normalize-line-endings", "color"] diff = ["dep:difflib"] unstable = [] color = [] predicates-3.1.0/LICENSE-APACHE000064400000000000000000000261351046102023000137030ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. predicates-3.1.0/LICENSE-MIT000064400000000000000000000020461046102023000134060ustar 00000000000000Copyright (c) Individual contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. predicates-3.1.0/README.md000064400000000000000000000023231046102023000132270ustar 00000000000000# predicates-rs > An implementation of **boolean-valued predicate functions** in Rust. [![Documentation](https://img.shields.io/badge/docs-master-blue.svg)](https://docs.rs/predicates) ![License](https://img.shields.io/crates/l/predicates.svg) [![Crates.io](https://img.shields.io/crates/v/predicates.svg?maxAge=2592000)](https://crates.io/crates/predicates) [Changelog](https://github.com/assert-rs/predicates-rs/blob/master/CHANGELOG.md) ## Usage First, add this to your `Cargo.toml`: ```toml [dependencies] predicates = "3.1.0" ``` Next, add this to your crate: ```rust extern crate predicates; use predicates::prelude::*; ``` For more information on using predicates, look at the [documentation](https://docs.rs/predicates) ## License `predicates-rs` is distributed under the terms of both the MIT license and the Apache License (Version 2.0). * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) * MIT license ([LICENSE-MIT](LICENSE-MIT) or ) ## Credits Big thanks to [futures-rs](https://github.com/alexcrichton/futures-rs), whose slick API design informed a lot of decisions made on the API design of this library. predicates-3.1.0/examples/case_tree.rs000064400000000000000000000004651046102023000160730ustar 00000000000000use predicates::prelude::*; use predicates_tree::CaseTreeExt; fn main() { let pred = predicate::ne(5).not().and(predicate::ge(5)); let var = 5; let case = pred.find_case(true, &var); if let Some(case) = case { println!("var is {}", var); println!("{}", case.tree()); } } predicates-3.1.0/src/boolean.rs000064400000000000000000000312461046102023000145320ustar 00000000000000// Copyright (c) 2018 The predicates-rs Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Definition of boolean logic combinators over `Predicate`s. use std::fmt; use std::marker::PhantomData; use crate::reflection; use crate::Predicate; /// Predicate that combines two `Predicate`s, returning the AND of the results. /// /// This is created by the `Predicate::and` function. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct AndPredicate where M1: Predicate, M2: Predicate, Item: ?Sized, { a: M1, b: M2, _phantom: PhantomData, } unsafe impl Send for AndPredicate where M1: Predicate + Send, M2: Predicate + Send, Item: ?Sized, { } unsafe impl Sync for AndPredicate where M1: Predicate + Sync, M2: Predicate + Sync, Item: ?Sized, { } impl AndPredicate where M1: Predicate, M2: Predicate, Item: ?Sized, { /// Create a new `AndPredicate` over predicates `a` and `b`. pub fn new(a: M1, b: M2) -> AndPredicate { AndPredicate { a, b, _phantom: PhantomData, } } } impl Predicate for AndPredicate where M1: Predicate, M2: Predicate, Item: ?Sized, { fn eval(&self, item: &Item) -> bool { self.a.eval(item) && self.b.eval(item) } fn find_case<'a>(&'a self, expected: bool, variable: &Item) -> Option> { let child_a = self.a.find_case(expected, variable); match (expected, child_a) { (true, Some(child_a)) => self.b.find_case(expected, variable).map(|child_b| { reflection::Case::new(Some(self), expected) .add_child(child_a) .add_child(child_b) }), (true, None) => None, (false, Some(child_a)) => { Some(reflection::Case::new(Some(self), expected).add_child(child_a)) } (false, None) => self .b .find_case(expected, variable) .map(|child_b| reflection::Case::new(Some(self), expected).add_child(child_b)), } } } impl reflection::PredicateReflection for AndPredicate where M1: Predicate, M2: Predicate, Item: ?Sized, { fn children<'a>(&'a self) -> Box> + 'a> { let params = vec![ reflection::Child::new("left", &self.a), reflection::Child::new("right", &self.b), ]; Box::new(params.into_iter()) } } impl fmt::Display for AndPredicate where M1: Predicate, M2: Predicate, Item: ?Sized, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "({} && {})", self.a, self.b) } } #[cfg(test)] mod test_and { use crate::prelude::*; #[test] fn find_case_true() { assert!(predicate::always() .and(predicate::always()) .find_case(true, &5) .is_some()); } #[test] fn find_case_true_left_fail() { assert!(predicate::never() .and(predicate::always()) .find_case(true, &5) .is_none()); } #[test] fn find_case_true_right_fail() { assert!(predicate::always() .and(predicate::never()) .find_case(true, &5) .is_none()); } #[test] fn find_case_true_fails() { assert!(predicate::never() .and(predicate::never()) .find_case(true, &5) .is_none()); } #[test] fn find_case_false() { assert!(predicate::never() .and(predicate::never()) .find_case(false, &5) .is_some()); } #[test] fn find_case_false_fails() { assert!(predicate::always() .and(predicate::always()) .find_case(false, &5) .is_none()); } #[test] fn find_case_false_left_fail() { assert!(predicate::never() .and(predicate::always()) .find_case(false, &5) .is_some()); } #[test] fn find_case_false_right_fail() { assert!(predicate::always() .and(predicate::never()) .find_case(false, &5) .is_some()); } } /// Predicate that combines two `Predicate`s, returning the OR of the results. /// /// This is created by the `Predicate::or` function. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct OrPredicate where M1: Predicate, M2: Predicate, Item: ?Sized, { a: M1, b: M2, _phantom: PhantomData, } unsafe impl Send for OrPredicate where M1: Predicate + Send, M2: Predicate + Send, Item: ?Sized, { } unsafe impl Sync for OrPredicate where M1: Predicate + Sync, M2: Predicate + Sync, Item: ?Sized, { } impl OrPredicate where M1: Predicate, M2: Predicate, Item: ?Sized, { /// Create a new `OrPredicate` over predicates `a` and `b`. pub fn new(a: M1, b: M2) -> OrPredicate { OrPredicate { a, b, _phantom: PhantomData, } } } impl Predicate for OrPredicate where M1: Predicate, M2: Predicate, Item: ?Sized, { fn eval(&self, item: &Item) -> bool { self.a.eval(item) || self.b.eval(item) } fn find_case<'a>(&'a self, expected: bool, variable: &Item) -> Option> { let child_a = self.a.find_case(expected, variable); match (expected, child_a) { (true, Some(child_a)) => { Some(reflection::Case::new(Some(self), expected).add_child(child_a)) } (true, None) => self .b .find_case(expected, variable) .map(|child_b| reflection::Case::new(Some(self), expected).add_child(child_b)), (false, Some(child_a)) => self.b.find_case(expected, variable).map(|child_b| { reflection::Case::new(Some(self), expected) .add_child(child_a) .add_child(child_b) }), (false, None) => None, } } } impl reflection::PredicateReflection for OrPredicate where M1: Predicate, M2: Predicate, Item: ?Sized, { fn children<'a>(&'a self) -> Box> + 'a> { let params = vec![ reflection::Child::new("left", &self.a), reflection::Child::new("right", &self.b), ]; Box::new(params.into_iter()) } } impl fmt::Display for OrPredicate where M1: Predicate, M2: Predicate, Item: ?Sized, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "({} || {})", self.a, self.b) } } #[cfg(test)] mod test_or { use crate::prelude::*; #[test] fn find_case_true() { assert!(predicate::always() .or(predicate::always()) .find_case(true, &5) .is_some()); } #[test] fn find_case_true_left_fail() { assert!(predicate::never() .or(predicate::always()) .find_case(true, &5) .is_some()); } #[test] fn find_case_true_right_fail() { assert!(predicate::always() .or(predicate::never()) .find_case(true, &5) .is_some()); } #[test] fn find_case_true_fails() { assert!(predicate::never() .or(predicate::never()) .find_case(true, &5) .is_none()); } #[test] fn find_case_false() { assert!(predicate::never() .or(predicate::never()) .find_case(false, &5) .is_some()); } #[test] fn find_case_false_fails() { assert!(predicate::always() .or(predicate::always()) .find_case(false, &5) .is_none()); } #[test] fn find_case_false_left_fail() { assert!(predicate::never() .or(predicate::always()) .find_case(false, &5) .is_none()); } #[test] fn find_case_false_right_fail() { assert!(predicate::always() .or(predicate::never()) .find_case(false, &5) .is_none()); } } /// Predicate that returns a `Predicate` taking the logical NOT of the result. /// /// This is created by the `Predicate::not` function. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct NotPredicate where M: Predicate, Item: ?Sized, { inner: M, _phantom: PhantomData, } unsafe impl Send for NotPredicate where M: Predicate + Send, Item: ?Sized, { } unsafe impl Sync for NotPredicate where M: Predicate + Sync, Item: ?Sized, { } impl NotPredicate where M: Predicate, Item: ?Sized, { /// Create a new `NotPredicate` over predicate `inner`. pub fn new(inner: M) -> NotPredicate { NotPredicate { inner, _phantom: PhantomData, } } } impl Predicate for NotPredicate where M: Predicate, Item: ?Sized, { fn eval(&self, item: &Item) -> bool { !self.inner.eval(item) } fn find_case<'a>(&'a self, expected: bool, variable: &Item) -> Option> { self.inner .find_case(!expected, variable) .map(|child| reflection::Case::new(Some(self), expected).add_child(child)) } } impl reflection::PredicateReflection for NotPredicate where M: Predicate, Item: ?Sized, { fn children<'a>(&'a self) -> Box> + 'a> { let params = vec![reflection::Child::new("predicate", &self.inner)]; Box::new(params.into_iter()) } } impl fmt::Display for NotPredicate where M: Predicate, Item: ?Sized, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "(! {})", self.inner) } } /// `Predicate` extension that adds boolean logic. pub trait PredicateBooleanExt where Self: Predicate, { /// Compute the logical AND of two `Predicate` results, returning the result. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let predicate_fn1 = predicate::always().and(predicate::always()); /// let predicate_fn2 = predicate::always().and(predicate::never()); /// assert_eq!(true, predicate_fn1.eval(&4)); /// assert_eq!(false, predicate_fn2.eval(&4)); fn and(self, other: B) -> AndPredicate where B: Predicate, Self: Sized, { AndPredicate::new(self, other) } /// Compute the logical OR of two `Predicate` results, returning the result. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let predicate_fn1 = predicate::always().or(predicate::always()); /// let predicate_fn2 = predicate::always().or(predicate::never()); /// let predicate_fn3 = predicate::never().or(predicate::never()); /// assert_eq!(true, predicate_fn1.eval(&4)); /// assert_eq!(true, predicate_fn2.eval(&4)); /// assert_eq!(false, predicate_fn3.eval(&4)); fn or(self, other: B) -> OrPredicate where B: Predicate, Self: Sized, { OrPredicate::new(self, other) } /// Compute the logical NOT of a `Predicate`, returning the result. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let predicate_fn1 = predicate::always().not(); /// let predicate_fn2 = predicate::never().not(); /// assert_eq!(false, predicate_fn1.eval(&4)); /// assert_eq!(true, predicate_fn2.eval(&4)); fn not(self) -> NotPredicate where Self: Sized, { NotPredicate::new(self) } } impl PredicateBooleanExt for P where P: Predicate, Item: ?Sized, { } predicates-3.1.0/src/boxed.rs000064400000000000000000000064261046102023000142160ustar 00000000000000// Copyright (c) 2018 The predicates-rs Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Predicate that can wrap other dynamically-called predicates in an //! easy-to-manage type. use std::fmt; use crate::reflection; use crate::utils; use crate::Predicate; /// `Predicate` that wraps another `Predicate` as a trait object, allowing /// sized storage of predicate types. pub struct BoxPredicate(Box + Send + Sync>); impl BoxPredicate where Item: ?Sized, { /// Creates a new `BoxPredicate`, a wrapper around a dynamically-dispatched /// `Predicate` type with useful trait impls. pub fn new>(inner: P) -> BoxPredicate where P: Send + Sync + 'static, { BoxPredicate(Box::new(inner)) } } impl fmt::Debug for BoxPredicate where Item: ?Sized, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("BoxPredicate").finish() } } impl reflection::PredicateReflection for BoxPredicate where Item: ?Sized, { fn parameters<'a>(&'a self) -> Box> + 'a> { self.0.parameters() } fn children<'a>(&'a self) -> Box> + 'a> { self.0.children() } } impl fmt::Display for BoxPredicate where Item: ?Sized, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } impl Predicate for BoxPredicate where Item: ?Sized, { fn eval(&self, variable: &Item) -> bool { self.0.eval(variable) } fn find_case<'a>(&'a self, expected: bool, variable: &Item) -> Option> { utils::default_find_case(self, expected, variable) } } /// `Predicate` extension for boxing a `Predicate`. pub trait PredicateBoxExt where Self: Predicate, { /// Returns a `BoxPredicate` wrapper around this `Predicate` type. /// /// Returns a `BoxPredicate` wrapper around this `Predicate type. The /// `BoxPredicate` type has a number of useful properties: /// /// - It stores the inner predicate as a trait object, so the type of /// `BoxPredicate` will always be the same even if steps are added or /// removed from the predicate. /// - It is a common type, allowing it to be stored in vectors or other /// collection types. /// - It implements `Debug` and `Display`. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let predicates = vec![ /// predicate::always().boxed(), /// predicate::never().boxed(), /// ]; /// assert_eq!(true, predicates[0].eval(&4)); /// assert_eq!(false, predicates[1].eval(&4)); /// ``` fn boxed(self) -> BoxPredicate where Self: Sized + Send + Sync + 'static, { BoxPredicate::new(self) } } impl PredicateBoxExt for P where P: Predicate {} predicates-3.1.0/src/color.rs000064400000000000000000000035111046102023000142230ustar 00000000000000#[derive(Copy, Clone, Debug, Default)] pub(crate) struct Palette { description: anstyle::Style, var: anstyle::Style, expected: anstyle::Style, } impl Palette { pub(crate) fn new(alternate: bool) -> Self { if alternate && cfg!(feature = "color") { Self { description: anstyle::AnsiColor::Blue.on_default() | anstyle::Effects::BOLD, var: anstyle::AnsiColor::Red.on_default() | anstyle::Effects::BOLD, expected: anstyle::AnsiColor::Green.on_default() | anstyle::Effects::BOLD, } } else { Self::plain() } } pub(crate) fn plain() -> Self { Self { description: Default::default(), var: Default::default(), expected: Default::default(), } } pub(crate) fn description(self, display: D) -> Styled { Styled::new(display, self.description) } pub(crate) fn var(self, display: D) -> Styled { Styled::new(display, self.var) } pub(crate) fn expected(self, display: D) -> Styled { Styled::new(display, self.expected) } } #[derive(Debug)] pub(crate) struct Styled { display: D, style: anstyle::Style, } impl Styled { pub(crate) fn new(display: D, style: anstyle::Style) -> Self { Self { display, style } } } impl std::fmt::Display for Styled { #[inline] fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if f.alternate() { write!(f, "{}", self.style.render())?; self.display.fmt(f)?; write!(f, "{}", self.style.render_reset())?; Ok(()) } else { self.display.fmt(f) } } } predicates-3.1.0/src/constant.rs000064400000000000000000000050301046102023000147340ustar 00000000000000// Copyright (c) 2018 The predicates-rs Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Definition of a constant (always true or always false) `Predicate`. use std::fmt; use crate::reflection; use crate::utils; use crate::Predicate; /// Predicate that always returns a constant (boolean) result. /// /// This is created by the `predicate::always` and `predicate::never` functions. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct BooleanPredicate { retval: bool, } impl Predicate for BooleanPredicate { fn eval(&self, _variable: &Item) -> bool { self.retval } fn find_case<'a>(&'a self, expected: bool, variable: &Item) -> Option> { utils::default_find_case(self, expected, variable) } } impl reflection::PredicateReflection for BooleanPredicate { fn parameters<'a>(&'a self) -> Box> + 'a> { let params = vec![reflection::Parameter::new("value", &self.retval)]; Box::new(params.into_iter()) } } impl fmt::Display for BooleanPredicate { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let palette = crate::Palette::new(f.alternate()); write!(f, "{}", palette.expected(self.retval)) } } /// Creates a new `Predicate` that always returns `true`. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let predicate_fn = predicate::always(); /// assert_eq!(true, predicate_fn.eval(&5)); /// assert_eq!(true, predicate_fn.eval(&10)); /// assert_eq!(true, predicate_fn.eval(&15)); /// // Won't work - Predicates can only operate on a single type /// // assert_eq!(true, predicate_fn.eval("hello")) /// ``` pub fn always() -> BooleanPredicate { BooleanPredicate { retval: true } } /// Creates a new `Predicate` that always returns `false`. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let predicate_fn = predicate::never(); /// assert_eq!(false, predicate_fn.eval(&5)); /// assert_eq!(false, predicate_fn.eval(&10)); /// assert_eq!(false, predicate_fn.eval(&15)); /// // Won't work - Predicates can only operate on a single type /// // assert_eq!(false, predicate_fn.eval("hello")) /// ``` pub fn never() -> BooleanPredicate { BooleanPredicate { retval: false } } predicates-3.1.0/src/float/close.rs000064400000000000000000000111131046102023000153140ustar 00000000000000// Copyright (c) 2018 The predicates-rs Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use std::fmt; use float_cmp::ApproxEq; use float_cmp::Ulps; use crate::reflection; use crate::Predicate; /// Predicate that ensures two numbers are "close" enough, understanding that rounding errors /// occur. /// /// This is created by the `predicate::float::is_close`. #[derive(Debug, Clone, Copy, PartialEq)] pub struct IsClosePredicate { target: f64, epsilon: f64, ulps: ::U, } impl IsClosePredicate { /// Set the amount of error allowed. /// /// Values `1`-`5` should work in most cases. Sometimes more control is needed and you will /// need to set `IsClosePredicate::epsilon` separately from `IsClosePredicate::ulps`. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let a = 0.15_f64 + 0.15_f64 + 0.15_f64; /// let predicate_fn = predicate::float::is_close(a).distance(5); /// ``` pub fn distance(mut self, distance: ::U) -> Self { self.epsilon = (distance as f64) * ::std::f64::EPSILON; self.ulps = distance; self } /// Set the absolute deviation allowed. /// /// This is meant to handle problems near `0`. Values `1.`-`5.` epislons should work in most /// cases. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let a = 0.15_f64 + 0.15_f64 + 0.15_f64; /// let predicate_fn = predicate::float::is_close(a).epsilon(5.0 * ::std::f64::EPSILON); /// ``` pub fn epsilon(mut self, epsilon: f64) -> Self { self.epsilon = epsilon; self } /// Set the relative deviation allowed. /// /// This is meant to handle large numbers. Values `1`-`5` should work in most cases. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let a = 0.15_f64 + 0.15_f64 + 0.15_f64; /// let predicate_fn = predicate::float::is_close(a).ulps(5); /// ``` pub fn ulps(mut self, ulps: ::U) -> Self { self.ulps = ulps; self } } impl Predicate for IsClosePredicate { fn eval(&self, variable: &f64) -> bool { variable.approx_eq( self.target, float_cmp::F64Margin { epsilon: self.epsilon, ulps: self.ulps, }, ) } fn find_case<'a>(&'a self, expected: bool, variable: &f64) -> Option> { let actual = self.eval(variable); if expected == actual { Some( reflection::Case::new(Some(self), actual) .add_product(reflection::Product::new( "actual epsilon", (variable - self.target).abs(), )) .add_product(reflection::Product::new( "actual ulps", variable.ulps(&self.target).abs(), )), ) } else { None } } } impl reflection::PredicateReflection for IsClosePredicate { fn parameters<'a>(&'a self) -> Box> + 'a> { let params = vec![ reflection::Parameter::new("epsilon", &self.epsilon), reflection::Parameter::new("ulps", &self.ulps), ]; Box::new(params.into_iter()) } } impl fmt::Display for IsClosePredicate { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let palette = crate::Palette::new(f.alternate()); write!( f, "{} {} {}", palette.var("var"), palette.description("!="), palette.expected(self.target), ) } } /// Create a new `Predicate` that ensures two numbers are "close" enough, understanding that /// rounding errors occur. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let a = 0.15_f64 + 0.15_f64 + 0.15_f64; /// let b = 0.1_f64 + 0.1_f64 + 0.25_f64; /// let predicate_fn = predicate::float::is_close(a); /// assert_eq!(true, predicate_fn.eval(&b)); /// assert_eq!(false, predicate_fn.distance(0).eval(&b)); /// ``` pub fn is_close(target: f64) -> IsClosePredicate { IsClosePredicate { target, epsilon: 2.0 * ::std::f64::EPSILON, ulps: 2, } } predicates-3.1.0/src/float/mod.rs000064400000000000000000000011011046102023000147620ustar 00000000000000// Copyright (c) 2018 The predicates-rs Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Float Predicates //! //! This module contains predicates specific to string handling. #[cfg(feature = "float-cmp")] mod close; #[cfg(feature = "float-cmp")] pub use self::close::{is_close, IsClosePredicate}; predicates-3.1.0/src/function.rs000064400000000000000000000070771046102023000147450ustar 00000000000000// Copyright (c) 2018 The predicates-rs Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Definition of `Predicate` for wrapping a `Fn(&T) -> bool` use std::fmt; use std::marker::PhantomData; use crate::reflection; use crate::utils; use crate::Predicate; /// Predicate that wraps a function over a reference that returns a `bool`. /// This type is returned by the `predicate::function` function. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct FnPredicate where F: Fn(&T) -> bool, T: ?Sized, { function: F, name: &'static str, _phantom: PhantomData, } unsafe impl Send for FnPredicate where F: Send + Fn(&T) -> bool, T: ?Sized, { } unsafe impl Sync for FnPredicate where F: Sync + Fn(&T) -> bool, T: ?Sized, { } impl FnPredicate where F: Fn(&T) -> bool, T: ?Sized, { /// Provide a descriptive name for this function. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// struct Example { /// string: String, /// number: i32, /// } /// /// let string_check = predicate::function(|x: &Example| x.string == "hello") /// .fn_name("is_hello"); /// println!("predicate: {}", string_check); /// ``` pub fn fn_name(mut self, name: &'static str) -> Self { self.name = name; self } } impl Predicate for FnPredicate where F: Fn(&T) -> bool, T: ?Sized, { fn eval(&self, variable: &T) -> bool { (self.function)(variable) } fn find_case<'a>(&'a self, expected: bool, variable: &T) -> Option> { utils::default_find_case(self, expected, variable) } } impl reflection::PredicateReflection for FnPredicate where F: Fn(&T) -> bool, T: ?Sized, { } impl fmt::Display for FnPredicate where F: Fn(&T) -> bool, T: ?Sized, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let palette = crate::Palette::new(f.alternate()); write!( f, "{}({})", palette.description(self.name), palette.var("var"), ) } } /// Creates a new predicate that wraps over the given function. The returned /// type implements `Predicate` and therefore has all combinators available to /// it. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// struct Example { /// string: String, /// number: i32, /// } /// /// let string_check = predicate::function(|x: &Example| x.string == "hello"); /// let number_check = predicate::function(|x: &Example| x.number == 42); /// let predicate_fn = string_check.and(number_check); /// let good_example = Example { string: "hello".into(), number: 42 }; /// assert_eq!(true, predicate_fn.eval(&good_example)); /// let bad_example = Example { string: "goodbye".into(), number: 0 }; /// assert_eq!(false, predicate_fn.eval(&bad_example)); /// ``` pub fn function(function: F) -> FnPredicate where F: Fn(&T) -> bool, T: ?Sized, { FnPredicate { function, name: "fn", _phantom: PhantomData, } } #[test] fn str_function() { let f = function(|x: &str| x == "hello"); assert!(f.eval("hello")); assert!(!f.eval("goodbye")); } predicates-3.1.0/src/iter.rs000064400000000000000000000253471046102023000140630ustar 00000000000000// Copyright (c) 2018 The predicates-rs Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Definition of `Predicate`s for comparisons of membership in a set. use std::collections::HashSet; use std::fmt; use std::hash::Hash; use std::iter::FromIterator; use crate::reflection; use crate::utils; use crate::Predicate; /// Predicate that returns `true` if `variable` is a member of the pre-defined /// set, otherwise returns `false`. /// /// Note that this implementation places the fewest restrictions on the /// underlying `Item` type at the expense of having the least performant /// implementation (linear search). If the type to be searched is `Hash + Eq`, /// it is much more efficient to use `HashableInPredicate` and /// `in_hash`. The implementation-specific predicates will be /// deprecated when Rust supports trait specialization. #[derive(Debug, Clone, PartialEq, Eq)] pub struct InPredicate where T: PartialEq + fmt::Debug, { inner: utils::DebugAdapter>, } impl InPredicate where T: Ord + fmt::Debug, { /// Creates a new predicate that will return `true` when the given `variable` is /// contained with the set of items provided. /// /// Note that this implementation requires `Item` to be `Ord`. The /// `InPredicate` uses a less efficient search algorithm but only /// requires `Item` implement `PartialEq`. The implementation-specific /// predicates will be deprecated when Rust supports trait specialization. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let predicate_fn = predicate::in_iter(vec![1, 3, 5]).sort(); /// assert_eq!(true, predicate_fn.eval(&1)); /// assert_eq!(false, predicate_fn.eval(&2)); /// assert_eq!(true, predicate_fn.eval(&3)); /// /// let predicate_fn = predicate::in_iter(vec!["a", "c", "e"]).sort(); /// assert_eq!(true, predicate_fn.eval("a")); /// assert_eq!(false, predicate_fn.eval("b")); /// assert_eq!(true, predicate_fn.eval("c")); /// /// let predicate_fn = predicate::in_iter(vec![String::from("a"), String::from("c"), String::from("e")]).sort(); /// assert_eq!(true, predicate_fn.eval("a")); /// assert_eq!(false, predicate_fn.eval("b")); /// assert_eq!(true, predicate_fn.eval("c")); /// ``` pub fn sort(self) -> OrdInPredicate { let mut items = self.inner.debug; items.sort(); OrdInPredicate { inner: utils::DebugAdapter::new(items), } } } impl Predicate

for InPredicate where T: std::borrow::Borrow

+ PartialEq + fmt::Debug, P: PartialEq + fmt::Debug + ?Sized, { fn eval(&self, variable: &P) -> bool { self.inner.debug.iter().any(|x| x.borrow() == variable) } fn find_case<'a>(&'a self, expected: bool, variable: &P) -> Option> { utils::default_find_case(self, expected, variable).map(|case| { case.add_product(reflection::Product::new( "var", utils::DebugAdapter::new(variable).to_string(), )) }) } } impl reflection::PredicateReflection for InPredicate where T: PartialEq + fmt::Debug, { fn parameters<'a>(&'a self) -> Box> + 'a> { let params = vec![reflection::Parameter::new("values", &self.inner)]; Box::new(params.into_iter()) } } impl fmt::Display for InPredicate where T: PartialEq + fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let palette = crate::Palette::new(f.alternate()); write!( f, "{} {} {}", palette.var("var"), palette.description("in"), palette.expected("values") ) } } /// Creates a new predicate that will return `true` when the given `variable` is /// contained with the set of items provided. /// /// Note that this implementation places the fewest restrictions on the /// underlying `Item` type at the expense of having the least performant /// implementation (linear search). If the type to be searched is `Hash + Eq`, /// it is much more efficient to use `HashableInPredicate` and /// `in_hash`. The implementation-specific predicates will be /// deprecated when Rust supports trait specialization. /// /// If you need to optimize this /// - Type is `Ord`, call `sort()` on this predicate. /// - Type is `Hash`, replace `in_iter` with `in_hash`. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let predicate_fn = predicate::in_iter(vec![1, 3, 5]); /// assert_eq!(true, predicate_fn.eval(&1)); /// assert_eq!(false, predicate_fn.eval(&2)); /// assert_eq!(true, predicate_fn.eval(&3)); /// /// let predicate_fn = predicate::in_iter(vec!["a", "c", "e"]); /// assert_eq!(true, predicate_fn.eval("a")); /// assert_eq!(false, predicate_fn.eval("b")); /// assert_eq!(true, predicate_fn.eval("c")); /// /// let predicate_fn = predicate::in_iter(vec![String::from("a"), String::from("c"), String::from("e")]); /// assert_eq!(true, predicate_fn.eval("a")); /// assert_eq!(false, predicate_fn.eval("b")); /// assert_eq!(true, predicate_fn.eval("c")); /// ``` pub fn in_iter(iter: I) -> InPredicate where T: PartialEq + fmt::Debug, I: IntoIterator, { InPredicate { inner: utils::DebugAdapter::new(Vec::from_iter(iter)), } } /// Predicate that returns `true` if `variable` is a member of the pre-defined /// set, otherwise returns `false`. /// /// Note that this implementation requires `Item` to be `Ord`. The /// `InPredicate` uses a less efficient search algorithm but only /// requires `Item` implement `PartialEq`. The implementation-specific /// predicates will be deprecated when Rust supports trait specialization. /// /// This is created by the `predicate::in_iter(...).sort` function. #[derive(Debug, Clone, PartialEq, Eq)] pub struct OrdInPredicate where T: Ord + fmt::Debug, { inner: utils::DebugAdapter>, } impl Predicate

for OrdInPredicate where T: std::borrow::Borrow

+ Ord + fmt::Debug, P: Ord + fmt::Debug + ?Sized, { fn eval(&self, variable: &P) -> bool { self.inner .debug .binary_search_by(|x| x.borrow().cmp(variable)) .is_ok() } fn find_case<'a>(&'a self, expected: bool, variable: &P) -> Option> { utils::default_find_case(self, expected, variable).map(|case| { case.add_product(reflection::Product::new( "var", utils::DebugAdapter::new(variable).to_string(), )) }) } } impl reflection::PredicateReflection for OrdInPredicate where T: Ord + fmt::Debug, { fn parameters<'a>(&'a self) -> Box> + 'a> { let params = vec![reflection::Parameter::new("values", &self.inner)]; Box::new(params.into_iter()) } } impl fmt::Display for OrdInPredicate where T: Ord + fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let palette = crate::Palette::new(f.alternate()); write!( f, "{} {} {}", palette.var("var"), palette.description("in"), palette.expected("values") ) } } /// Predicate that returns `true` if `variable` is a member of the pre-defined /// `HashSet`, otherwise returns `false`. /// /// Note that this implementation requires `Item` to be `Hash + Eq`. The /// `InPredicate` uses a less efficient search algorithm but only /// requires `Item` implement `PartialEq`. The implementation-specific /// predicates will be deprecated when Rust supports trait specialization. /// /// This is created by the `predicate::in_hash` function. #[derive(Debug, Clone, PartialEq, Eq)] pub struct HashableInPredicate where T: Hash + Eq + fmt::Debug, { inner: utils::DebugAdapter>, } impl Predicate

for HashableInPredicate where T: std::borrow::Borrow

+ Hash + Eq + fmt::Debug, P: Hash + Eq + fmt::Debug + ?Sized, { fn eval(&self, variable: &P) -> bool { self.inner.debug.contains(variable) } fn find_case<'a>(&'a self, expected: bool, variable: &P) -> Option> { utils::default_find_case(self, expected, variable).map(|case| { case.add_product(reflection::Product::new( "var", utils::DebugAdapter::new(variable).to_string(), )) }) } } impl reflection::PredicateReflection for HashableInPredicate where T: Hash + Eq + fmt::Debug, { fn parameters<'a>(&'a self) -> Box> + 'a> { let params = vec![reflection::Parameter::new("values", &self.inner)]; Box::new(params.into_iter()) } } impl fmt::Display for HashableInPredicate where T: Hash + Eq + fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let palette = crate::Palette::new(f.alternate()); write!( f, "{} {} {}", palette.var("var"), palette.description("in"), palette.expected("values") ) } } /// Creates a new predicate that will return `true` when the given `variable` is /// contained with the set of items provided. /// /// Note that this implementation requires `Item` to be `Hash + Eq`. The /// `InPredicate` uses a less efficient search algorithm but only /// requires `Item` implement `PartialEq`. The implementation-specific /// predicates will be deprecated when Rust supports trait specialization. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let predicate_fn = predicate::in_hash(vec![1, 3, 5]); /// assert_eq!(true, predicate_fn.eval(&1)); /// assert_eq!(false, predicate_fn.eval(&2)); /// assert_eq!(true, predicate_fn.eval(&3)); /// /// let predicate_fn = predicate::in_hash(vec!["a", "c", "e"]); /// assert_eq!(true, predicate_fn.eval("a")); /// assert_eq!(false, predicate_fn.eval("b")); /// assert_eq!(true, predicate_fn.eval("c")); /// /// let predicate_fn = predicate::in_hash(vec![String::from("a"), String::from("c"), String::from("e")]); /// assert_eq!(true, predicate_fn.eval("a")); /// assert_eq!(false, predicate_fn.eval("b")); /// assert_eq!(true, predicate_fn.eval("c")); /// ``` pub fn in_hash(iter: I) -> HashableInPredicate where T: Hash + Eq + fmt::Debug, I: IntoIterator, { HashableInPredicate { inner: utils::DebugAdapter::new(HashSet::from_iter(iter)), } } predicates-3.1.0/src/lib.rs000064400000000000000000000225521046102023000136610ustar 00000000000000// Copyright (c) 2018 The predicates-rs Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , 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 = "3.1.0" //! ``` //! //! 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 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)] #![cfg_attr(docsrs, feature(doc_auto_cfg))] 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; predicates-3.1.0/src/name.rs000064400000000000000000000054071046102023000140330ustar 00000000000000// Copyright (c) 2018 The predicates-rs Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Name predicate expressions. use std::fmt; use std::marker::PhantomData; use crate::reflection; use crate::Predicate; /// Augment an existing predicate with a name. /// /// This is created by the `PredicateNameExt::name` function. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct NamePredicate where M: Predicate, Item: ?Sized, { inner: M, name: &'static str, _phantom: PhantomData, } unsafe impl Send for NamePredicate where M: Predicate + Send, Item: ?Sized, { } unsafe impl Sync for NamePredicate where M: Predicate + Sync, Item: ?Sized, { } impl Predicate for NamePredicate where M: Predicate, Item: ?Sized, { fn eval(&self, item: &Item) -> bool { self.inner.eval(item) } fn find_case<'a>(&'a self, expected: bool, variable: &Item) -> Option> { self.inner .find_case(expected, variable) .map(|child_case| reflection::Case::new(Some(self), expected).add_child(child_case)) } } impl reflection::PredicateReflection for NamePredicate where M: Predicate, Item: ?Sized, { fn children<'a>(&'a self) -> Box> + 'a> { let params = vec![reflection::Child::new(self.name, &self.inner)]; Box::new(params.into_iter()) } } impl fmt::Display for NamePredicate where M: Predicate, Item: ?Sized, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let palette = crate::Palette::new(f.alternate()); write!(f, "{}", palette.description(self.name)) } } /// `Predicate` extension that adds naming predicate expressions. pub trait PredicateNameExt where Self: Predicate, { /// Name a predicate expression. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let predicate_fn = predicate::str::is_empty().not().name("non-empty"); /// println!("{}", predicate_fn); /// ``` fn name(self, name: &'static str) -> NamePredicate where Self: Sized, { NamePredicate { inner: self, name, _phantom: PhantomData, } } } impl PredicateNameExt for P where P: Predicate, Item: ?Sized, { } predicates-3.1.0/src/ord.rs000064400000000000000000000177231046102023000137030ustar 00000000000000// Copyright (c) 2018, 2022 The predicates-rs Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Definition of `Predicate`s for comparisons over `Ord` and `Eq` types. use std::fmt; use crate::reflection; use crate::utils; use crate::Predicate; #[derive(Clone, Copy, Debug, PartialEq, Eq)] enum EqOps { Equal, NotEqual, } impl fmt::Display for EqOps { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let op = match *self { EqOps::Equal => "==", EqOps::NotEqual => "!=", }; write!(f, "{}", op) } } /// Predicate that returns `true` if `variable` matches the pre-defined `Eq` /// value, otherwise returns `false`. /// /// This is created by the `predicate::{eq, ne}` functions. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct EqPredicate { constant: T, op: EqOps, } impl Predicate

for EqPredicate where T: std::borrow::Borrow

+ fmt::Debug, P: fmt::Debug + PartialEq + ?Sized, { fn eval(&self, variable: &P) -> bool { match self.op { EqOps::Equal => variable.eq(self.constant.borrow()), EqOps::NotEqual => variable.ne(self.constant.borrow()), } } fn find_case<'a>(&'a self, expected: bool, variable: &P) -> Option> { utils::default_find_case(self, expected, variable).map(|case| { case.add_product(reflection::Product::new( "var", utils::DebugAdapter::new(variable).to_string(), )) }) } } impl reflection::PredicateReflection for EqPredicate where T: fmt::Debug {} impl fmt::Display for EqPredicate where T: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let palette = crate::Palette::new(f.alternate()); write!( f, "{} {} {}", palette.var("var"), palette.description(self.op), palette.expected(utils::DebugAdapter::new(&self.constant)), ) } } /// Creates a new predicate that will return `true` when the given `variable` is /// equal to a pre-defined value. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let predicate_fn = predicate::eq(5); /// assert_eq!(true, predicate_fn.eval(&5)); /// assert_eq!(false, predicate_fn.eval(&10)); /// /// let predicate_fn = predicate::eq("Hello"); /// assert_eq!(true, predicate_fn.eval("Hello")); /// assert_eq!(false, predicate_fn.eval("Goodbye")); /// /// let predicate_fn = predicate::eq(String::from("Hello")); /// assert_eq!(true, predicate_fn.eval("Hello")); /// assert_eq!(false, predicate_fn.eval("Goodbye")); /// ``` pub fn eq(constant: T) -> EqPredicate where T: fmt::Debug + PartialEq, { EqPredicate { constant, op: EqOps::Equal, } } /// Creates a new predicate that will return `true` when the given `variable` is /// _not_ equal to a pre-defined value. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let predicate_fn = predicate::ne(5); /// assert_eq!(false, predicate_fn.eval(&5)); /// assert_eq!(true, predicate_fn.eval(&10)); /// ``` pub fn ne(constant: T) -> EqPredicate where T: PartialEq + fmt::Debug, { EqPredicate { constant, op: EqOps::NotEqual, } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] enum OrdOps { LessThan, LessThanOrEqual, GreaterThanOrEqual, GreaterThan, } impl fmt::Display for OrdOps { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let op = match *self { OrdOps::LessThan => "<", OrdOps::LessThanOrEqual => "<=", OrdOps::GreaterThanOrEqual => ">=", OrdOps::GreaterThan => ">", }; write!(f, "{}", op) } } /// Predicate that returns `true` if `variable` matches the pre-defined `Ord` /// value, otherwise returns `false`. /// /// This is created by the `predicate::{gt, ge, lt, le}` functions. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct OrdPredicate { constant: T, op: OrdOps, } impl Predicate

for OrdPredicate where T: std::borrow::Borrow

+ fmt::Debug, P: fmt::Debug + PartialOrd + ?Sized, { fn eval(&self, variable: &P) -> bool { match self.op { OrdOps::LessThan => variable.lt(self.constant.borrow()), OrdOps::LessThanOrEqual => variable.le(self.constant.borrow()), OrdOps::GreaterThanOrEqual => variable.ge(self.constant.borrow()), OrdOps::GreaterThan => variable.gt(self.constant.borrow()), } } fn find_case<'a>(&'a self, expected: bool, variable: &P) -> Option> { utils::default_find_case(self, expected, variable).map(|case| { case.add_product(reflection::Product::new( "var", utils::DebugAdapter::new(variable).to_string(), )) }) } } impl reflection::PredicateReflection for OrdPredicate where T: fmt::Debug {} impl fmt::Display for OrdPredicate where T: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let palette = crate::Palette::new(f.alternate()); write!( f, "{} {} {}", palette.var("var"), palette.description(self.op), palette.expected(utils::DebugAdapter::new(&self.constant)), ) } } /// Creates a new predicate that will return `true` when the given `variable` is /// less than a pre-defined value. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let predicate_fn = predicate::lt(5); /// assert_eq!(true, predicate_fn.eval(&4)); /// assert_eq!(false, predicate_fn.eval(&6)); /// /// let predicate_fn = predicate::lt("b"); /// assert_eq!(true, predicate_fn.eval("a")); /// assert_eq!(false, predicate_fn.eval("c")); /// /// let predicate_fn = predicate::lt(String::from("b")); /// assert_eq!(true, predicate_fn.eval("a")); /// assert_eq!(false, predicate_fn.eval("c")); /// ``` pub fn lt(constant: T) -> OrdPredicate where T: fmt::Debug + PartialOrd, { OrdPredicate { constant, op: OrdOps::LessThan, } } /// Creates a new predicate that will return `true` when the given `variable` is /// less than or equal to a pre-defined value. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let predicate_fn = predicate::le(5); /// assert_eq!(true, predicate_fn.eval(&4)); /// assert_eq!(true, predicate_fn.eval(&5)); /// assert_eq!(false, predicate_fn.eval(&6)); /// ``` pub fn le(constant: T) -> OrdPredicate where T: PartialOrd + fmt::Debug, { OrdPredicate { constant, op: OrdOps::LessThanOrEqual, } } /// Creates a new predicate that will return `true` when the given `variable` is /// greater than or equal to a pre-defined value. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let predicate = predicate::ge(5); /// assert_eq!(false, predicate.eval(&4)); /// assert_eq!(true, predicate.eval(&5)); /// assert_eq!(true, predicate.eval(&6)); /// ``` pub fn ge(constant: T) -> OrdPredicate where T: PartialOrd + fmt::Debug, { OrdPredicate { constant, op: OrdOps::GreaterThanOrEqual, } } /// Creates a new predicate that will return `true` when the given `variable` is /// greater than a pre-defined value. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let predicate_fn = predicate::gt(5); /// assert_eq!(false, predicate_fn.eval(&4)); /// assert_eq!(false, predicate_fn.eval(&5)); /// assert_eq!(true, predicate_fn.eval(&6)); /// ``` pub fn gt(constant: T) -> OrdPredicate where T: PartialOrd + fmt::Debug, { OrdPredicate { constant, op: OrdOps::GreaterThan, } } predicates-3.1.0/src/path/existence.rs000064400000000000000000000044621046102023000160360ustar 00000000000000// Copyright (c) 2018 The predicates-rs Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use std::fmt; use std::path; use crate::reflection; use crate::utils; use crate::Predicate; /// Predicate that checks if a file is present /// /// This is created by the `predicate::path::exists` and `predicate::path::missing`. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct ExistencePredicate { exists: bool, } impl Predicate for ExistencePredicate { fn eval(&self, path: &path::Path) -> bool { path.exists() == self.exists } fn find_case<'a>( &'a self, expected: bool, variable: &path::Path, ) -> Option> { utils::default_find_case(self, expected, variable).map(|case| { case.add_product(reflection::Product::new( "var", variable.display().to_string(), )) }) } } impl reflection::PredicateReflection for ExistencePredicate {} impl fmt::Display for ExistencePredicate { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let palette = crate::Palette::new(f.alternate()); write!( f, "{}({})", palette.description(if self.exists { "exists" } else { "missing" }), palette.var("var") ) } } /// Creates a new `Predicate` that ensures the path exists. /// /// # Examples /// /// ``` /// use std::path::Path; /// use predicates::prelude::*; /// /// let predicate_fn = predicate::path::exists(); /// assert_eq!(true, predicate_fn.eval(Path::new("Cargo.toml"))); /// ``` pub fn exists() -> ExistencePredicate { ExistencePredicate { exists: true } } /// Creates a new `Predicate` that ensures the path doesn't exist. /// /// # Examples /// /// ``` /// use std::path::Path; /// use predicates::prelude::*; /// /// let predicate_fn = predicate::path::missing(); /// assert_eq!(true, predicate_fn.eval(Path::new("non-existent-file.foo"))); /// ``` pub fn missing() -> ExistencePredicate { ExistencePredicate { exists: false } } predicates-3.1.0/src/path/fc.rs000064400000000000000000000066341046102023000144420ustar 00000000000000// Copyright (c) 2018 The predicates-rs Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use std::fmt; use std::fs; use std::io::{self, Read}; use std::path; use crate::reflection; use crate::Predicate; fn read_file(path: &path::Path) -> io::Result> { let mut buffer = Vec::new(); fs::File::open(path)?.read_to_end(&mut buffer)?; Ok(buffer) } /// Predicate adapter that converts a `path` predicate to a byte predicate on its content. /// /// This is created by `pred.from_path()`. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct FileContentPredicate

where P: Predicate<[u8]>, { p: P, } impl

FileContentPredicate

where P: Predicate<[u8]>, { fn eval(&self, path: &path::Path) -> io::Result { let buffer = read_file(path)?; Ok(self.p.eval(&buffer)) } } impl

reflection::PredicateReflection for FileContentPredicate

where P: Predicate<[u8]>, { fn children<'a>(&'a self) -> Box> + 'a> { let params = vec![reflection::Child::new("predicate", &self.p)]; Box::new(params.into_iter()) } } impl

fmt::Display for FileContentPredicate

where P: Predicate<[u8]>, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.p.fmt(f) } } impl

Predicate for FileContentPredicate

where P: Predicate<[u8]>, { fn eval(&self, path: &path::Path) -> bool { self.eval(path).unwrap_or(false) } fn find_case<'a>( &'a self, expected: bool, variable: &path::Path, ) -> Option> { let buffer = read_file(variable); match (expected, buffer) { (_, Ok(buffer)) => self.p.find_case(expected, &buffer).map(|case| { case.add_product(reflection::Product::new( "var", variable.display().to_string(), )) }), (true, Err(_)) => None, (false, Err(err)) => Some( reflection::Case::new(Some(self), false) .add_product(reflection::Product::new( "var", variable.display().to_string(), )) .add_product(reflection::Product::new("error", err)), ), } } } /// `Predicate` extension adapting a `slice` Predicate. pub trait PredicateFileContentExt where Self: Predicate<[u8]>, Self: Sized, { /// Returns a `FileContentPredicate` that adapts `Self` to a file content `Predicate`. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// use std::path::Path; /// /// let predicate_fn = predicate::str::is_empty().not().from_utf8().from_file_path(); /// assert_eq!(true, predicate_fn.eval(Path::new("./tests/hello_world"))); /// assert_eq!(false, predicate_fn.eval(Path::new("./tests/empty_file"))); /// ``` #[allow(clippy::wrong_self_convention)] fn from_file_path(self) -> FileContentPredicate { FileContentPredicate { p: self } } } impl

PredicateFileContentExt for P where P: Predicate<[u8]> {} predicates-3.1.0/src/path/fs.rs000064400000000000000000000125001046102023000144470ustar 00000000000000// Copyright (c) 2018 The predicates-rs Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use std::fmt; use std::fs; use std::io::{self, Read}; use std::path; use crate::reflection; use crate::utils; use crate::Predicate; fn read_file(path: &path::Path) -> io::Result> { let mut buffer = Vec::new(); fs::File::open(path)?.read_to_end(&mut buffer)?; Ok(buffer) } /// Predicate that compares file matches #[derive(Debug, Clone, PartialEq, Eq)] pub struct BinaryFilePredicate { path: path::PathBuf, content: utils::DebugAdapter>, } impl BinaryFilePredicate { fn eval(&self, path: &path::Path) -> io::Result { let content = read_file(path)?; Ok(self.content.debug == content) } /// Creates a new `Predicate` that ensures complete equality /// /// # Examples /// /// ``` /// use std::path::Path; /// use predicates::prelude::*; /// /// let predicate_file = predicate::path::eq_file(Path::new("Cargo.toml")).utf8().unwrap(); /// assert_eq!(true, predicate_file.eval(Path::new("Cargo.toml"))); /// assert_eq!(false, predicate_file.eval(Path::new("Cargo.lock"))); /// assert_eq!(false, predicate_file.eval(Path::new("src"))); /// /// assert_eq!(false, predicate_file.eval("Not a real Cargo.toml file content")); /// ``` pub fn utf8(self) -> Option { let path = self.path; let content = String::from_utf8(self.content.debug).ok()?; Some(StrFilePredicate { path, content }) } } impl Predicate for BinaryFilePredicate { fn eval(&self, path: &path::Path) -> bool { self.eval(path).unwrap_or(false) } fn find_case<'a>( &'a self, expected: bool, variable: &path::Path, ) -> Option> { utils::default_find_case(self, expected, variable) } } impl Predicate<[u8]> for BinaryFilePredicate { fn eval(&self, actual: &[u8]) -> bool { self.content.debug == actual } fn find_case<'a>(&'a self, expected: bool, variable: &[u8]) -> Option> { utils::default_find_case(self, expected, variable) } } impl reflection::PredicateReflection for BinaryFilePredicate { fn parameters<'a>(&'a self) -> Box> + 'a> { let params = vec![reflection::Parameter::new("content", &self.content)]; Box::new(params.into_iter()) } } impl fmt::Display for BinaryFilePredicate { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let palette = crate::Palette::new(f.alternate()); write!( f, "{} {} {}", palette.var("var"), palette.description("is"), palette.expected(self.path.display()) ) } } /// Creates a new `Predicate` that ensures complete equality /// /// # Examples /// /// ``` /// use std::path::Path; /// use predicates::prelude::*; /// /// let predicate_file = predicate::path::eq_file(Path::new("Cargo.toml")); /// assert_eq!(true, predicate_file.eval(Path::new("Cargo.toml"))); /// assert_eq!(false, predicate_file.eval(Path::new("src"))); /// assert_eq!(false, predicate_file.eval(Path::new("src"))); /// ``` pub fn eq_file>(path: P) -> BinaryFilePredicate { let path = path.into(); let content = utils::DebugAdapter::new(read_file(&path).unwrap()); BinaryFilePredicate { path, content } } /// Predicate that compares string content of files #[derive(Debug, Clone, PartialEq, Eq)] pub struct StrFilePredicate { path: path::PathBuf, content: String, } impl StrFilePredicate { fn eval(&self, path: &path::Path) -> Option { let content = read_file(path).ok()?; let content = String::from_utf8(content).ok()?; Some(self.content == content) } } impl Predicate for StrFilePredicate { fn eval(&self, path: &path::Path) -> bool { self.eval(path).unwrap_or(false) } fn find_case<'a>( &'a self, expected: bool, variable: &path::Path, ) -> Option> { utils::default_find_case(self, expected, variable) } } impl Predicate for StrFilePredicate { fn eval(&self, actual: &str) -> bool { self.content == actual } fn find_case<'a>(&'a self, expected: bool, variable: &str) -> Option> { utils::default_find_case(self, expected, variable) } } impl reflection::PredicateReflection for StrFilePredicate { fn parameters<'a>(&'a self) -> Box> + 'a> { let params = vec![reflection::Parameter::new("content", &self.content)]; Box::new(params.into_iter()) } } impl fmt::Display for StrFilePredicate { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let palette = crate::Palette::new(f.alternate()); write!( f, "{} {} {}", palette.var("var"), palette.description("is"), palette.expected(self.path.display()) ) } } predicates-3.1.0/src/path/ft.rs000064400000000000000000000134151046102023000144560ustar 00000000000000// Copyright (c) 2018 The predicates-rs Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use std::fmt; use std::fs; use std::io; use std::path; use crate::reflection; use crate::Predicate; #[derive(Clone, Copy, Debug, PartialEq, Eq)] enum FileType { File, Dir, Symlink, } impl FileType { fn from_path(path: &path::Path, follow: bool) -> io::Result { let file_type = if follow { path.metadata() } else { path.symlink_metadata() }? .file_type(); if file_type.is_dir() { return Ok(FileType::Dir); } if file_type.is_file() { return Ok(FileType::File); } Ok(FileType::Symlink) } fn eval(self, ft: fs::FileType) -> bool { match self { FileType::File => ft.is_file(), FileType::Dir => ft.is_dir(), FileType::Symlink => ft.is_symlink(), } } } impl fmt::Display for FileType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let t = match *self { FileType::File => "file", FileType::Dir => "dir", FileType::Symlink => "symlink", }; write!(f, "{}", t) } } /// Predicate that checks the `std::fs::FileType`. /// /// This is created by the `predicate::path::is_file`, `predicate::path::is_dir`, and `predicate::path::is_symlink`. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct FileTypePredicate { ft: FileType, follow: bool, } impl FileTypePredicate { /// Follow symbolic links. /// /// When yes is true, symbolic links are followed as if they were normal directories and files. /// /// Default: disabled. pub fn follow_links(mut self, yes: bool) -> Self { self.follow = yes; self } /// Allow to create an `FileTypePredicate` from a `path` pub fn from_path(path: &path::Path) -> io::Result { Ok(FileTypePredicate { ft: FileType::from_path(path, true)?, follow: true, }) } } impl Predicate for FileTypePredicate { fn eval(&self, path: &path::Path) -> bool { let metadata = if self.follow { path.metadata() } else { path.symlink_metadata() }; metadata .map(|m| self.ft.eval(m.file_type())) .unwrap_or(false) } fn find_case<'a>( &'a self, expected: bool, variable: &path::Path, ) -> Option> { let actual_type = FileType::from_path(variable, self.follow); match (expected, actual_type) { (_, Ok(actual_type)) => { let result = self.ft == actual_type; if result == expected { Some( reflection::Case::new(Some(self), result) .add_product(reflection::Product::new("actual filetype", actual_type)), ) } else { None } } (true, Err(_)) => None, (false, Err(err)) => Some( reflection::Case::new(Some(self), false) .add_product(reflection::Product::new("error", err)), ), } } } impl reflection::PredicateReflection for FileTypePredicate { fn parameters<'a>(&'a self) -> Box> + 'a> { let params = vec![reflection::Parameter::new("follow", &self.follow)]; Box::new(params.into_iter()) } } impl fmt::Display for FileTypePredicate { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let palette = crate::Palette::new(f.alternate()); write!( f, "{} {} {}", palette.var("var"), palette.description("is"), palette.expected(self.ft) ) } } /// Creates a new `Predicate` that ensures the path points to a file. /// /// # Examples /// /// ``` /// use std::path::Path; /// use predicates::prelude::*; /// /// let predicate_fn = predicate::path::is_file(); /// assert_eq!(true, predicate_fn.eval(Path::new("Cargo.toml"))); /// assert_eq!(false, predicate_fn.eval(Path::new("src"))); /// assert_eq!(false, predicate_fn.eval(Path::new("non-existent-file.foo"))); /// ``` pub fn is_file() -> FileTypePredicate { FileTypePredicate { ft: FileType::File, follow: false, } } /// Creates a new `Predicate` that ensures the path points to a directory. /// /// # Examples /// /// ``` /// use std::path::Path; /// use predicates::prelude::*; /// /// let predicate_fn = predicate::path::is_dir(); /// assert_eq!(false, predicate_fn.eval(Path::new("Cargo.toml"))); /// assert_eq!(true, predicate_fn.eval(Path::new("src"))); /// assert_eq!(false, predicate_fn.eval(Path::new("non-existent-file.foo"))); /// ``` pub fn is_dir() -> FileTypePredicate { FileTypePredicate { ft: FileType::Dir, follow: false, } } /// Creates a new `Predicate` that ensures the path points to a symlink. /// /// # Examples /// /// ``` /// use std::path::Path; /// use predicates::prelude::*; /// /// let predicate_fn = predicate::path::is_symlink(); /// assert_eq!(false, predicate_fn.eval(Path::new("Cargo.toml"))); /// assert_eq!(false, predicate_fn.eval(Path::new("src"))); /// assert_eq!(false, predicate_fn.eval(Path::new("non-existent-file.foo"))); /// ``` pub fn is_symlink() -> FileTypePredicate { FileTypePredicate { ft: FileType::Symlink, follow: false, } } predicates-3.1.0/src/path/mod.rs000064400000000000000000000013701046102023000146210ustar 00000000000000// Copyright (c) 2018 The predicates-rs Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Path Predicates //! //! This module contains predicates specific to the file system. mod existence; pub use self::existence::{exists, missing, ExistencePredicate}; mod ft; pub use self::ft::{is_dir, is_file, is_symlink, FileTypePredicate}; mod fc; pub use self::fc::{FileContentPredicate, PredicateFileContentExt}; mod fs; pub use self::fs::{eq_file, BinaryFilePredicate, StrFilePredicate}; predicates-3.1.0/src/prelude.rs000064400000000000000000000034141046102023000145470ustar 00000000000000// Copyright (c) 2018 The predicates-rs Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Module that contains the essentials for working with predicates. pub use crate::boolean::PredicateBooleanExt; pub use crate::boxed::PredicateBoxExt; pub use crate::name::PredicateNameExt; pub use crate::path::PredicateFileContentExt; pub use crate::str::PredicateStrExt; pub use crate::Predicate; /// Predicate factories pub mod predicate { // primitive `Predicate` types pub use crate::constant::{always, never}; pub use crate::function::function; pub use crate::iter::{in_hash, in_iter}; pub use crate::ord::{eq, ge, gt, le, lt, ne}; /// `str` Predicate factories /// /// This module contains predicates specific to string handling. pub mod str { pub use crate::str::is_empty; pub use crate::str::{contains, ends_with, starts_with}; #[cfg(feature = "diff")] pub use crate::str::diff; #[cfg(feature = "regex")] pub use crate::str::is_match; } /// `Path` Predicate factories /// /// This module contains predicates specific to path handling. pub mod path { pub use crate::path::eq_file; pub use crate::path::{exists, missing}; pub use crate::path::{is_dir, is_file, is_symlink}; } /// `f64` Predicate factories /// /// This module contains predicates specific to float handling. pub mod float { #[cfg(feature = "float-cmp")] pub use crate::float::is_close; } } predicates-3.1.0/src/str/adapters.rs000064400000000000000000000134621046102023000155260ustar 00000000000000// Copyright (c) 2018 The predicates-rs Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use std::ffi; use std::fmt; use std::str; use crate::reflection; #[cfg(feature = "normalize-line-endings")] use crate::str::normalize::NormalizedPredicate; use crate::Predicate; /// Predicate adaper that trims the variable being tested. /// /// This is created by `pred.trim()`. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct TrimPredicate

where P: Predicate, { p: P, } impl

Predicate for TrimPredicate

where P: Predicate, { fn eval(&self, variable: &str) -> bool { self.p.eval(variable.trim()) } fn find_case<'a>(&'a self, expected: bool, variable: &str) -> Option> { self.p.find_case(expected, variable.trim()) } } impl

reflection::PredicateReflection for TrimPredicate

where P: Predicate, { fn children<'a>(&'a self) -> Box> + 'a> { let params = vec![reflection::Child::new("predicate", &self.p)]; Box::new(params.into_iter()) } } impl

fmt::Display for TrimPredicate

where P: Predicate, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.p.fmt(f) } } /// Predicate adaper that converts a `str` predicate to byte predicate. /// /// This is created by `pred.from_utf8()`. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Utf8Predicate

where P: Predicate, { p: P, } impl

Predicate for Utf8Predicate

where P: Predicate, { fn eval(&self, variable: &ffi::OsStr) -> bool { variable.to_str().map(|s| self.p.eval(s)).unwrap_or(false) } fn find_case<'a>( &'a self, expected: bool, variable: &ffi::OsStr, ) -> Option> { let var_str = variable.to_str(); match (expected, var_str) { (_, Some(var_str)) => self.p.find_case(expected, var_str).map(|child| { child.add_product(reflection::Product::new("var as str", var_str.to_owned())) }), (true, None) => None, (false, None) => Some( reflection::Case::new(Some(self), false) .add_product(reflection::Product::new("error", "Invalid UTF-8 string")), ), } } } impl

Predicate<[u8]> for Utf8Predicate

where P: Predicate, { fn eval(&self, variable: &[u8]) -> bool { str::from_utf8(variable) .map(|s| self.p.eval(s)) .unwrap_or(false) } fn find_case<'a>(&'a self, expected: bool, variable: &[u8]) -> Option> { let var_str = str::from_utf8(variable); match (expected, var_str) { (_, Ok(var_str)) => self.p.find_case(expected, var_str).map(|child| { child.add_product(reflection::Product::new("var as str", var_str.to_owned())) }), (true, Err(_)) => None, (false, Err(err)) => Some( reflection::Case::new(Some(self), false) .add_product(reflection::Product::new("error", err)), ), } } } impl

reflection::PredicateReflection for Utf8Predicate

where P: Predicate, { fn children<'a>(&'a self) -> Box> + 'a> { let params = vec![reflection::Child::new("predicate", &self.p)]; Box::new(params.into_iter()) } } impl

fmt::Display for Utf8Predicate

where P: Predicate, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.p.fmt(f) } } /// `Predicate` extension adapting a `str` Predicate. pub trait PredicateStrExt where Self: Predicate, Self: Sized, { /// Returns a `TrimPredicate` that ensures the data passed to `Self` is trimmed. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let predicate_fn = predicate::str::is_empty().trim(); /// assert_eq!(true, predicate_fn.eval(" ")); /// assert_eq!(false, predicate_fn.eval(" Hello ")); /// ``` fn trim(self) -> TrimPredicate { TrimPredicate { p: self } } /// Returns a `Utf8Predicate` that adapts `Self` to a `[u8]` `Predicate`. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// use std::ffi::OsStr; /// /// let predicate_fn = predicate::str::is_empty().not().from_utf8(); /// assert_eq!(true, predicate_fn.eval(OsStr::new("Hello"))); /// assert_eq!(false, predicate_fn.eval(OsStr::new(""))); /// let variable: &[u8] = b""; /// assert_eq!(false, predicate_fn.eval(variable)); /// ``` #[allow(clippy::wrong_self_convention)] fn from_utf8(self) -> Utf8Predicate { Utf8Predicate { p: self } } /// Returns a `NormalizedPredicate` that ensures /// the newlines within the data passed to `Self` is normalised. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let predicate_fn = predicate::eq("Hello World!\n").normalize(); /// assert_eq!(true, predicate_fn.eval("Hello World!\n")); /// assert_eq!(true, predicate_fn.eval("Hello World!\r")); /// assert_eq!(true, predicate_fn.eval("Hello World!\r\n")); /// assert_eq!(false, predicate_fn.eval("Goodbye")); /// ``` /// #[cfg(feature = "normalize-line-endings")] fn normalize(self) -> NormalizedPredicate { NormalizedPredicate { p: self } } } impl

PredicateStrExt for P where P: Predicate {} predicates-3.1.0/src/str/basics.rs000064400000000000000000000200761046102023000151660ustar 00000000000000// Copyright (c) 2018 The predicates-rs Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use std::fmt; use crate::reflection; use crate::utils; use crate::Predicate; /// Predicate that checks for empty strings. /// /// This is created by `predicates::str::is_empty`. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct IsEmptyPredicate {} impl Predicate for IsEmptyPredicate { fn eval(&self, variable: &str) -> bool { variable.is_empty() } fn find_case<'a>(&'a self, expected: bool, variable: &str) -> Option> { utils::default_find_case(self, expected, variable) .map(|case| case.add_product(reflection::Product::new("var", variable.to_owned()))) } } impl reflection::PredicateReflection for IsEmptyPredicate {} impl fmt::Display for IsEmptyPredicate { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let palette = crate::Palette::new(f.alternate()); write!( f, "{}.{}()", palette.var("var"), palette.description("is_empty"), ) } } /// Creates a new `Predicate` that ensures a str is empty /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let predicate_fn = predicate::str::is_empty(); /// assert_eq!(true, predicate_fn.eval("")); /// assert_eq!(false, predicate_fn.eval("Food World")); /// ``` pub fn is_empty() -> IsEmptyPredicate { IsEmptyPredicate {} } /// Predicate checks start of str /// /// This is created by `predicates::str::starts_with`. #[derive(Debug, Clone, PartialEq, Eq)] pub struct StartsWithPredicate { pattern: String, } impl Predicate for StartsWithPredicate { fn eval(&self, variable: &str) -> bool { variable.starts_with(&self.pattern) } fn find_case<'a>(&'a self, expected: bool, variable: &str) -> Option> { utils::default_find_case(self, expected, variable) .map(|case| case.add_product(reflection::Product::new("var", variable.to_owned()))) } } impl reflection::PredicateReflection for StartsWithPredicate {} impl fmt::Display for StartsWithPredicate { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let palette = crate::Palette::new(f.alternate()); write!( f, "{}.{}({:?})", palette.var("var"), palette.description("starts_with"), self.pattern ) } } /// Creates a new `Predicate` that ensures a str starts with `pattern` /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let predicate_fn = predicate::str::starts_with("Hello"); /// assert_eq!(true, predicate_fn.eval("Hello World")); /// assert_eq!(false, predicate_fn.eval("Goodbye World")); /// ``` pub fn starts_with

(pattern: P) -> StartsWithPredicate where P: Into, { StartsWithPredicate { pattern: pattern.into(), } } /// Predicate checks end of str /// /// This is created by `predicates::str::ends_with`. #[derive(Debug, Clone, PartialEq, Eq)] pub struct EndsWithPredicate { pattern: String, } impl Predicate for EndsWithPredicate { fn eval(&self, variable: &str) -> bool { variable.ends_with(&self.pattern) } fn find_case<'a>(&'a self, expected: bool, variable: &str) -> Option> { utils::default_find_case(self, expected, variable) .map(|case| case.add_product(reflection::Product::new("var", variable.to_owned()))) } } impl reflection::PredicateReflection for EndsWithPredicate {} impl fmt::Display for EndsWithPredicate { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let palette = crate::Palette::new(f.alternate()); write!( f, "{}.{}({:?})", palette.var("var"), palette.description("ends_with"), self.pattern ) } } /// Creates a new `Predicate` that ensures a str ends with `pattern` /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let predicate_fn = predicate::str::ends_with("World"); /// assert_eq!(true, predicate_fn.eval("Hello World")); /// assert_eq!(false, predicate_fn.eval("Hello Moon")); /// ``` pub fn ends_with

(pattern: P) -> EndsWithPredicate where P: Into, { EndsWithPredicate { pattern: pattern.into(), } } /// Predicate that checks for patterns. /// /// This is created by `predicates::str:contains`. #[derive(Debug, Clone, PartialEq, Eq)] pub struct ContainsPredicate { pattern: String, } impl ContainsPredicate { /// Require a specific count of matches. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let predicate_fn = predicate::str::contains("Two").count(2); /// assert_eq!(true, predicate_fn.eval("One Two Three Two One")); /// assert_eq!(false, predicate_fn.eval("One Two Three")); /// ``` pub fn count(self, count: usize) -> MatchesPredicate { MatchesPredicate { pattern: self.pattern, count, } } } impl Predicate for ContainsPredicate { fn eval(&self, variable: &str) -> bool { variable.contains(&self.pattern) } fn find_case<'a>(&'a self, expected: bool, variable: &str) -> Option> { utils::default_find_case(self, expected, variable) .map(|case| case.add_product(reflection::Product::new("var", variable.to_owned()))) } } impl reflection::PredicateReflection for ContainsPredicate {} impl fmt::Display for ContainsPredicate { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let palette = crate::Palette::new(f.alternate()); write!( f, "{}.{}({})", palette.var("var"), palette.description("contains"), palette.expected(&self.pattern), ) } } /// Predicate that checks for repeated patterns. /// /// This is created by `predicates::str::contains(...).count`. #[derive(Debug, Clone, PartialEq, Eq)] pub struct MatchesPredicate { pattern: String, count: usize, } impl Predicate for MatchesPredicate { fn eval(&self, variable: &str) -> bool { variable.matches(&self.pattern).count() == self.count } fn find_case<'a>(&'a self, expected: bool, variable: &str) -> Option> { let actual_count = variable.matches(&self.pattern).count(); let result = self.count == actual_count; if result == expected { Some( reflection::Case::new(Some(self), result) .add_product(reflection::Product::new("var", variable.to_owned())) .add_product(reflection::Product::new("actual count", actual_count)), ) } else { None } } } impl reflection::PredicateReflection for MatchesPredicate { fn parameters<'a>(&'a self) -> Box> + 'a> { let params = vec![reflection::Parameter::new("count", &self.count)]; Box::new(params.into_iter()) } } impl fmt::Display for MatchesPredicate { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let palette = crate::Palette::new(f.alternate()); write!( f, "{}.{}({})", palette.var("var"), palette.description("contains"), palette.expected(&self.pattern), ) } } /// Creates a new `Predicate` that ensures a str contains `pattern` /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let predicate_fn = predicate::str::contains("Two"); /// assert_eq!(true, predicate_fn.eval("One Two Three")); /// assert_eq!(false, predicate_fn.eval("Four Five Six")); /// ``` pub fn contains

(pattern: P) -> ContainsPredicate where P: Into, { ContainsPredicate { pattern: pattern.into(), } } predicates-3.1.0/src/str/difference.rs000064400000000000000000000102361046102023000160110ustar 00000000000000// Copyright (c) 2018 The predicates-rs Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use std::borrow; use std::fmt; use crate::reflection; use crate::Predicate; /// Predicate that diffs two strings. /// /// This is created by the `predicate::str::diff`. #[derive(Debug, Clone, PartialEq, Eq)] pub struct DifferencePredicate { orig: borrow::Cow<'static, str>, } impl Predicate for DifferencePredicate { fn eval(&self, edit: &str) -> bool { edit == self.orig } fn find_case<'a>(&'a self, expected: bool, variable: &str) -> Option> { let result = variable != self.orig; if result == expected { None } else { let palette = crate::Palette::new(true); let orig: Vec<_> = self.orig.lines().map(|l| format!("{}\n", l)).collect(); let variable: Vec<_> = variable.lines().map(|l| format!("{}\n", l)).collect(); let diff = difflib::unified_diff( &orig, &variable, "", "", &palette.expected("orig").to_string(), &palette.var("var").to_string(), 0, ); let mut diff = colorize_diff(diff, palette); diff.insert(0, "\n".to_owned()); Some( reflection::Case::new(Some(self), result) .add_product(reflection::Product::new("diff", diff.join(""))), ) } } } impl reflection::PredicateReflection for DifferencePredicate { fn parameters<'a>(&'a self) -> Box> + 'a> { let params = vec![reflection::Parameter::new("original", &self.orig)]; Box::new(params.into_iter()) } } impl fmt::Display for DifferencePredicate { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let palette = crate::Palette::new(f.alternate()); write!( f, "{:#} {:#} {:#}", palette.description("diff"), palette.expected("original"), palette.var("var"), ) } } /// Creates a new `Predicate` that diffs two strings. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let predicate_fn = predicate::str::diff("Hello World"); /// assert_eq!(true, predicate_fn.eval("Hello World")); /// assert!(predicate_fn.find_case(false, "Hello World").is_none()); /// assert_eq!(false, predicate_fn.eval("Goodbye World")); /// assert!(predicate_fn.find_case(false, "Goodbye World").is_some()); /// ``` pub fn diff(orig: S) -> DifferencePredicate where S: Into>, { DifferencePredicate { orig: orig.into() } } #[cfg(feature = "color")] fn colorize_diff(mut lines: Vec, palette: crate::Palette) -> Vec { for (i, line) in lines.iter_mut().enumerate() { match (i, line.as_bytes().first()) { (0, _) => { if let Some((prefix, body)) = line.split_once(' ') { *line = format!("{:#} {}", palette.expected(prefix), body); } } (1, _) => { if let Some((prefix, body)) = line.split_once(' ') { *line = format!("{:#} {}", palette.var(prefix), body); } } (_, Some(b'-')) => { let (prefix, body) = line.split_at(1); *line = format!("{:#}{}", palette.expected(prefix), body); } (_, Some(b'+')) => { let (prefix, body) = line.split_at(1); *line = format!("{:#}{}", palette.var(prefix), body); } (_, Some(b'@')) => { *line = format!("{:#}", palette.description(&line)); } _ => (), } } lines } #[cfg(not(feature = "color"))] fn colorize_diff(lines: Vec, _palette: crate::Palette) -> Vec { lines } predicates-3.1.0/src/str/mod.rs000064400000000000000000000016401046102023000144750ustar 00000000000000// Copyright (c) 2018 The predicates-rs Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! String Predicates //! //! This module contains predicates specific to string handling. mod basics; pub use self::basics::*; mod adapters; pub use self::adapters::*; #[cfg(feature = "diff")] mod difference; #[cfg(feature = "diff")] pub use self::difference::{diff, DifferencePredicate}; #[cfg(feature = "normalize-line-endings")] mod normalize; #[cfg(feature = "normalize-line-endings")] pub use self::normalize::NormalizedPredicate; #[cfg(feature = "regex")] mod regex; #[cfg(feature = "regex")] pub use self::regex::{is_match, RegexError, RegexPredicate}; predicates-3.1.0/src/str/normalize.rs000064400000000000000000000032131046102023000157140ustar 00000000000000// Copyright (c) 2018 The predicates-rs Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use crate::reflection; use crate::Predicate; use std::fmt; use normalize_line_endings::normalized; #[derive(Debug, Clone, Copy, PartialEq, Eq)] /// Predicate adapter that normalizes the newlines contained in the variable being tested. /// /// This is created by `pred.normalize()`. pub struct NormalizedPredicate

where P: Predicate, { pub(crate) p: P, } impl

reflection::PredicateReflection for NormalizedPredicate

where P: Predicate, { fn children<'a>(&'a self) -> Box> + 'a> { let params = vec![reflection::Child::new("predicate", &self.p)]; Box::new(params.into_iter()) } } impl

Predicate for NormalizedPredicate

where P: Predicate, { fn eval(&self, variable: &str) -> bool { let variable = normalized(variable.chars()).collect::(); self.p.eval(&variable) } fn find_case<'a>(&'a self, expected: bool, variable: &str) -> Option> { let variable = normalized(variable.chars()).collect::(); self.p.find_case(expected, &variable) } } impl

fmt::Display for NormalizedPredicate

where P: Predicate, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.p.fmt(f) } } predicates-3.1.0/src/str/regex.rs000064400000000000000000000100451046102023000150270ustar 00000000000000// Copyright (c) 2018 The predicates-rs Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use std::fmt; use crate::reflection; use crate::utils; use crate::Predicate; /// An error that occurred during parsing or compiling a regular expression. pub type RegexError = regex::Error; /// Predicate that uses regex matching /// /// This is created by the `predicate::str::is_match`. #[derive(Debug, Clone)] pub struct RegexPredicate { re: regex::Regex, } impl RegexPredicate { /// Require a specific count of matches. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let predicate_fn = predicate::str::is_match("T[a-z]*").unwrap().count(3); /// assert_eq!(true, predicate_fn.eval("One Two Three Two One")); /// assert_eq!(false, predicate_fn.eval("One Two Three")); /// ``` pub fn count(self, count: usize) -> RegexMatchesPredicate { RegexMatchesPredicate { re: self.re, count } } } impl Predicate for RegexPredicate { fn eval(&self, variable: &str) -> bool { self.re.is_match(variable) } fn find_case<'a>(&'a self, expected: bool, variable: &str) -> Option> { utils::default_find_case(self, expected, variable) .map(|case| case.add_product(reflection::Product::new("var", variable.to_owned()))) } } impl reflection::PredicateReflection for RegexPredicate {} impl fmt::Display for RegexPredicate { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let palette = crate::Palette::new(f.alternate()); write!( f, "{}.{}({})", palette.var("var"), palette.description("is_match"), palette.expected(&self.re), ) } } /// Predicate that checks for repeated patterns. /// /// This is created by `predicates::str::is_match(...).count`. #[derive(Debug, Clone)] pub struct RegexMatchesPredicate { re: regex::Regex, count: usize, } impl Predicate for RegexMatchesPredicate { fn eval(&self, variable: &str) -> bool { self.re.find_iter(variable).count() == self.count } fn find_case<'a>(&'a self, expected: bool, variable: &str) -> Option> { let actual_count = self.re.find_iter(variable).count(); let result = self.count == actual_count; if result == expected { Some( reflection::Case::new(Some(self), result) .add_product(reflection::Product::new("var", variable.to_owned())) .add_product(reflection::Product::new("actual count", actual_count)), ) } else { None } } } impl reflection::PredicateReflection for RegexMatchesPredicate { fn parameters<'a>(&'a self) -> Box> + 'a> { let params = vec![reflection::Parameter::new("count", &self.count)]; Box::new(params.into_iter()) } } impl fmt::Display for RegexMatchesPredicate { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let palette = crate::Palette::new(f.alternate()); write!( f, "{}.{}({})", palette.var("var"), palette.description("is_match"), palette.expected(&self.re), ) } } /// Creates a new `Predicate` that uses a regular expression to match the string. /// /// # Examples /// /// ``` /// use predicates::prelude::*; /// /// let predicate_fn = predicate::str::is_match("^Hello.*$").unwrap(); /// assert_eq!(true, predicate_fn.eval("Hello World")); /// assert_eq!(false, predicate_fn.eval("Food World")); /// ``` pub fn is_match(pattern: S) -> Result where S: AsRef, { regex::Regex::new(pattern.as_ref()).map(|re| RegexPredicate { re }) } predicates-3.1.0/src/utils.rs000064400000000000000000000025071046102023000142510ustar 00000000000000// Copyright (c) 2018 The predicates-rs Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use std::fmt; use crate::reflection; use crate::Predicate; #[derive(Clone, PartialEq, Eq)] pub(crate) struct DebugAdapter where T: fmt::Debug, { pub(crate) debug: T, } impl DebugAdapter where T: fmt::Debug, { pub fn new(debug: T) -> Self { Self { debug } } } impl fmt::Display for DebugAdapter where T: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:#?}", self.debug) } } impl fmt::Debug for DebugAdapter where T: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.debug.fmt(f) } } pub(crate) fn default_find_case<'a, P, Item>( pred: &'a P, expected: bool, variable: &Item, ) -> Option> where P: Predicate, Item: ?Sized, { let actual = pred.eval(variable); if expected == actual { Some(reflection::Case::new(Some(pred), actual)) } else { None } }