From fb40eafaff69c5549a710bbbd81541a56af4ce24 Mon Sep 17 00:00:00 2001 From: nivkner Date: Tue, 27 Jun 2017 13:58:19 +0300 Subject: Remove WalkDirIterator (#58) remove WalkDirIterator And make skip_current_dir and filter_entry inherent methods. Fixes #40. --- README.md | 2 +- src/lib.rs | 268 +++++++++++++++++++++++++++++++++++++---------------------- src/tests.rs | 2 +- 3 files changed, 170 insertions(+), 102 deletions(-) diff --git a/README.md b/README.md index ee525de..97d6840 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ This uses the `filter_entry` iterator adapter to avoid yielding hidden files and directories efficiently: ```rust,no_run -use walkdir::{DirEntry, WalkDir, WalkDirIterator}; +use walkdir::{DirEntry, WalkDir}; fn is_hidden(entry: &DirEntry) -> bool { entry.file_name() diff --git a/src/lib.rs b/src/lib.rs index 872a839..b38544d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,9 +16,7 @@ walkdir = "1" # From the top -The `WalkDir` type builds iterators. The `WalkDirIterator` trait provides -methods for directory iterator adapters, such as efficiently pruning entries -during traversal. The `DirEntry` type describes values yielded by the iterator. +The `WalkDir` type builds iterators. The `DirEntry` type describes values yielded by the iterator. Finally, the `Error` type is a small wrapper around `std::io::Error` with additional information, such as if a loop was detected while following symbolic links (not enabled by default). @@ -68,7 +66,7 @@ This uses the `filter_entry` iterator adapter to avoid yielding hidden files and directories efficiently: ```rust,no_run -use walkdir::{DirEntry, WalkDir, WalkDirIterator}; +use walkdir::{DirEntry, WalkDir}; fn is_hidden(entry: &DirEntry) -> bool { entry.file_name() @@ -342,91 +340,6 @@ impl IntoIterator for WalkDir { } } -/// A trait for recursive directory iterators. -pub trait WalkDirIterator: Iterator { - /// Skips the current directory. - /// - /// This causes the iterator to stop traversing the contents of the least - /// recently yielded directory. This means any remaining entries in that - /// directory will be skipped (including sub-directories). - /// - /// Note that the ergonomics of this method are questionable since it - /// borrows the iterator mutably. Namely, you must write out the looping - /// condition manually. For example, to skip hidden entries efficiently on - /// unix systems: - /// - /// ```rust,no_run - /// use walkdir::{DirEntry, WalkDir, WalkDirIterator}; - /// - /// fn is_hidden(entry: &DirEntry) -> bool { - /// entry.file_name() - /// .to_str() - /// .map(|s| s.starts_with(".")) - /// .unwrap_or(false) - /// } - /// - /// let mut it = WalkDir::new("foo").into_iter(); - /// loop { - /// let entry = match it.next() { - /// None => break, - /// Some(Err(err)) => panic!("ERROR: {}", err), - /// Some(Ok(entry)) => entry, - /// }; - /// if is_hidden(&entry) { - /// if entry.file_type().is_dir() { - /// it.skip_current_dir(); - /// } - /// continue; - /// } - /// println!("{}", entry.path().display()); - /// } - /// ``` - /// - /// You may find it more convenient to use the `filter_entry` iterator - /// adapter. (See its documentation for the same example functionality as - /// above.) - fn skip_current_dir(&mut self); - - /// Yields only entries which satisfy the given predicate and skips - /// descending into directories that do not satisfy the given predicate. - /// - /// The predicate is applied to all entries. If the predicate is - /// true, iteration carries on as normal. If the predicate is false, the - /// entry is ignored and if it is a directory, it is not descended into. - /// - /// This is often more convenient to use than `skip_current_dir`. For - /// example, to skip hidden files and directories efficiently on unix - /// systems: - /// - /// ```rust,no_run - /// use walkdir::{DirEntry, WalkDir, WalkDirIterator}; - /// - /// fn is_hidden(entry: &DirEntry) -> bool { - /// entry.file_name() - /// .to_str() - /// .map(|s| s.starts_with(".")) - /// .unwrap_or(false) - /// } - /// - /// for entry in WalkDir::new("foo") - /// .into_iter() - /// .filter_entry(|e| !is_hidden(e)) { - /// let entry = entry.unwrap(); - /// println!("{}", entry.path().display()); - /// } - /// ``` - /// - /// Note that the iterator will still yield errors for reading entries that - /// may not satisfy the predicate. - /// - /// Note that entries skipped with `min_depth` and `max_depth` are not - /// passed to this predicate. - fn filter_entry

(self, predicate: P) -> FilterEntry - where Self: Sized, P: FnMut(&DirEntry) -> bool { - FilterEntry { it: self, predicate: predicate } - } -} - /// An iterator for recursively descending into a directory. /// /// A value with this type must be constructed with the `WalkDir` type, which @@ -561,8 +474,49 @@ impl Iterator for IntoIter { } } -impl WalkDirIterator for IntoIter { - fn skip_current_dir(&mut self) { +impl IntoIter { + /// Skips the current directory. + /// + /// This causes the iterator to stop traversing the contents of the least + /// recently yielded directory. This means any remaining entries in that + /// directory will be skipped (including sub-directories). + /// + /// Note that the ergonomics of this method are questionable since it + /// borrows the iterator mutably. Namely, you must write out the looping + /// condition manually. For example, to skip hidden entries efficiently on + /// unix systems: + /// + /// ```rust,no_run + /// use walkdir::{DirEntry, WalkDir}; + /// + /// fn is_hidden(entry: &DirEntry) -> bool { + /// entry.file_name() + /// .to_str() + /// .map(|s| s.starts_with(".")) + /// .unwrap_or(false) + /// } + /// + /// let mut it = WalkDir::new("foo").into_iter(); + /// loop { + /// let entry = match it.next() { + /// None => break, + /// Some(Err(err)) => panic!("ERROR: {}", err), + /// Some(Ok(entry)) => entry, + /// }; + /// if is_hidden(&entry) { + /// if entry.file_type().is_dir() { + /// it.skip_current_dir(); + /// } + /// continue; + /// } + /// println!("{}", entry.path().display()); + /// } + /// ``` + /// + /// You may find it more convenient to use the `filter_entry` iterator + /// adapter. (See its documentation for the same example functionality as + /// above.) + pub fn skip_current_dir(&mut self) { if !self.stack_list.is_empty() { self.stack_list.pop(); } @@ -570,9 +524,46 @@ impl WalkDirIterator for IntoIter { self.stack_path.pop(); } } -} -impl IntoIter { + /// Yields only entries which satisfy the given predicate and skips + /// descending into directories that do not satisfy the given predicate. + /// + /// The predicate is applied to all entries. If the predicate is + /// true, iteration carries on as normal. If the predicate is false, the + /// entry is ignored and if it is a directory, it is not descended into. + /// + /// This is often more convenient to use than `skip_current_dir`. For + /// example, to skip hidden files and directories efficiently on unix + /// systems: + /// + /// ```rust,no_run + /// use walkdir::{DirEntry, WalkDir}; + /// + /// fn is_hidden(entry: &DirEntry) -> bool { + /// entry.file_name() + /// .to_str() + /// .map(|s| s.starts_with(".")) + /// .unwrap_or(false) + /// } + /// + /// for entry in WalkDir::new("foo") + /// .into_iter() + /// .filter_entry(|e| !is_hidden(e)) { + /// let entry = entry.unwrap(); + /// println!("{}", entry.path().display()); + /// } + /// ``` + /// + /// Note that the iterator will still yield errors for reading entries that + /// may not satisfy the predicate. + /// + /// Note that entries skipped with `min_depth` and `max_depth` are not + /// passed to this predicate. + pub fn filter_entry

