From 265298bc9f85cf29054e32bda257be66b9324368 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vuka=C5=A1in=20Stepanovi=C4=87?= Date: Thu, 12 Aug 2021 09:16:58 +0200 Subject: [PATCH 01/10] Add MinDepth filter --- src/filter/common.rs | 6 ++++++ src/filter/min_depth.rs | 21 +++++++++++++++++++++ src/filter/mod.rs | 6 ++++++ src/walk.rs | 13 +++++++++---- 4 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 src/filter/common.rs create mode 100644 src/filter/min_depth.rs diff --git a/src/filter/common.rs b/src/filter/common.rs new file mode 100644 index 000000000..6ebe086b7 --- /dev/null +++ b/src/filter/common.rs @@ -0,0 +1,6 @@ +use crate::walk::DirEntry; + +pub trait Filter { + /// Whether the entry should be skipped or not. + fn should_skip(&self, entry: &DirEntry) -> bool; +} diff --git a/src/filter/min_depth.rs b/src/filter/min_depth.rs new file mode 100644 index 000000000..23540e800 --- /dev/null +++ b/src/filter/min_depth.rs @@ -0,0 +1,21 @@ +use crate::walk::DirEntry; + +use super::common::Filter; + +pub struct MinDepth { + min_depth: Option, +} + +impl MinDepth { + pub fn new(min_depth: Option) -> Self { + Self { min_depth } + } +} + +impl Filter for MinDepth { + fn should_skip(&self, entry: &DirEntry) -> bool { + self.min_depth + .map(|min_depth| entry.depth().map_or(true, |d| d < min_depth)) + .unwrap_or_default() + } +} diff --git a/src/filter/mod.rs b/src/filter/mod.rs index 5e45d3b1c..880948863 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -1,9 +1,15 @@ pub use self::size::SizeFilter; pub use self::time::TimeFilter; +pub use self::common::Filter; +pub use self::min_depth::MinDepth; + #[cfg(unix)] pub use self::owner::OwnerFilter; +mod common; +mod min_depth; + mod size; mod time; diff --git a/src/walk.rs b/src/walk.rs index bcb15d4be..b77d7301d 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -19,6 +19,7 @@ use crate::error::print_error; use crate::exec; use crate::exit_codes::{merge_exitcodes, ExitCode}; use crate::filesystem; +use crate::filter::{Filter, MinDepth}; use crate::options::Options; use crate::output; @@ -383,10 +384,14 @@ fn spawn_senders( } }; - if let Some(min_depth) = config.min_depth { - if entry.depth().map_or(true, |d| d < min_depth) { - return ignore::WalkState::Continue; - } + let filters: Vec> = vec![Box::new(MinDepth::new(config.min_depth))]; + + let result = filters + .iter() + .find_map(|x| x.should_skip(&entry).then(|| ignore::WalkState::Continue)); + + if let Some(x) = result { + return x; } // Check the name first, since it doesn't require metadata From c673798a0a6e69d6ee1320adb4134fb05285418d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vuka=C5=A1in=20Stepanovi=C4=87?= Date: Thu, 12 Aug 2021 09:19:20 +0200 Subject: [PATCH 02/10] Add RegexMatch filter --- src/filter/mod.rs | 2 ++ src/filter/regex_match.rs | 46 +++++++++++++++++++++++++++++++++++++++ src/walk.rs | 28 +++++------------------- 3 files changed, 53 insertions(+), 23 deletions(-) create mode 100644 src/filter/regex_match.rs diff --git a/src/filter/mod.rs b/src/filter/mod.rs index 880948863..a54433fa9 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -3,12 +3,14 @@ pub use self::time::TimeFilter; pub use self::common::Filter; pub use self::min_depth::MinDepth; +pub use self::regex_match::RegexMatch; #[cfg(unix)] pub use self::owner::OwnerFilter; mod common; mod min_depth; +mod regex_match; mod size; mod time; diff --git a/src/filter/regex_match.rs b/src/filter/regex_match.rs new file mode 100644 index 000000000..46c8c7d4f --- /dev/null +++ b/src/filter/regex_match.rs @@ -0,0 +1,46 @@ +use std::{borrow::Cow, ffi::OsStr, sync::Arc}; + +use regex::bytes::Regex; + +use crate::filesystem; + +use super::common::Filter; + +pub struct RegexMatch { + pattern: Arc, + search_full_path: bool, +} + +impl RegexMatch { + pub fn new(pattern: Arc, search_full_path: bool) -> Self { + Self { + pattern, + search_full_path, + } + } +} + +impl Filter for RegexMatch { + fn should_skip(&self, entry: &crate::walk::DirEntry) -> bool { + let entry_path = entry.path(); + + let search_str: Cow = if self.search_full_path { + let path_abs_buf = filesystem::path_absolute_form(entry_path) + .expect("Retrieving absolute path succeeds"); + Cow::Owned(path_abs_buf.as_os_str().to_os_string()) + } else { + match entry_path.file_name() { + Some(filename) => Cow::Borrowed(filename), + None => unreachable!( + "Encountered file system entry without a file name. This should only \ + happen for paths like 'foo/bar/..' or '/' which are not supposed to \ + appear in a file system traversal." + ), + } + }; + + !self + .pattern + .is_match(&filesystem::osstr_to_bytes(search_str.as_ref())) + } +} diff --git a/src/walk.rs b/src/walk.rs index b77d7301d..7a2f1cb8a 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -1,5 +1,3 @@ -use std::borrow::Cow; -use std::ffi::OsStr; use std::fs::{FileType, Metadata}; use std::io; use std::path::{Path, PathBuf}; @@ -19,7 +17,7 @@ use crate::error::print_error; use crate::exec; use crate::exit_codes::{merge_exitcodes, ExitCode}; use crate::filesystem; -use crate::filter::{Filter, MinDepth}; +use crate::filter::{Filter, MinDepth, RegexMatch}; use crate::options::Options; use crate::output; @@ -384,7 +382,10 @@ fn spawn_senders( } }; - let filters: Vec> = vec![Box::new(MinDepth::new(config.min_depth))]; + let filters: Vec> = vec![ + Box::new(MinDepth::new(config.min_depth)), + Box::new(RegexMatch::new(pattern.clone(), config.search_full_path)), + ]; let result = filters .iter() @@ -397,25 +398,6 @@ fn spawn_senders( // Check the name first, since it doesn't require metadata let entry_path = entry.path(); - let search_str: Cow = if config.search_full_path { - let path_abs_buf = filesystem::path_absolute_form(entry_path) - .expect("Retrieving absolute path succeeds"); - Cow::Owned(path_abs_buf.as_os_str().to_os_string()) - } else { - match entry_path.file_name() { - Some(filename) => Cow::Borrowed(filename), - None => unreachable!( - "Encountered file system entry without a file name. This should only \ - happen for paths like 'foo/bar/..' or '/' which are not supposed to \ - appear in a file system traversal." - ), - } - }; - - if !pattern.is_match(&filesystem::osstr_to_bytes(search_str.as_ref())) { - return ignore::WalkState::Continue; - } - // Filter out unwanted extensions. if let Some(ref exts_regex) = config.extensions { if let Some(path_str) = entry_path.file_name() { From 5f4b06de2102dfd6a5ca198e8977b93c16a40a92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vuka=C5=A1in=20Stepanovi=C4=87?= Date: Thu, 12 Aug 2021 09:26:02 +0200 Subject: [PATCH 03/10] Add Extensions filter --- src/filter/extensions.rs | 30 ++++++++++++++++++++++++++++++ src/filter/mod.rs | 2 ++ src/walk.rs | 15 ++------------- 3 files changed, 34 insertions(+), 13 deletions(-) create mode 100644 src/filter/extensions.rs diff --git a/src/filter/extensions.rs b/src/filter/extensions.rs new file mode 100644 index 000000000..07678ca42 --- /dev/null +++ b/src/filter/extensions.rs @@ -0,0 +1,30 @@ +use regex::bytes::RegexSet; + +use crate::filesystem; + +use super::common::Filter; + +pub struct Extensions { + extensions: Option, +} + +impl Extensions { + pub fn new(extensions: Option) -> Self { + Self { extensions } + } +} + +impl Filter for Extensions { + fn should_skip(&self, entry: &crate::walk::DirEntry) -> bool { + self.extensions + .as_ref() + .map(|exts_regex| { + entry + .path() + .file_name() + .map(|path_str| !exts_regex.is_match(&filesystem::osstr_to_bytes(path_str))) + .unwrap_or(true) + }) + .unwrap_or_default() + } +} diff --git a/src/filter/mod.rs b/src/filter/mod.rs index a54433fa9..b656e706b 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -2,6 +2,7 @@ pub use self::size::SizeFilter; pub use self::time::TimeFilter; pub use self::common::Filter; +pub use self::extensions::Extensions; pub use self::min_depth::MinDepth; pub use self::regex_match::RegexMatch; @@ -9,6 +10,7 @@ pub use self::regex_match::RegexMatch; pub use self::owner::OwnerFilter; mod common; +mod extensions; mod min_depth; mod regex_match; diff --git a/src/walk.rs b/src/walk.rs index 7a2f1cb8a..5294cf1b0 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -16,8 +16,7 @@ use regex::bytes::Regex; use crate::error::print_error; use crate::exec; use crate::exit_codes::{merge_exitcodes, ExitCode}; -use crate::filesystem; -use crate::filter::{Filter, MinDepth, RegexMatch}; +use crate::filter::{Extensions, Filter, MinDepth, RegexMatch}; use crate::options::Options; use crate::output; @@ -385,6 +384,7 @@ fn spawn_senders( let filters: Vec> = vec![ Box::new(MinDepth::new(config.min_depth)), Box::new(RegexMatch::new(pattern.clone(), config.search_full_path)), + Box::new(Extensions::new(config.extensions.clone())), ]; let result = filters @@ -398,17 +398,6 @@ fn spawn_senders( // Check the name first, since it doesn't require metadata let entry_path = entry.path(); - // Filter out unwanted extensions. - if let Some(ref exts_regex) = config.extensions { - if let Some(path_str) = entry_path.file_name() { - if !exts_regex.is_match(&filesystem::osstr_to_bytes(path_str)) { - return ignore::WalkState::Continue; - } - } else { - return ignore::WalkState::Continue; - } - } - // Filter out unwanted file types. if let Some(ref file_types) = config.file_types { if file_types.should_ignore(&entry) { From f5f29194ead08a9a59c7d64100e0f8581edd960d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vuka=C5=A1in=20Stepanovi=C4=87?= Date: Thu, 12 Aug 2021 10:46:06 +0200 Subject: [PATCH 04/10] Add FileTypes filter --- src/filetypes.rs | 52 -------------------------------------- src/filter/filetypes.rs | 56 +++++++++++++++++++++++++++++++++++++++++ src/filter/mod.rs | 2 ++ src/main.rs | 4 +-- src/options.rs | 2 +- src/walk.rs | 32 ++++++++++++----------- 6 files changed, 78 insertions(+), 70 deletions(-) delete mode 100644 src/filetypes.rs create mode 100644 src/filter/filetypes.rs diff --git a/src/filetypes.rs b/src/filetypes.rs deleted file mode 100644 index 2baf0f28f..000000000 --- a/src/filetypes.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::filesystem; -use crate::walk; - -/// Whether or not to show -pub struct FileTypes { - pub files: bool, - pub directories: bool, - pub symlinks: bool, - pub sockets: bool, - pub pipes: bool, - pub executables_only: bool, - pub empty_only: bool, -} - -impl Default for FileTypes { - fn default() -> FileTypes { - FileTypes { - files: false, - directories: false, - symlinks: false, - sockets: false, - pipes: false, - executables_only: false, - empty_only: false, - } - } -} - -impl FileTypes { - pub fn should_ignore(&self, entry: &walk::DirEntry) -> bool { - if let Some(ref entry_type) = entry.file_type() { - (!self.files && entry_type.is_file()) - || (!self.directories && entry_type.is_dir()) - || (!self.symlinks && entry_type.is_symlink()) - || (!self.sockets && filesystem::is_socket(*entry_type)) - || (!self.pipes && filesystem::is_pipe(*entry_type)) - || (self.executables_only - && !entry - .metadata() - .map(|m| filesystem::is_executable(&m)) - .unwrap_or(false)) - || (self.empty_only && !filesystem::is_empty(&entry)) - || !(entry_type.is_file() - || entry_type.is_dir() - || entry_type.is_symlink() - || filesystem::is_socket(*entry_type) - || filesystem::is_pipe(*entry_type)) - } else { - true - } - } -} diff --git a/src/filter/filetypes.rs b/src/filter/filetypes.rs new file mode 100644 index 000000000..38b26caa3 --- /dev/null +++ b/src/filter/filetypes.rs @@ -0,0 +1,56 @@ +use crate::filesystem; +use crate::walk; + +use super::Filter; + +/// Whether or not to show +#[derive(Clone)] +pub struct FileTypes { + pub files: bool, + pub directories: bool, + pub symlinks: bool, + pub sockets: bool, + pub pipes: bool, + pub executables_only: bool, + pub empty_only: bool, +} + +impl Default for FileTypes { + fn default() -> FileTypes { + FileTypes { + files: false, + directories: false, + symlinks: false, + sockets: false, + pipes: false, + executables_only: false, + empty_only: false, + } + } +} + +impl Filter for FileTypes { + fn should_skip(&self, entry: &walk::DirEntry) -> bool { + entry + .file_type() + .map(|ref entry_type| { + (!self.files && entry_type.is_file()) + || (!self.directories && entry_type.is_dir()) + || (!self.symlinks && entry_type.is_symlink()) + || (!self.sockets && filesystem::is_socket(*entry_type)) + || (!self.pipes && filesystem::is_pipe(*entry_type)) + || (self.executables_only + && !entry + .metadata() + .map(|m| filesystem::is_executable(&m)) + .unwrap_or(false)) + || (self.empty_only && !filesystem::is_empty(&entry)) + || !(entry_type.is_file() + || entry_type.is_dir() + || entry_type.is_symlink() + || filesystem::is_socket(*entry_type) + || filesystem::is_pipe(*entry_type)) + }) + .unwrap_or(true) + } +} diff --git a/src/filter/mod.rs b/src/filter/mod.rs index b656e706b..7eec8a129 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -3,6 +3,7 @@ pub use self::time::TimeFilter; pub use self::common::Filter; pub use self::extensions::Extensions; +pub use self::filetypes::FileTypes; pub use self::min_depth::MinDepth; pub use self::regex_match::RegexMatch; @@ -11,6 +12,7 @@ pub use self::owner::OwnerFilter; mod common; mod extensions; +mod filetypes; mod min_depth; mod regex_match; diff --git a/src/main.rs b/src/main.rs index 7acba8898..903e2a47a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,6 @@ mod error; mod exec; mod exit_codes; mod filesystem; -mod filetypes; mod filter; mod options; mod output; @@ -26,10 +25,9 @@ use regex::bytes::{RegexBuilder, RegexSetBuilder}; use crate::error::print_error; use crate::exec::CommandTemplate; use crate::exit_codes::ExitCode; -use crate::filetypes::FileTypes; #[cfg(unix)] use crate::filter::OwnerFilter; -use crate::filter::{SizeFilter, TimeFilter}; +use crate::filter::{FileTypes, SizeFilter, TimeFilter}; use crate::options::Options; use crate::regex_helper::{pattern_has_uppercase_char, pattern_matches_strings_with_leading_dot}; diff --git a/src/options.rs b/src/options.rs index aa9b5ea90..2992d9747 100644 --- a/src/options.rs +++ b/src/options.rs @@ -4,7 +4,7 @@ use lscolors::LsColors; use regex::bytes::RegexSet; use crate::exec::CommandTemplate; -use crate::filetypes::FileTypes; +use crate::filter::FileTypes; #[cfg(unix)] use crate::filter::OwnerFilter; use crate::filter::{SizeFilter, TimeFilter}; diff --git a/src/walk.rs b/src/walk.rs index 5294cf1b0..9de80fe3f 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -381,15 +381,26 @@ fn spawn_senders( } }; - let filters: Vec> = vec![ - Box::new(MinDepth::new(config.min_depth)), - Box::new(RegexMatch::new(pattern.clone(), config.search_full_path)), - Box::new(Extensions::new(config.extensions.clone())), + let filters: Vec>> = vec![ + Some(Box::new(MinDepth::new(config.min_depth))), + Some(Box::new(RegexMatch::new( + pattern.clone(), + config.search_full_path, + ))), + Some(Box::new(Extensions::new(config.extensions.clone()))), + config + .file_types + .clone() + .map(|x| -> Box { Box::new(x) }), ]; - let result = filters - .iter() - .find_map(|x| x.should_skip(&entry).then(|| ignore::WalkState::Continue)); + let result = filters.iter().find_map(|filter_opt| { + filter_opt + .as_ref() + .map(|filter| filter.should_skip(&entry)) + .unwrap_or(false) + .then(|| ignore::WalkState::Continue) + }); if let Some(x) = result { return x; @@ -398,13 +409,6 @@ fn spawn_senders( // Check the name first, since it doesn't require metadata let entry_path = entry.path(); - // Filter out unwanted file types. - if let Some(ref file_types) = config.file_types { - if file_types.should_ignore(&entry) { - return ignore::WalkState::Continue; - } - } - #[cfg(unix)] { if let Some(ref owner_constraint) = config.owner_constraint { From 98eb81b8788e6b42b50536b4742c77d91424c83f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vuka=C5=A1in=20Stepanovi=C4=87?= Date: Thu, 12 Aug 2021 11:29:13 +0200 Subject: [PATCH 05/10] Add SkipRoot filter --- src/filter/mod.rs | 2 ++ src/filter/skip_root.rs | 9 +++++++++ src/walk.rs | 7 ++----- 3 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 src/filter/skip_root.rs diff --git a/src/filter/mod.rs b/src/filter/mod.rs index 7eec8a129..dbb3db31c 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -6,6 +6,7 @@ pub use self::extensions::Extensions; pub use self::filetypes::FileTypes; pub use self::min_depth::MinDepth; pub use self::regex_match::RegexMatch; +pub use self::skip_root::SkipRoot; #[cfg(unix)] pub use self::owner::OwnerFilter; @@ -15,6 +16,7 @@ mod extensions; mod filetypes; mod min_depth; mod regex_match; +mod skip_root; mod size; mod time; diff --git a/src/filter/skip_root.rs b/src/filter/skip_root.rs new file mode 100644 index 000000000..a0854940c --- /dev/null +++ b/src/filter/skip_root.rs @@ -0,0 +1,9 @@ +use super::Filter; + +pub struct SkipRoot; + +impl Filter for SkipRoot { + fn should_skip(&self, entry: &crate::walk::DirEntry) -> bool { + entry.depth().map(|depth| depth == 0).unwrap_or(false) + } +} diff --git a/src/walk.rs b/src/walk.rs index 9de80fe3f..6c03e7346 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -16,7 +16,7 @@ use regex::bytes::Regex; use crate::error::print_error; use crate::exec; use crate::exit_codes::{merge_exitcodes, ExitCode}; -use crate::filter::{Extensions, Filter, MinDepth, RegexMatch}; +use crate::filter::{Extensions, Filter, MinDepth, RegexMatch, SkipRoot}; use crate::options::Options; use crate::output; @@ -345,10 +345,6 @@ fn spawn_senders( } let entry = match entry_o { - Ok(ref e) if e.depth() == 0 => { - // Skip the root directory entry. - return ignore::WalkState::Continue; - } Ok(e) => DirEntry::Normal(e), Err(ignore::Error::WithPath { path, @@ -382,6 +378,7 @@ fn spawn_senders( }; let filters: Vec>> = vec![ + Some(Box::new(SkipRoot)), Some(Box::new(MinDepth::new(config.min_depth))), Some(Box::new(RegexMatch::new( pattern.clone(), From 3d2230ecc962437184b25b2cdc0029ba5bf00503 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vuka=C5=A1in=20Stepanovi=C4=87?= Date: Fri, 13 Aug 2021 07:02:00 +0200 Subject: [PATCH 06/10] Remove bool::then for min supported Rust version --- CHANGELOG.md | 1 + src/walk.rs | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8280b3e4..693795806 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ ## Other - Many documentation updates +- Refactor filtering logic in `spawn_senders`, see #382 (@Asha20) # v8.2.1 diff --git a/src/walk.rs b/src/walk.rs index 6c03e7346..e9277f482 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -392,11 +392,15 @@ fn spawn_senders( ]; let result = filters.iter().find_map(|filter_opt| { - filter_opt + let should_skip = filter_opt .as_ref() .map(|filter| filter.should_skip(&entry)) - .unwrap_or(false) - .then(|| ignore::WalkState::Continue) + .unwrap_or(false); + + match should_skip { + true => Some(ignore::WalkState::Continue), + false => None, + } }); if let Some(x) = result { From 319f82bd4c1d592f79a191e952a1c4b3148bcc0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vuka=C5=A1in=20Stepanovi=C4=87?= Date: Sun, 14 Nov 2021 17:56:15 +0100 Subject: [PATCH 07/10] Simplify code that applies file filters --- src/walk.rs | 36 +++++++++++------------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/src/walk.rs b/src/walk.rs index 91f7fad93..adf853426 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -407,34 +407,20 @@ fn spawn_senders( } }; - let filters: Vec>> = vec![ - Some(Box::new(SkipRoot)), - Some(Box::new(MinDepth::new(config.min_depth))), - Some(Box::new(RegexMatch::new( - pattern.clone(), - config.search_full_path, - ))), - Some(Box::new(Extensions::new(config.extensions.clone()))), - config - .file_types - .clone() - .map(|x| -> Box { Box::new(x) }), + let mut filters: Vec> = vec![ + Box::new(SkipRoot), + Box::new(MinDepth::new(config.min_depth)), + Box::new(RegexMatch::new(pattern.clone(), config.search_full_path)), + Box::new(Extensions::new(config.extensions.clone())), ]; - let result = filters.iter().find_map(|filter_opt| { - let should_skip = filter_opt - .as_ref() - .map(|filter| filter.should_skip(&entry)) - .unwrap_or(false); - - match should_skip { - true => Some(ignore::WalkState::Continue), - false => None, - } - }); + if let Some(file_types) = config.file_types.clone() { + filters.push(Box::new(file_types)); + } - if let Some(x) = result { - return x; + let should_skip = filters.iter().any(|filter| filter.should_skip(&entry)); + if should_skip { + return ignore::WalkState::Continue; } // Check the name first, since it doesn't require metadata From 71f94cc9a0f8902d8e1c3373b800015fef56f68a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vuka=C5=A1in=20Stepanovi=C4=87?= Date: Sun, 14 Nov 2021 20:30:01 +0100 Subject: [PATCH 08/10] Construct file filters only once --- src/filter/common.rs | 2 +- src/filter/filetypes.rs | 4 ++-- src/walk.rs | 32 +++++++++++++++++++------------- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/filter/common.rs b/src/filter/common.rs index 6ebe086b7..5775328ff 100644 --- a/src/filter/common.rs +++ b/src/filter/common.rs @@ -1,6 +1,6 @@ use crate::walk::DirEntry; -pub trait Filter { +pub trait Filter: Send + Sync { /// Whether the entry should be skipped or not. fn should_skip(&self, entry: &DirEntry) -> bool; } diff --git a/src/filter/filetypes.rs b/src/filter/filetypes.rs index 38b26caa3..08cf78081 100644 --- a/src/filter/filetypes.rs +++ b/src/filter/filetypes.rs @@ -42,9 +42,9 @@ impl Filter for FileTypes { || (self.executables_only && !entry .metadata() - .map(|m| filesystem::is_executable(&m)) + .map(filesystem::is_executable) .unwrap_or(false)) - || (self.empty_only && !filesystem::is_empty(&entry)) + || (self.empty_only && !filesystem::is_empty(entry)) || !(entry_type.is_file() || entry_type.is_dir() || entry_type.is_symlink() diff --git a/src/walk.rs b/src/walk.rs index adf853426..54e290051 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -363,11 +363,26 @@ fn spawn_senders( parallel_walker: ignore::WalkParallel, tx: Sender, ) { + let filters = { + let mut filters: Vec> = vec![ + Box::new(SkipRoot), + Box::new(MinDepth::new(config.min_depth)), + Box::new(RegexMatch::new(pattern, config.search_full_path)), + Box::new(Extensions::new(config.extensions.clone())), + ]; + + if let Some(file_types) = config.file_types.clone() { + filters.push(Box::new(file_types)); + } + + Arc::new(filters) + }; + parallel_walker.run(|| { let config = Arc::clone(config); - let pattern = Arc::clone(&pattern); let tx_thread = tx.clone(); let wants_to_quit = Arc::clone(wants_to_quit); + let filters = Arc::clone(&filters); Box::new(move |entry_o| { if wants_to_quit.load(Ordering::Relaxed) { @@ -407,18 +422,9 @@ fn spawn_senders( } }; - let mut filters: Vec> = vec![ - Box::new(SkipRoot), - Box::new(MinDepth::new(config.min_depth)), - Box::new(RegexMatch::new(pattern.clone(), config.search_full_path)), - Box::new(Extensions::new(config.extensions.clone())), - ]; - - if let Some(file_types) = config.file_types.clone() { - filters.push(Box::new(file_types)); - } - - let should_skip = filters.iter().any(|filter| filter.should_skip(&entry)); + let should_skip = filters + .iter() + .any(|filter| filter.should_skip(&entry)); if should_skip { return ignore::WalkState::Continue; } From f37b417c74d7848dc776977ffae5f19fc9522da9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vuka=C5=A1in=20Stepanovi=C4=87?= Date: Sun, 14 Nov 2021 20:44:06 +0100 Subject: [PATCH 09/10] Pass by reference in Extensions file filter --- src/filter/extensions.rs | 10 +++++----- src/walk.rs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/filter/extensions.rs b/src/filter/extensions.rs index 07678ca42..15094731a 100644 --- a/src/filter/extensions.rs +++ b/src/filter/extensions.rs @@ -4,17 +4,17 @@ use crate::filesystem; use super::common::Filter; -pub struct Extensions { - extensions: Option, +pub struct Extensions<'a> { + extensions: Option<&'a RegexSet>, } -impl Extensions { - pub fn new(extensions: Option) -> Self { +impl<'a> Extensions<'a> { + pub fn new(extensions: Option<&'a RegexSet>) -> Self { Self { extensions } } } -impl Filter for Extensions { +impl Filter for Extensions<'_> { fn should_skip(&self, entry: &crate::walk::DirEntry) -> bool { self.extensions .as_ref() diff --git a/src/walk.rs b/src/walk.rs index 54e290051..2882903ff 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -368,7 +368,7 @@ fn spawn_senders( Box::new(SkipRoot), Box::new(MinDepth::new(config.min_depth)), Box::new(RegexMatch::new(pattern, config.search_full_path)), - Box::new(Extensions::new(config.extensions.clone())), + Box::new(Extensions::new(config.extensions.as_ref())), ]; if let Some(file_types) = config.file_types.clone() { From 4d530d1b96a3f1b23c73d986222c560fcc5bddf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vuka=C5=A1in=20Stepanovi=C4=87?= Date: Sun, 14 Nov 2021 21:12:26 +0100 Subject: [PATCH 10/10] Switch file filter dynamic dispatch to enum --- src/filter/common.rs | 22 ++++++++++++++++++++++ src/filter/mod.rs | 3 ++- src/walk.rs | 18 ++++++++---------- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/filter/common.rs b/src/filter/common.rs index 5775328ff..2895aafc6 100644 --- a/src/filter/common.rs +++ b/src/filter/common.rs @@ -1,6 +1,28 @@ use crate::walk::DirEntry; +use super::{Extensions, FileTypes, MinDepth, RegexMatch, SkipRoot}; + pub trait Filter: Send + Sync { /// Whether the entry should be skipped or not. fn should_skip(&self, entry: &DirEntry) -> bool; } + +pub enum FilterKind<'a> { + SkipRoot(SkipRoot), + MinDepth(MinDepth), + RegexMatch(RegexMatch), + Extensions(Extensions<'a>), + FileTypes(FileTypes), +} + +impl<'a> FilterKind<'a> { + pub fn should_skip(&self, entry: &DirEntry) -> bool { + match self { + FilterKind::SkipRoot(f) => f.should_skip(entry), + FilterKind::MinDepth(f) => f.should_skip(entry), + FilterKind::RegexMatch(f) => f.should_skip(entry), + FilterKind::Extensions(f) => f.should_skip(entry), + FilterKind::FileTypes(f) => f.should_skip(entry), + } + } +} diff --git a/src/filter/mod.rs b/src/filter/mod.rs index dbb3db31c..a7950adc9 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -1,7 +1,8 @@ pub use self::size::SizeFilter; pub use self::time::TimeFilter; -pub use self::common::Filter; +pub(super) use self::common::Filter; +pub use self::common::FilterKind; pub use self::extensions::Extensions; pub use self::filetypes::FileTypes; pub use self::min_depth::MinDepth; diff --git a/src/walk.rs b/src/walk.rs index 2882903ff..a5001fffc 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -18,7 +18,7 @@ use crate::config::Config; use crate::error::print_error; use crate::exec; use crate::exit_codes::{merge_exitcodes, ExitCode}; -use crate::filter::{Extensions, Filter, MinDepth, RegexMatch, SkipRoot}; +use crate::filter::{Extensions, FilterKind, MinDepth, RegexMatch, SkipRoot}; use crate::output; /// The receiver thread can either be buffering results or directly streaming to the console. @@ -364,15 +364,15 @@ fn spawn_senders( tx: Sender, ) { let filters = { - let mut filters: Vec> = vec![ - Box::new(SkipRoot), - Box::new(MinDepth::new(config.min_depth)), - Box::new(RegexMatch::new(pattern, config.search_full_path)), - Box::new(Extensions::new(config.extensions.as_ref())), + let mut filters: Vec = vec![ + FilterKind::SkipRoot(SkipRoot), + FilterKind::MinDepth(MinDepth::new(config.min_depth)), + FilterKind::RegexMatch(RegexMatch::new(pattern, config.search_full_path)), + FilterKind::Extensions(Extensions::new(config.extensions.as_ref())), ]; if let Some(file_types) = config.file_types.clone() { - filters.push(Box::new(file_types)); + filters.push(FilterKind::FileTypes(file_types)); } Arc::new(filters) @@ -422,9 +422,7 @@ fn spawn_senders( } }; - let should_skip = filters - .iter() - .any(|filter| filter.should_skip(&entry)); + let should_skip = filters.iter().any(|filter| filter.should_skip(&entry)); if should_skip { return ignore::WalkState::Continue; }