Skip to content

Commit

Permalink
Rename TreeIterator to HierarchicalIterator.
Browse files Browse the repository at this point in the history
  • Loading branch information
olson-sean-k committed Nov 4, 2023
1 parent 3f7d628 commit b4fefd8
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 52 deletions.
98 changes: 51 additions & 47 deletions src/walk/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ impl<T> Filtrate<T> {
self.filter_map(From::from)
}

pub fn filter_map<U, F>(self, f: F) -> Residue<U>
pub fn filter_map<R, F>(self, f: F) -> Residue<R>
where
F: FnOnce(T) -> U,
F: FnOnce(T) -> R,
{
Residue::new(f(self.into_inner()))
}
Expand All @@ -88,9 +88,9 @@ impl<T> Filtrate<T> {
self.filter_map_node(From::from)
}

pub fn filter_map_node<U, F>(self, f: F) -> Residue<TreeResidue<U>>
pub fn filter_map_node<R, F>(self, f: F) -> Residue<TreeResidue<R>>
where
F: FnOnce(T) -> U,
F: FnOnce(T) -> R,
{
Residue::new(TreeResidue::Node(f(self.into_inner())))
}
Expand All @@ -102,14 +102,14 @@ impl<T> Filtrate<T> {
self.filter_map_tree(cancellation, From::from)
}

pub fn filter_map_tree<I, U, F>(
pub fn filter_map_tree<I, R, F>(
self,
mut cancellation: WalkCancellation<'_, I>,
f: F,
) -> Residue<TreeResidue<U>>
) -> Residue<TreeResidue<R>>
where
I: SkipTree,
F: FnOnce(T) -> U,
F: FnOnce(T) -> R,
{
cancellation.skip_tree();
Residue::new(TreeResidue::Tree(f(self.into_inner())))
Expand All @@ -127,9 +127,9 @@ pub trait Feed {
type Residue;
}

impl<T, U> Feed for (T, U) {
impl<T, R> Feed for (T, R) {
type Filtrate = T;
type Residue = U;
type Residue = R;
}

pub trait Isomeric: Feed {
Expand Down Expand Up @@ -161,6 +161,18 @@ where
Separation::Residue(Residue::new(residue))
}

pub fn filter_map<F>(self, f: F) -> Self
where
F: FnOnce(S::Filtrate) -> S::Residue,
{
match self {
Separation::Filtrate(filtrate) => {
Separation::from_inner_residue(f(filtrate.into_inner()))
},
separation => separation,
}
}

pub fn map_filtrate<U, F>(self, f: F) -> Separation<(U, S::Residue)>
where
F: FnOnce(S::Filtrate) -> U,
Expand Down Expand Up @@ -202,28 +214,21 @@ where
}
}

