predicates-rs icon indicating copy to clipboard operation
predicates-rs copied to clipboard

Implement Predicate<PathBuf> for BinaryFilePredicate

Open asomers opened this issue 6 years ago • 7 comments

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.

asomers avatar Feb 01 '19 21:02 asomers

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?

epage avatar Feb 02 '19 16:02 epage

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.

asomers avatar Feb 02 '19 16:02 asomers

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?

epage avatar Feb 02 '19 17:02 epage

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));
}

asomers avatar Feb 02 '19 17:02 asomers

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?

epage avatar Feb 02 '19 19:02 epage

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);
}

asomers avatar Feb 04 '19 21:02 asomers

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 PathBuf predicates into Path predicates
  • We can add owned type impl Predicate to 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>.

epage avatar Feb 05 '19 21:02 epage