diff --git a/src/main.rs b/src/main.rs index 758f374..20e6862 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,7 @@ use config::Config; use glob::Pattern; use indicatif::{ProgressBar, ProgressStyle}; use log::{debug, error, info}; +use rayon::prelude::*; use sanitizer::{clean_filename, is_excluded, is_safe_rename, Sequence}; use std::fs; use std::io::IsTerminal; @@ -31,6 +32,9 @@ const DEFAULT_EXCLUDES: &[&str] = &[ "__pycache__/**", ]; +// Schwellwert für parallele Verarbeitung (bei weniger Dateien lohnt sich der Overhead nicht) +const PARALLEL_THRESHOLD: usize = 100; + /// Repräsentiert eine geplante Umbenennungsoperation #[derive(Debug)] struct RenameOperation { @@ -161,39 +165,45 @@ fn main() -> Result<()> { None }; - // Berechne Umbenennungen - // Hinweis: Die Reihenfolge (tiefste zuerst) muss erhalten bleiben, - // damit Parent-Verzeichnisse nicht vor ihren Kindern umbenannt werden. - let rename_ops: Vec = entries - .iter() - .filter_map(|entry| { - let old_path = entry.path(); + // Berechne Umbenennungen (parallel bei vielen Dateien, sequentiell bei wenigen) + // Hinweis: rayon's par_iter() auf indexierten Collections bewahrt die Reihenfolge, + // sodass die tiefenbasierte Sortierung erhalten bleibt. + let map_entry = |entry: &walkdir::DirEntry| -> Option { + let old_path = entry.path(); - // Ebenentiefe 0 -> überspringen - if entry.depth() == 0 && entry.file_type().is_dir() && !args.modify_root { - return None; + // Ebenentiefe 0 -> überspringen + if entry.depth() == 0 && entry.file_type().is_dir() && !args.modify_root { + return None; + } + + // Special Files (Symlinks, Sockets, etc.) nur mit --special + let file_type = entry.file_type(); + if !args.special && (!file_type.is_file() && !file_type.is_dir()) { + if args.verbose && file_type.is_symlink() { + debug!( + "Überspringe Symlink: {} (nutze --special um Symlink-Namen zu bereinigen)", + old_path.display() + ); } + return None; + } - // Special Files (Symlinks, Sockets, etc.) nur mit --special - let file_type = entry.file_type(); - if !args.special && (!file_type.is_file() && !file_type.is_dir()) { - if args.verbose && file_type.is_symlink() { - debug!("Überspringe Symlink: {} (nutze --special um Symlink-Namen zu bereinigen)", old_path.display()); - } - return None; - } + // Dateiname ermitteln und bereinigen + let filename = old_path.file_name()?; + let new_name = clean_filename(filename, &config, &sequence, false)?; + let new_path = old_path.with_file_name(&new_name); - // Dateiname ermitteln und bereinigen - let filename = old_path.file_name()?; - let new_name = clean_filename(filename, &config, &sequence, false)?; - let new_path = old_path.with_file_name(&new_name); - - Some(RenameOperation { - old_path: old_path.to_path_buf(), - new_path, - }) + Some(RenameOperation { + old_path: old_path.to_path_buf(), + new_path, }) - .collect(); + }; + + let rename_ops: Vec = if entries.len() >= PARALLEL_THRESHOLD { + entries.par_iter().filter_map(map_entry).collect() + } else { + entries.iter().filter_map(map_entry).collect() + }; // Statistiken let total_processed = entries.len();