Skip to content

Commit

Permalink
Rename Compose to Combine.
Browse files Browse the repository at this point in the history
This change renames the `Compose` trait to `Combine` and uses the
"combine" nomenclature when discussing combinators (`Any`). Some
documentation and some identifiers concerning `Any` have also been
changed to reduce ambiguity and to better relfect these names.
  • Loading branch information
olson-sean-k committed Sep 29, 2023
1 parent a9862e8 commit 13a3e16
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 58 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ the expression to match or walk overlapping trees.

## Combinators

Glob patterns can be composed and matched together using the [`any`] combinator.
Glob patterns can be combined and matched together using the [`any`] combinator.
[`any`] accepts an [`IntoIterator`] with items that are compiled [`Pattern`]s or
`str` slices. The output is an [`Any`], which implements [`Pattern`] and
efficiently matches any of its input patterns.
Expand Down
68 changes: 46 additions & 22 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ impl From<token::Variance<InvariantText<'_>>> for Variance {
/// [`Glob::partition`]: crate::Glob::partition
/// [`Path`]: std::path::Path
/// [`PathBuf`]: std::path::PathBuf
pub trait Pattern<'t>: Compose<'t, Error = Infallible> {
pub trait Pattern<'t>: Combine<'t, Error = Infallible> {
/// Returns `true` if a path matches the pattern.
///
/// The given path must be convertible into a [`CandidatePath`].
Expand Down Expand Up @@ -255,21 +255,21 @@ pub trait Pattern<'t>: Compose<'t, Error = Infallible> {
fn is_exhaustive(&self) -> bool;
}

/// A glob expression representation that can be composed into a combinator like
/// [`Any`].
/// A glob expression representation that can be incorporated into a combinator.
///
/// See implementors and the [`any`] function.
/// This trait is implemented by types that can be (fallibly) converted into a
/// [`Pattern`] and incorporated into a combinator. See [`any`].
///
/// [`any`]: crate::any
/// [`Any`]: crate::Any
pub trait Compose<'t>:
TryInto<Checked<Self::Tokens>, Error = <Self as Compose<'t>>::Error>
/// [`Pattern`]: crate::Pattern
pub trait Combine<'t>:
TryInto<Checked<Self::Tokens>, Error = <Self as Combine<'t>>::Error>
{
type Tokens: TokenTree<'t>;
type Error: Into<BuildError>;
}

impl<'t> Compose<'t> for &'t str {
impl<'t> Combine<'t> for &'t str {
type Tokens = Tokenized<'t>;
type Error = BuildError;
}
Expand Down Expand Up @@ -682,7 +682,7 @@ impl<'t> Glob<'t> {
///
/// let path: &Path = /* ... */ // Candidate path.
/// # Path::new("");
///
///
/// let directory = Path::new("."); // Working directory.
/// let (prefix, glob) = Glob::new("../../src/**").unwrap().partition();
/// let prefix = dunce::canonicalize(directory.join(&prefix)).unwrap();
Expand Down Expand Up @@ -979,15 +979,15 @@ impl<'t> TryFrom<&'t str> for Glob<'t> {
}
}

impl<'t> Compose<'t> for Glob<'t> {
impl<'t> Combine<'t> for Glob<'t> {
type Tokens = Tokenized<'t>;
type Error = Infallible;
}

/// Combinator that matches any of its component [`Pattern`]s.
///
/// An instance of `Any` is constructed using the [`any`] function, which
/// composes multiple [`Pattern`]s for more ergonomic and efficient matching.
/// combines multiple [`Pattern`]s for more ergonomic and efficient matching.
///
/// [`any`]: crate::any
/// [`Pattern`]: crate::Pattern
Expand Down Expand Up @@ -1022,7 +1022,7 @@ impl<'t> Pattern<'t> for Any<'t> {
}
}

