olson-sean-k / wax

Opinionated and portable globs that can be matched against paths and directory trees.
https://glob.guide
MIT License
115 stars 10 forks source link

Trouble getting `not()` to build #25

Closed milesj closed 2 years ago

milesj commented 2 years ago

Me again. I recently updated to 0.5.0 and was looking forward to using not() for negation. My code changes are here: https://github.com/moonrepo/moon/pull/130/files#diff-59f9b6fb165685b88f87aed332e7f4f396bb795b2ad3f302f7d7944a36aa7cf6L123

For context, the negations come from a config file and are a Vec<String>, but Rust fails to build when I pass this type to not().

error[E0271]: type mismatch resolving `<std::string::String as TryInto<Glob<'_>>>::Error == BuildError<'_>`
   --> crates/utils/src/glob.rs:126:14
    |
126 |             .not(negations)?
    |              ^^^ expected struct `BuildError`, found enum `Infallible`
    |

I then tried references with &Vec<string> and even Vec<&str> with no luck. Both throw the same error above.

I've even tried converting the strings to Globs and passing Vec<Glob>, but that still fails to build also.

error[E0271]: type mismatch resolving `<Glob<'_> as TryInto<Glob<'_>>>::Error == BuildError<'_>`
   --> crates/utils/src/glob.rs:126:14
    |
126 |             .not(
    |              ^^^ expected struct `BuildError`, found enum `Infallible`
    |

The only thing that does work is explicitly passing [&str], like .not(["test/**/*"]), but this isn't an option for me.

Basically everything I've tried has failed, and I'm curious if you have any suggestions here.

olson-sean-k commented 2 years ago

Thanks for opening an issue!

This is a bug in the API. Instead of accepting types that emit a compatible error when converting into a Glob, the not function requires that the conversion emit BuildError. In the linked change, you've already constructed Globs, so the conversion is infallible and emits the Infallible error. This should work, but the API applies the wrong constraints.

I fear that functions like not and try_from_patterns put too much "type magic" in the public API. As a more immediate fix, I'll change the constraints on not so that the code in the linked change builds, but I'm considering changing these APIs to something less flexible but more simple.

olson-sean-k commented 2 years ago

In the meantime, you may be able to work around this by using Negation and filter_tree directly. The Negation::try_from_patterns function should be more flexible.

let glob = Glob::new(...).unwrap();
let nglobs: Vec<Glob> = ...;
let negation = Negation::try_from_patterns(nglobs).unwrap();
for entry in glob
    .walk(...)
    .filter_tree(move |entry| negation.target(entry))
{
    let entry = entry.unwrap();
    ...
}

See also the implementation of not, which uses Negation and filter_tree in the same way.

milesj commented 2 years ago

Thanks, using Negation directly unblocks me for now.

olson-sean-k commented 2 years ago

This has been fixed in 6d66a10. That change uses similar constraints in not as are used in try_from_patterns so that not can accept Globs directly.