Implement Predicate<PathBuf> for BinaryFilePredicate
It would be handy if BinaryFilePredicate implemented Predicate<PathBuf>. There are some functions that, for lifetime reasons, must take a 'static argument, like PathBuf. Right now those functions can't easily use predicates.
I just gave it a try and didn't have any problems
#!/usr/bin/env run-cargo-script
//! ```cargo
//! [package]
//! edition="2018"
//! [dependencies]
//! predicates = "1"
//! ```
use predicates::prelude::*;
fn main() {
let actual = std::path::PathBuf::from("Cargo.toml");
let expected = std::path::PathBuf::from("Cargo.toml");
let pred = predicate::path::eq_file(expected);
println!("{}", pred.eval(actual.as_path()));
}
Could you clarify where you are having lifetime problems at?
It worked for you because of that as_path() on the last line. In my case I'm using predicates from a generic function, so I can't do that.
Could you provide an example so I can better understand the constraints and we can work out how predicates might be able to change to make it work?
It's basically like this. The matches function doesn't know anything about what type it's handling. It's not very critical for me, though.
#!/usr/bin/env run-cargo-script
//! ```cargo
//! [package]
//! edition="2018"
//! [dependencies]
//! predicates = "1"
//! ```
fn matches<T, P: Predicate<T>>(value: &T, predicate: P) -> bool {
predicate.eval(value)
}
use predicates::prelude::*;
fn main() {
let actual = std::path::PathBuf::from("Cargo.toml");
let expected = std::path::PathBuf::from("Cargo.toml");
let pred = predicate::path::eq_file(expected);
println!("{}", matches(&actual, pred));
}
Thanks for the example. For me to better understand the needs / use cases, is there a reason matches(actual.as_path(), pred) isn't sufficient?
Well, there's more generic code in front of that matches, and that code takes its argument by value, like this:
#!/usr/bin/env run-cargo-script
//! ```cargo
//! [package]
//! edition="2018"
//! [dependencies]
//! predicates = "1"
//! ```
fn do_something_with_value<T>(_value: T) {
}
fn do_something_with_value_if_it_matches<T, P>(value: T, predicate: P)
where P: Predicate<T>
{
if matches(&value, predicate) {
do_something_with_value(value)
}
}
fn matches<T, P: Predicate<T>>(value: &T, predicate: P) -> bool {
predicate.eval(value)
}
use predicates::prelude::*;
fn main() {
let actual = std::path::PathBuf::from("Cargo.toml");
let expected = std::path::PathBuf::from("Cargo.toml");
let pred = predicate::path::eq_file(expected);
do_something_with_value_if_it_matches(actual, pred);
}
btw this is related to #20 where I ran into a lot of problems solving this generically.
Some options
- We might be able to have blanket impls that translate
PathBufpredicates intoPathpredicates - We can add owned type
impl Predicateto each of our predicates - Don't know if I looked into whether
AsRef/ Deref / Borrow are object safe, allowing us to take&dyn AsRef<Path>.