// TODO: Base this `impl` on concrete types (i.e., `(T, TreeResidue<R>)`) instead of trait bounds
// on `S`.
impl<R, S> Separation<S>
impl<T, R, S> Separation<S>
where
S: Feed<Residue = TreeResidue<R>>,
S: Feed<Filtrate = T, Residue = TreeResidue<R>>,
{
pub fn filter_map_node<F>(self, f: F) -> Self
where
F: FnOnce(S::Filtrate) -> R,
F: FnOnce(T) -> R,
{
match self {
Separation::Filtrate(filtrate) => {
Separation::from_inner_residue(TreeResidue::Node(f(filtrate.into_inner())))
},
separation => separation,
}
self.filter_map(|filtrate| TreeResidue::Node(f(filtrate)))
}

pub fn filter_map_tree<I, F>(self, mut cancellation: WalkCancellation<'_, I>, f: F) -> Self
where
I: SkipTree,
F: FnOnce(S::Filtrate) -> R,
F: FnOnce(T) -> R,
{
match self {
Separation::Filtrate(filtrate) => {
Expand All @@ -246,8 +251,8 @@ where
f: F,
) -> Self
where
R: From<S::Filtrate>,
S: Isomeric,
R: From<T>,
I: SkipTree,
F: FnOnce(S::Substituent<'_>) -> Option<TreeResidue<()>>,
{
Expand Down Expand Up @@ -332,9 +337,9 @@ impl<'i, I> WalkCancellation<'i, I> {
// TODO: This module should not allow this at all and `WalkCancellation`, much like
// `TypeState`, should not be possible to construct outside of the module. Instead,
// client code should rely solely on combinators, but this requires RPITIT to write
// combinators that accept arbitrary input type parameters (like `FnMut`s). RPITIT is
// slated to land at the end of December of 2023. Remove this and implement iterators
// using pure combinators when that happens.
// combinators with arbitrary output types (like unnameable `FnMut`s). RPITIT is slated
// to land at the end of December of 2023. Remove this and implement iterators using pure
// combinators when that happens.
pub(in crate::walk) fn unchecked(tree: &'i mut I) -> Self {
WalkCancellation(tree)
}
Expand Down Expand Up @@ -366,26 +371,18 @@ impl<T> AsRef<T> for TreeResidue<T> {
}
}

pub trait TreeIterator:
/// Hierarchical iterator over items in a tree data structure.
///
/// Here, _hierarchical_ means that the iterator traverses the tree in a manner that never yields a
/// node before its ancestors (e.g., a child node before its parent node). Both pre-order DFS and
/// BFS are examples of such a traversal.
///
/// `TreeIterator` allows client code to control tree traversal when filtering items using a
/// `WalkCancellation`, which discards a particular node and cancels traversal to its child nodes
/// (sub-tree). Filtering a sub-tree completely discards that tree, and no filter separation is
/// produced (no filtrate nor residue).
pub trait HierarchicalIterator:
Iterator<Item = <Self::Feed as Feed>::Filtrate> + SeparatingFilter + SkipTree
{
fn filter_tree_by_substituent<F>(self, f: F) -> FilterTreeBySubstituent<Self, F>
where
Self: Sized,
Self::Feed: Isomeric,
F: FnMut(<Self::Feed as Isomeric>::Substituent<'_>) -> Option<TreeResidue<()>>;

fn filter_map_tree<S, F>(self, f: F) -> FilterMapTree<Self, S, F>
where
Self: Sized,
S: Feed,
F: FnMut(WalkCancellation<Self>, Separation<Self::Feed>) -> Separation<S>;
}

impl<R, I> TreeIterator for I
where
I: Iterator<Item = <Self::Feed as Feed>::Filtrate> + SeparatingFilter + SkipTree,
I::Feed: Feed<Residue = TreeResidue<R>>,
{
fn filter_tree_by_substituent<F>(self, f: F) -> FilterTreeBySubstituent<Self, F>
where
Expand All @@ -400,7 +397,7 @@ where
where
Self: Sized,
S: Feed,
F: FnMut(WalkCancellation<Self>, Separation<I::Feed>) -> Separation<S>,
F: FnMut(WalkCancellation<Self>, Separation<Self::Feed>) -> Separation<S>,
{
FilterMapTree {
input: self,
Expand All @@ -410,6 +407,13 @@ where
}
}

impl<R, I> HierarchicalIterator for I
where
I: Iterator<Item = <Self::Feed as Feed>::Filtrate> + SeparatingFilter + SkipTree,
I::Feed: Feed<Residue = TreeResidue<R>>,
{
}

#[derive(Clone, Debug)]
pub struct FilterTreeBySubstituent<I, F> {
input: I,
Expand All @@ -419,7 +423,7 @@ pub struct FilterTreeBySubstituent<I, F> {
impl<R, I, F> SeparatingFilter for FilterTreeBySubstituent<I, F>
where
R: From<<I::Feed as Feed>::Filtrate>,
I: TreeIterator,
I: HierarchicalIterator,
I::Feed: Feed<Residue = TreeResidue<R>> + Isomeric,
F: FnMut(<I::Feed as Isomeric>::Substituent<'_>) -> Option<TreeResidue<()>>,
{
Expand All @@ -445,7 +449,7 @@ where
impl<R, I, F> Iterator for FilterTreeBySubstituent<I, F>
where
R: From<<I::Feed as Feed>::Filtrate>,
I: TreeIterator,
I: HierarchicalIterator,
I::Feed: Feed<Residue = TreeResidue<R>> + Isomeric,
F: FnMut(<I::Feed as Isomeric>::Substituent<'_>) -> Option<TreeResidue<()>>,
{
Expand Down
2 changes: 1 addition & 1 deletion src/walk/glob.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use walkdir::{self, WalkDir};
use crate::capture::MatchedText;
use crate::encode::CompileError;
use crate::token::{self, Token, TokenTree};
use crate::walk::filter::{self, SeparatingFilter, Separation, SkipTree, TreeIterator};
use crate::walk::filter::{self, HierarchicalIterator, SeparatingFilter, Separation, SkipTree};
use crate::walk::tree::{
EntryResidue, FileIterator, LinkBehavior, WalkBehavior, WalkEntry, WalkError, WalkTree,
};
Expand Down
12 changes: 8 additions & 4 deletions src/walk/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use thiserror::Error;
use walkdir::{self, DirEntry, WalkDir};

use crate::walk::filter::{
self, Isomeric, SeparatingFilter, SeparatingFilterInput, Separation, SkipTree, TreeIterator,
TreeResidue, WalkCancellation,
self, HierarchicalIterator, Isomeric, SeparatingFilter, SeparatingFilterInput, Separation,
SkipTree, TreeResidue, WalkCancellation,
};
use crate::walk::glob::WalkNegation;
use crate::{BuildError, Combine};
Expand Down Expand Up @@ -384,6 +384,10 @@ impl SeparatingFilterInput for WalkTree {
type Feed = (Result<WalkEntry, WalkError>, TreeResidue<WalkEntry>);
}

// TODO: This differing behavior is perhaps a bit more intuitive, but less flexible than
// `skip_current_dir`'s behavior. Crucially, `SkipTree` makes it extremely difficult to
// discard a directory in file tree based on its contents, such as some file with a name that
// indicates that a directory should be ignored, etc.
impl SkipTree for WalkTree {
fn skip_tree(&mut self) {
// `IntoIter::skip_current_dir` discards the least recently yielded directory, but
Expand All @@ -410,7 +414,7 @@ impl SkipTree for WalkTree {
/// [`WalkEntry`]: crate::WalkEntry
#[cfg_attr(docsrs, doc(cfg(feature = "walk")))]
pub trait FileIterator:
Iterator<Item = FileFiltrate<Self::Entry>> + TreeIterator<Feed = FileFeed<Self::Entry>>
HierarchicalIterator<Feed = FileFeed<Self::Entry>> + Iterator<Item = FileFiltrate<Self::Entry>>
{
type Entry;

Expand Down Expand Up @@ -548,7 +552,7 @@ pub trait FileIterator:

impl<T, I> FileIterator for I
where
I: Iterator<Item = FileFiltrate<T>> + TreeIterator<Feed = FileFeed<T>>,
I: HierarchicalIterator<Feed = FileFeed<T>> + Iterator<Item = FileFiltrate<T>>,
{
type Entry = T;
}
Expand Down

0 comments on commit b4fefd8

Please sign in to comment.