(self, predicate: P) -> FilterEntry + where Self: Sized, P: FnMut(&DirEntry) -> bool { + FilterEntry { it: self, predicate: predicate } + } + fn handle_entry( &mut self, mut dent: DirEntry, @@ -890,9 +881,8 @@ pub struct FilterEntry { predicate: P, } -impl Iterator for FilterEntry - where I: WalkDirIterator>, - P: FnMut(&DirEntry) -> bool { +impl

Iterator for FilterEntry + where P: FnMut(&DirEntry) -> bool { type Item = Result; fn next(&mut self) -> Option> { @@ -912,10 +902,88 @@ impl Iterator for FilterEntry } } -impl WalkDirIterator for FilterEntry - where I: WalkDirIterator>, - P: FnMut(&DirEntry) -> bool { - fn skip_current_dir(&mut self) { +impl

FilterEntry + where P: FnMut(&DirEntry) -> bool { + /// Yields only entries which satisfy the given predicate and skips + /// descending into directories that do not satisfy the given predicate. + /// + /// The predicate is applied to all entries. If the predicate is + /// true, iteration carries on as normal. If the predicate is false, the + /// entry is ignored and if it is a directory, it is not descended into. + /// + /// This is often more convenient to use than `skip_current_dir`. For + /// example, to skip hidden files and directories efficiently on unix + /// systems: + /// + /// ```rust,no_run + /// use walkdir::{DirEntry, WalkDir}; + /// + /// fn is_hidden(entry: &DirEntry) -> bool { + /// entry.file_name() + /// .to_str() + /// .map(|s| s.starts_with(".")) + /// .unwrap_or(false) + /// } + /// + /// for entry in WalkDir::new("foo") + /// .into_iter() + /// .filter_entry(|e| !is_hidden(e)) { + /// let entry = entry.unwrap(); + /// println!("{}", entry.path().display()); + /// } + /// ``` + /// + /// Note that the iterator will still yield errors for reading entries that + /// may not satisfy the predicate. + /// + /// Note that entries skipped with `min_depth` and `max_depth` are not + /// passed to this predicate. + pub fn filter_entry(self, predicate: P) -> FilterEntry { + FilterEntry { it: self, predicate: predicate } + } + + /// Skips the current directory. + /// + /// This causes the iterator to stop traversing the contents of the least + /// recently yielded directory. This means any remaining entries in that + /// directory will be skipped (including sub-directories). + /// + /// Note that the ergonomics of this method are questionable since it + /// borrows the iterator mutably. Namely, you must write out the looping + /// condition manually. For example, to skip hidden entries efficiently on + /// unix systems: + /// + /// ```rust,no_run + /// use walkdir::{DirEntry, WalkDir}; + /// + /// fn is_hidden(entry: &DirEntry) -> bool { + /// entry.file_name() + /// .to_str() + /// .map(|s| s.starts_with(".")) + /// .unwrap_or(false) + /// } + /// + /// let mut it = WalkDir::new("foo").into_iter(); + /// loop { + /// let entry = match it.next() { + /// None => break, + /// Some(Err(err)) => panic!("ERROR: {}", err), + /// Some(Ok(entry)) => entry, + /// }; + /// if is_hidden(&entry) { + /// if entry.file_type().is_dir() { + /// it.skip_current_dir(); + /// } + /// continue; + /// } + /// println!("{}", entry.path().display()); + /// } + /// ``` + /// + /// You may find it more convenient to use the `filter_entry` iterator + /// adapter. (See its documentation for the same example functionality as + /// above.) + pub fn skip_current_dir(&mut self) { self.it.skip_current_dir(); } } diff --git a/src/tests.rs b/src/tests.rs index 2239cc7..7e3dbeb 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -10,7 +10,7 @@ use std::collections::HashMap; use quickcheck::{Arbitrary, Gen, QuickCheck, StdGen}; use rand::{self, Rng}; -use super::{DirEntry, WalkDir, WalkDirIterator, IntoIter, Error, ErrorInner}; +use super::{DirEntry, WalkDir, IntoIter, Error, ErrorInner}; #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] enum Tree { -- cgit v1.2.3