impl<'t> Compose<'t> for Any<'t> {
impl<'t> Combine<'t> for Any<'t> {
type Tokens = Token<'t, ()>;
type Error = Infallible;
}
Expand All @@ -1031,24 +1031,23 @@ impl<'t> Compose<'t> for Any<'t> {
// This would allow for a variety of types to be composed in an `any` call
// and would be especially useful if additional combinators are
// introduced.
/// Composes glob expressions into a combinator that matches if any of its input
/// [`Pattern`]s match.
/// Constructs a combinator that matches if any of its input [`Pattern`]s match.
///
/// This function accepts an [`IntoIterator`] with items that implement the
/// [`Compose`] trait such as [`Glob`] and `&str`. The output [`Any`] implements
/// [`Pattern`] by matching any of its component [`Pattern`]s. [`Any`] is often
/// more ergonomic and efficient than matching individually against multiple
/// This function accepts an [`IntoIterator`] with items that implement
/// [`Combine`], such as [`Glob`] and `&str`. The output [`Any`] implements
/// [`Pattern`] by matching its component [`Pattern`]s. [`Any`] is often more
/// ergonomic and efficient than matching individually against multiple
/// [`Pattern`]s.
///
/// [`Any`] groups all captures and therefore only exposes the complete text of
/// a match. It is not possible to index a particular capturing token in the
/// component patterns. [`Any`] only supports logical matching and cannot be
/// used to semantically match a directory tree.
/// component patterns. Combinators only support logical matching and cannot be
/// used to semantically match (walk) a directory tree.
///
/// # Examples
///
/// To match a path against multiple patterns, the patterns can first be
/// composed into an [`Any`].
/// combined into an [`Any`].
///
/// ```rust
/// use wax::{Glob, Pattern};
Expand All @@ -1074,20 +1073,45 @@ impl<'t> Compose<'t> for Any<'t> {
/// assert!(wax::any([red, blue]).unwrap().is_match("red/potion.txt"));
/// ```
///
/// This function can only combine patterns of the same type, but intermediate
/// combinators can be used to combine different types into a single combinator.
///
/// ```rust
/// use wax::{Glob, Pattern};
///
/// # fn fallible() -> Result<(), wax::BuildError> {
/// let glob = Glob::new("**/*.txt")?;
///
/// // ...
///
/// #[rustfmt::skip]
/// let any = wax::any([
/// wax::any([glob])?,
/// wax::any([
/// "**/*.pdf",
/// "**/*.tex",
/// ])?,
/// ])?;
/// assert!(any.is_match("doc/lattice.tex"));
/// # Ok(())
/// # }
/// ```
///
/// # Errors
///
/// Returns an error if any of the inputs fail to build. If the inputs are a
/// compiled [`Pattern`] type such as [`Glob`], then this only occurs if the
/// compiled program is too large.
///
/// [`Any`]: crate::Any
/// [`Combine`]: crate::Combine
/// [`Glob`]: crate::Glob
/// [`IntoIterator`]: std::iter::IntoIterator
/// [`Pattern`]: crate::Pattern
pub fn any<'t, I>(patterns: I) -> Result<Any<'t>, BuildError>
where
I: IntoIterator,
I::Item: Compose<'t>,
I::Item: Combine<'t>,
{
let tree = Checked::any(
patterns
Expand Down
52 changes: 26 additions & 26 deletions src/rule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use thiserror::Error;

use crate::diagnostics::{CompositeSpan, CorrelatedSpan, SpanExt as _};
use crate::token::{self, InvariantSize, Token, TokenKind, TokenTree, Tokenized};
use crate::{Any, BuildError, Compose, Glob};
use crate::{Any, BuildError, Combine, Glob};

/// Maximum invariant size.
///
Expand Down Expand Up @@ -283,35 +283,21 @@ impl<T> Checked<T> {
}
}

impl<T> AsRef<T> for Checked<T> {
fn as_ref(&self) -> &T {
&self.inner
}
}

impl<'t, T> Compose<'t> for Checked<T>
where
T: TokenTree<'t>,
{
type Tokens = T;
type Error = Infallible;
}

impl<'t> Checked<Token<'t, ()>> {
pub fn any<T, I>(tokens: I) -> Self
pub fn any<T, I>(trees: I) -> Self
where
T: TokenTree<'t>,
I: IntoIterator<Item = Checked<T>>,
{
Checked {
// `token::any` composes the input tokens into an alternative. The
// alternative is not checked, but the `any` combinator is
// explicitly allowed to ignore the subset of rules that may be
// `token::any` constructs an alternative from the input token
// trees. The alternative is not checked, but the `any` combinator
// is explicitly allowed to ignore the subset of rules that may be
// violated by this construction. In particular, branches may or may
// not have roots such that the alternative can match overlapping
// trees.
// directory trees.
inner: token::any(
tokens
trees
.into_iter()
.map(Checked::release)
.map(TokenTree::into_tokens),
Expand All @@ -328,6 +314,14 @@ impl<'t, A> Checked<Token<'t, A>> {
}
}

impl<'t, A> Checked<Tokenized<'t, A>> {
pub fn into_owned(self) -> Checked<Tokenized<'static, A>> {
Checked {
inner: self.release().into_owned(),
}
}
}

impl<'t> Checked<Tokenized<'t>> {
pub fn partition(self) -> (PathBuf, Self) {
let tokenized = self.release();
Expand All @@ -337,14 +331,20 @@ impl<'t> Checked<Tokenized<'t>> {
}
}

impl<'t, A> Checked<Tokenized<'t, A>> {
pub fn into_owned(self) -> Checked<Tokenized<'static, A>> {
Checked {
inner: self.release().into_owned(),
}
impl<T> AsRef<T> for Checked<T> {
fn as_ref(&self) -> &T {
&self.inner
}
}

impl<'t, T> Combine<'t> for Checked<T>
where
T: TokenTree<'t>,
{
type Tokens = T;
type Error = Infallible;
}

impl<'t> From<Any<'t>> for Checked<Token<'t, ()>> {
fn from(any: Any<'t>) -> Self {
let Any { tree, .. } = any;
Expand Down
19 changes: 10 additions & 9 deletions src/walk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use walkdir::{self, DirEntry, WalkDir};
use crate::capture::MatchedText;
use crate::encode::CompileError;
use crate::token::{self, Token, TokenTree};
use crate::{BuildError, CandidatePath, Compose, Glob};
use crate::{BuildError, CandidatePath, Combine, Glob};

pub type WalkItem<'e> = Result<WalkEntry<'e>, WalkError>;

Expand Down Expand Up @@ -344,24 +344,25 @@ pub struct Negation {
}

impl Negation {
/// Composes glob expressions into a `Negation`.
/// Combines glob expressions into a `Negation`.
///
/// This function accepts an [`IntoIterator`] with items that implement the
/// [`Compose`] trait such as [`Glob`] and `&str`.
/// This function accepts an [`IntoIterator`] with items that implement
/// [`Combine`], such as [`Glob`] and `&str`.
///
/// # Errors
///
/// Returns an error if any of the inputs fail to build. If the inputs are a
/// compiled [`Pattern`] type such as [`Glob`], then this only occurs if the
/// compiled program is too large.
/// compiled [`Pattern`] types such as [`Glob`], then this only occurs if
/// the compiled program is too large.
///
/// [`Combine`]: crate::Combine
/// [`Glob`]: crate::Glob
/// [`Pattern`]: crate::Pattern
/// [`IntoIterator`]: std::iter::IntoIterator
/// [`Pattern`]: crate::Pattern
pub fn any<'t, I>(patterns: I) -> Result<Self, BuildError>
where
I: IntoIterator,
I::Item: Compose<'t>,
I::Item: Combine<'t>,
{
let (exhaustive, nonexhaustive) = patterns
.into_iter()
Expand Down Expand Up @@ -667,7 +668,7 @@ impl<'g> Walk<'g> {
pub fn not<'t, I>(self, patterns: I) -> Result<impl 'g + FileIterator, BuildError>
where
I: IntoIterator,
I::Item: Compose<'t>,
I::Item: Combine<'t>,
{
Negation::any(patterns)
.map(|negation| self.filter_tree(move |entry| negation.target(entry)))
Expand Down

0 comments on commit 13a3e16

Please sign in to comment.