olson-sean-k / wax

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

Facilities for writing custom `Patterns` #39

Open arlyon opened 1 year ago

arlyon commented 1 year ago

Hi! Great library!

I would like to be able to write custom combinators such as InclusiveEmptyAny which matches any path in the event that the list of globs is empty. I tried implementing Pattern and Compose myself to do so but it seems like I need to implement From<Checked> to do so, which is private. The types that the library uses to do so are private also, so it seems that this is not possible as-is.

Similarly, it is impossible to implement Pattern::matched correctly since MatchedText and friends are currently private also.

Any pointers?

//! A simple `wax` combinator that unconditionally matches if the set of globs
//! is empty.

use std::convert::Infallible;

use wax::{Any, BuildError, CandidatePath, Compose, MatchedText, Pattern, Variance};

pub struct InclusiveEmptyAny<'a>(Option<Any<'a>>);

impl<'a> InclusiveEmptyAny<'a> {
    pub fn new<I>(patterns: I) -> Result<Self, BuildError>
    where
        I: IntoIterator,
        I::Item: Compose<'a>,
    {
        let iter = patterns.into_iter().collect::<Vec<_>>();
        if iter.len() == 0 {
            Ok(Self(None))
        } else {
            Ok(Self(Some(wax::any(iter)?)))
        }
    }
}

impl<'t> Compose<'t> for InclusiveEmptyAny<'t> {
    type Tokens = (); // what should this be?
    type Error = Infallible;
}

impl<'t> Pattern<'t> for InclusiveEmptyAny<'t> {
    fn is_match<'p>(&self, path: impl Into<CandidatePath<'p>>) -> bool {
        match self.0 {
            Some(ref any) => any.is_match(path),
            None => true,
        }
    }

    fn matched<'p>(&self, path: &'p CandidatePath<'_>) -> Option<MatchedText<'p>> {
        match self.0 {
            Some(ref any) => any.matched(path),
            None => Some(path.into()), // is this ok?
        }
    }

    fn variance(&self) -> Variance {
        match self.0 {
            Some(ref any) => any.variance(),
            None => Variance::Variant,
        }
    }

    fn is_exhaustive(&self) -> bool {
        match self.0 {
            Some(ref any) => any.is_exhaustive(),
            None => true,
        }
    }
}
error[E0277]: the trait bound `wax::rule::Checked<()>: From<InclusiveEmptyAny<'t>>` is not satisfied
   --> crates/globwalk/src/empty_glob.rs:27:18
    |
27  |     type Error = Infallible;
    |                  ^^^^^^^^^^ the trait `From<InclusiveEmptyAny<'t>>` is not implemented for `wax::rule::Checked<()>`
    |
    = help: the following other types implement trait `From<T>`:
              <wax::rule::Checked<wax::token::Token<'t, ()>> as From<wax::Any<'t>>>
              <wax::rule::Checked<wax::token::Tokenized<'t>> as From<Glob<'t>>>
    = note: required for `InclusiveEmptyAny<'t>` to implement `Into<wax::rule::Checked<()>>`
    = note: required for `wax::rule::Checked<()>` to implement `TryFrom<InclusiveEmptyAny<'t>>`
note: required by a bound in `Compose`
   --> /Users/arlyon/Programming/wax/src/lib.rs:314:36
    |
314 |     TryInto<Checked<Self::Tokens>, Error = <Self as Compose<'t>>::Error>
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Compose`

error[E0277]: the trait bound `wax::rule::Checked<()>: From<InclusiveEmptyAny<'t>>` is not satisfied
   --> crates/globwalk/src/empty_glob.rs:30:10
    |
30  | impl<'t> Pattern<'t> for InclusiveEmptyAny<'t> {
    |          ^^^^^^^^^^^ the trait `From<InclusiveEmptyAny<'t>>` is not implemented for `wax::rule::Checked<()>`
    |
    = help: the following other types implement trait `From<T>`:
              <wax::rule::Checked<wax::token::Token<'t, ()>> as From<wax::Any<'t>>>
              <wax::rule::Checked<wax::token::Tokenized<'t>> as From<Glob<'t>>>
    = note: required for `InclusiveEmptyAny<'t>` to implement `Into<wax::rule::Checked<()>>`
    = note: required for `wax::rule::Checked<()>` to implement `TryFrom<InclusiveEmptyAny<'t>>`
    = note: required for `InclusiveEmptyAny<'t>` to implement `Compose<'t>`
note: required by a bound in `wax::Pattern`
   --> /Users/arlyon/Programming/wax/src/lib.rs:276:24
    |
276 | pub trait Pattern<'t>: Compose<'t, Error = Infallible> {
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Pattern`