diff --git a/Cargo.lock b/Cargo.lock index 00dde8cb..2d76c332 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,12 +26,6 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - [[package]] name = "bitflags" version = "1.3.2" @@ -94,7 +88,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -106,73 +100,6 @@ dependencies = [ "os_str_bytes", ] -[[package]] -name = "crossbeam" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" -dependencies = [ - "cfg-if", - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" -dependencies = [ - "cfg-if", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" -dependencies = [ - "autocfg", - "cfg-if", - "crossbeam-utils", - "memoffset", - "scopeguard", -] - -[[package]] -name = "crossbeam-queue" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" -dependencies = [ - "cfg-if", -] - [[package]] name = "erdtree" version = "1.6.0" @@ -180,7 +107,6 @@ dependencies = [ "ansi_term", "clap", "clap_complete", - "crossbeam", "filesize", "ignore", "indextree", @@ -189,6 +115,7 @@ dependencies = [ "once_cell", "strip-ansi-escapes", "tempfile", + "thiserror", ] [[package]] @@ -365,15 +292,6 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" -[[package]] -name = "memoffset" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" -dependencies = [ - "autocfg", -] - [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -411,7 +329,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "version_check", ] @@ -493,12 +411,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - [[package]] name = "serde" version = "1.0.156" @@ -531,6 +443,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aad1363ed6d37b84299588d62d3a7d95b5a5c2d9aad5c85609fda12afaa1f40" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "tempfile" version = "3.4.0" @@ -553,6 +476,26 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "thiserror" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.10", +] + [[package]] name = "thread_local" version = "1.1.7" diff --git a/Cargo.toml b/Cargo.toml index 703de60a..d142adb4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ keywords = ["tree", "commandline", "command-line", "du", "disk-usage"] exclude = ["assets/*"] readme = "README.md" license = "MIT" -rust-version = "1.65" +rust-version = "1.67.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -26,12 +26,12 @@ path = "src/main.rs" ansi_term = "0.12.1" clap = { version = "4.1.1", features = ["derive"] } clap_complete = "4.1.1" -crossbeam = "0.8.2" filesize = "0.2.0" ignore = "0.4.2" indextree = "4.6.0" lscolors = { version = "0.13.0", features = ["ansi_term"] } once_cell = "1.17.0" +thiserror = "1.0.40" [dev-dependencies] indoc = "2.0.0" diff --git a/src/fs/inode.rs b/src/fs/inode.rs index 1acb43cf..eb56dd7c 100644 --- a/src/fs/inode.rs +++ b/src/fs/inode.rs @@ -1,9 +1,4 @@ -use std::{ - convert::TryFrom, - error::Error as StdError, - fmt::{self, Display}, - fs::Metadata, -}; +use std::{convert::TryFrom, fs::Metadata}; /// Represents a file's underlying inode. #[derive(Debug)] @@ -15,27 +10,20 @@ pub struct Inode { impl Inode { /// Initializer for an inode given all the properties that make it unique. - pub fn new(ino: u64, dev: u64, nlink: u64) -> Self { + pub const fn new(ino: u64, dev: u64, nlink: u64) -> Self { Self { ino, dev, nlink } } /// Returns a tuple fields of the [Inode] that mark is unique. - pub fn properties(&self) -> (u64, u64) { + pub const fn properties(&self) -> (u64, u64) { (self.ino, self.dev) } } -#[derive(Debug)] +#[derive(Debug, thiserror::Error)] +#[error("Insufficient information to compute inode")] pub struct Error; -impl Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Insufficient information to compute inode") - } -} - -impl StdError for Error {} - impl TryFrom for Inode { type Error = Error; diff --git a/src/icons.rs b/src/icons.rs index c74608a8..5fc2ee1f 100644 --- a/src/icons.rs +++ b/src/icons.rs @@ -293,9 +293,9 @@ pub fn icon_from_ext(ext: &OsStr) -> Option<&str> { /// Attempts to return an icon based on file type. pub fn icon_from_file_type(ft: &FileType) -> Option<&str> { if ft.is_dir() { - return FILE_TYPE_ICON_MAP.get("dir").map(|i| *i); + return FILE_TYPE_ICON_MAP.get("dir").copied(); } else if ft.is_symlink() { - return FILE_TYPE_ICON_MAP.get("symlink").map(|i| *i); + return FILE_TYPE_ICON_MAP.get("symlink").copied(); } None @@ -303,7 +303,7 @@ pub fn icon_from_file_type(ft: &FileType) -> Option<&str> { /// Attempts to get the icon associated with the special file kind. pub fn icon_from_file_name(name: &OsStr) -> Option<&str> { - FILE_NAME_ICON_MAP.get(name).map(|i| *i) + FILE_NAME_ICON_MAP.get(name).copied() } /// Returns the default fallback icon. diff --git a/src/main.rs b/src/main.rs index bf96af1a..6c72325c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,23 @@ +#![warn( + clippy::all, + clippy::correctness, + clippy::suspicious, + clippy::style, + clippy::complexity, + clippy::perf, + clippy::pedantic, + clippy::nursery +)] +#![allow( + clippy::struct_excessive_bools, + clippy::cast_precision_loss, + clippy::items_after_statements, + clippy::similar_names, + clippy::doc_markdown, + clippy::too_many_arguments, + clippy::type_complexity, + clippy::fallible_impl_from +)] use clap::CommandFactory; use render::{ context::Context, diff --git a/src/render/context/config.rs b/src/render/context/config.rs index 03059fdd..5b37ce4e 100644 --- a/src/render/context/config.rs +++ b/src/render/context/config.rs @@ -20,31 +20,29 @@ const XDG_CONFIG_HOME: &str = "XDG_CONFIG_HOME"; /// - `$HOME/.erdtreerc` pub fn read_config_to_string>(path: Option) -> Option { if let Some(p) = path { - return fs::read_to_string(p).ok().map(prepend_arg_prefix); + return fs::read_to_string(p).ok().map(|l| prepend_arg_prefix(&l)); } config_from_config_path() .or_else(config_from_xdg_path) .or_else(config_from_home) - .map(prepend_arg_prefix) + .map(|e| prepend_arg_prefix(&e)) } /// Parses the config `str`, removing comments and preparing it as a format understood by /// [`get_matches_from`]. /// /// [`get_matches_from`]: clap::builder::Command::get_matches_from -pub fn parse_config<'a>(config: &'a str) -> Vec<&'a str> { +pub fn parse<'a>(config: &'a str) -> Vec<&'a str> { config .lines() .filter(|line| { line.trim_start() .chars() - .nth(0) - .map(|ch| ch != '#') - .unwrap_or(true) + .next() + .map_or(true, |ch| ch != '#') }) - .map(str::split_ascii_whitespace) - .flatten() + .flat_map(str::split_ascii_whitespace) .collect::>() } @@ -53,8 +51,7 @@ fn config_from_config_path() -> Option { env::var_os(ERDTREE_CONFIG_PATH) .map(PathBuf::from) .map(fs::read_to_string) - .map(Result::ok) - .flatten() + .and_then(Result::ok) } /// Try to read in config from either one of the following locations: @@ -92,6 +89,6 @@ fn config_from_xdg_path() -> Option { /// [`get_matches_from`]. /// /// [`get_matches_from`]: clap::builder::Command::get_matches_from -fn prepend_arg_prefix(config: String) -> String { +fn prepend_arg_prefix(config: &str) -> String { format!("--\n{config}") } diff --git a/src/render/context/mod.rs b/src/render/context/mod.rs index 7dafa470..915b57ec 100644 --- a/src/render/context/mod.rs +++ b/src/render/context/mod.rs @@ -8,13 +8,8 @@ use clap::{ use ignore::overrides::{Override, OverrideBuilder}; use std::{ convert::From, - error::Error as StdError, ffi::{OsStr, OsString}, - fmt::{self, Display}, - num::NonZeroUsize, path::{Path, PathBuf}, - thread::available_parallelism, - usize, }; /// Operations to load in defaults from configuration file. @@ -119,24 +114,21 @@ impl Context { /// Initializes [Context], optionally reading in the configuration file to override defaults. /// Arguments provided will take precedence over config. pub fn init() -> Result { - let user_args = Context::command().args_override_self(true).get_matches(); + let user_args = Self::command().args_override_self(true).get_matches(); - let no_config = user_args - .get_one("no_config") - .map(bool::clone) - .unwrap_or(false); + let no_config = user_args.get_one("no_config").map_or(false, bool::clone); if no_config { - return Context::from_arg_matches(&user_args).map_err(|e| Error::ArgParse(e)); + return Self::from_arg_matches(&user_args).map_err(Error::ArgParse); } if let Some(ref config) = config::read_config_to_string::<&str>(None) { - let raw_config_args = config::parse_config(config); - let config_args = Context::command().get_matches_from(raw_config_args); + let raw_config_args = config::parse(config); + let config_args = Self::command().get_matches_from(raw_config_args); // If the user did not provide any arguments just read from config. if !user_args.args_present() { - return Context::from_arg_matches(&config_args).map_err(|e| Error::Config(e)); + return Self::from_arg_matches(&config_args).map_err(Error::Config); } // If the user did provide arguments we need to reconcile between config and @@ -152,7 +144,8 @@ impl Context { for id in ids { if id == "Context" { continue; - } else if id == "dir" { + } + if id == "dir" { if let Ok(Some(raw)) = user_args.try_get_raw(id) { let raw_args = raw.map(OsStr::to_owned).collect::>(); @@ -170,15 +163,15 @@ impl Context { _ => Self::pick_args_from(id, &config_args, &mut args), } } else { - Self::pick_args_from(id, &config_args, &mut args) + Self::pick_args_from(id, &config_args, &mut args); } } - let clargs = Context::command().get_matches_from(args); - return Context::from_arg_matches(&clargs).map_err(|e| Error::Config(e)); + let clargs = Self::command().get_matches_from(args); + return Self::from_arg_matches(&clargs).map_err(Error::Config); } - Context::from_arg_matches(&user_args).map_err(|e| Error::ArgParse(e)) + Self::from_arg_matches(&user_args).map_err(Error::ArgParse) } /// Returns reference to the path of the root directory to be traversed. @@ -189,18 +182,18 @@ impl Context { } /// The sort-order used for printing. - pub fn sort(&self) -> SortType { + pub const fn sort(&self) -> SortType { self.sort } /// Getter for `dirs_first` field. - pub fn dirs_first(&self) -> bool { + pub const fn dirs_first(&self) -> bool { self.dirs_first } /// The max depth to print. Note that all directories are fully traversed to compute file /// sizes; this just determines how much to print. - pub fn level(&self) -> Option { + pub const fn level(&self) -> Option { self.level } @@ -220,13 +213,13 @@ impl Context { builder.case_insensitive(true).unwrap(); } - for glob in self.glob.iter() { + for glob in &self.glob { builder.add(glob)?; } // all subsequent patterns are case insensitive builder.case_insensitive(true).unwrap(); - for glob in self.iglob.iter() { + for glob in &self.iglob { builder.add(glob)?; } @@ -236,11 +229,11 @@ impl Context { /// Used to pick either from config or user args when constructing [Context]. fn pick_args_from(id: &str, matches: &ArgMatches, args: &mut Vec) { if let Ok(Some(raw)) = matches.try_get_raw(id) { - let kebap = id.replace("_", "-"); + let kebap = id.replace('_', "-"); let raw_args = raw .map(OsStr::to_owned) - .map(|s| vec![OsString::from(format!("--{}", kebap)), s]) + .map(|s| vec![OsString::from(format!("--{kebap}")), s]) .filter(|pair| pair[1] != "false") .flatten() .filter(|s| s != "true") @@ -251,19 +244,10 @@ impl Context { } } -#[derive(Debug)] +#[derive(Debug, thiserror::Error)] pub enum Error { - ArgParse(ClapError), - Config(ClapError), -} - -impl Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::ArgParse(e) => write!(f, "{e}"), - Self::Config(e) => write!(f, "A configuration file was found but failed to parse: {e}"), - } - } + #[error("{0}")] + ArgParse(#[source] ClapError), + #[error("A configuration file was found but failed to parse: {0}")] + Config(#[source] ClapError), } - -impl StdError for Error {} diff --git a/src/render/context/test.rs b/src/render/context/test.rs index c9817aaf..edc3dafd 100644 --- a/src/render/context/test.rs +++ b/src/render/context/test.rs @@ -23,15 +23,15 @@ fn config() { let icons = context.icons; - assert!(icons, "Failed to propertly read 'icons' from config") + assert!(icons, "Failed to propertly read 'icons' from config"); } fn context_from_config() -> Option { - if let Some(ref config) = config::read_config_to_string(Some(TEST_CONFIG)) { - let raw_config_args = config::parse_config(config); - let config_args = Context::command().get_matches_from(raw_config_args); - Context::from_arg_matches(&config_args).ok() - } else { - None - } + config::read_config_to_string(Some(TEST_CONFIG)) + .as_ref() + .and_then(|config| { + let raw_config_args = config::parse(config); + let config_args = Context::command().get_matches_from(raw_config_args); + Context::from_arg_matches(&config_args).ok() + }) } diff --git a/src/render/disk_usage.rs b/src/render/disk_usage.rs index 5aa3eed4..e95da017 100644 --- a/src/render/disk_usage.rs +++ b/src/render/disk_usage.rs @@ -64,7 +64,7 @@ pub struct FileSize { impl FileSize { /// Initializes a [FileSize]. - pub fn new(bytes: u64, disk_usage: DiskUsage, prefix_kind: PrefixKind, scale: usize) -> Self { + pub const fn new(bytes: u64, disk_usage: DiskUsage, prefix_kind: PrefixKind, scale: usize) -> Self { Self { bytes, disk_usage, @@ -204,7 +204,7 @@ impl FileSize { format!("{:len$}", "", len = Self::empty_string_len(ctx)) } - fn empty_string_len(ctx: &Context) -> usize { + const fn empty_string_len(ctx: &Context) -> usize { // 3 places before the decimal // 1 for the decimal // ctx.scale after the decimal diff --git a/src/render/order.rs b/src/render/order.rs index 5f8bbda1..0131dc0a 100644 --- a/src/render/order.rs +++ b/src/render/order.rs @@ -55,7 +55,7 @@ impl Order { impl SortType { /// Yields function pointer to the appropriate `Node` comparator. - pub fn comparator(&self) -> Option Ordering>> { + pub fn comparator(self) -> Option Ordering>> { match self { Self::Name => Some(Box::new(Self::name_comparator)), Self::Size => Some(Box::new(Self::size_comparator)), @@ -71,22 +71,22 @@ impl SortType { /// Comparator that sorts [Node]s by size smallest to largest. fn size_comparator(a: &Node, b: &Node) -> Ordering { - let a_size = a.file_size().map(|fs| fs.bytes).unwrap_or(0); - let b_size = b.file_size().map(|fs| fs.bytes).unwrap_or(0); + let a_size = a.file_size().map_or(0, |fs| fs.bytes); + let b_size = b.file_size().map_or(0, |fs| fs.bytes); a_size.cmp(&b_size) } /// Comparator that sorts [Node]s by size largest to smallest. fn size_rev_comparator(a: &Node, b: &Node) -> Ordering { - let a_size = a.file_size().map(|fs| fs.bytes).unwrap_or(0); - let b_size = b.file_size().map(|fs| fs.bytes).unwrap_or(0); + let a_size = a.file_size().map_or(0, |fs| fs.bytes); + let b_size = b.file_size().map_or(0, |fs| fs.bytes); b_size.cmp(&a_size) } } impl From<(SortType, bool)> for Order { fn from((sort, dir_first): (SortType, bool)) -> Self { - Order { sort, dir_first } + Self { sort, dir_first } } } diff --git a/src/render/tree/error.rs b/src/render/tree/error.rs index 4f843214..8b926a3b 100644 --- a/src/render/tree/error.rs +++ b/src/render/tree/error.rs @@ -1,45 +1,23 @@ use ignore::Error as IgnoreError; -use std::{ - convert::From, - error::Error as StdError, - fmt::{self, Display, Formatter}, - io::Error as IoError, -}; +use std::io::Error as IoError; /// Errors that may occur while traversing or construction of [`Tree`]. /// /// [`Tree`]: super::Tree -#[derive(Debug)] +#[derive(Debug, thiserror::Error)] pub enum Error { + #[error("{0}")] DirNotFound(String), - ExpectedParent, - InvalidGlobPatterns(IgnoreError), - MissingRoot, - PathCanonicalizationError(IoError), -} -impl Display for Error { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - Error::DirNotFound(e) => write!(f, "{e}"), - Error::ExpectedParent => write!(f, "File expected to have parent"), - Error::InvalidGlobPatterns(e) => write!(f, "Invalid glob patterns: {e}"), - Error::MissingRoot => write!(f, "Failed to compute root node"), - Error::PathCanonicalizationError(e) => write!(f, "{e}"), - } - } -} + #[error("File expected to have parent")] + ExpectedParent, -impl StdError for Error {} + #[error("Invalid glob patterns: {0}")] + InvalidGlobPatterns(#[from] IgnoreError), -impl From for Error { - fn from(value: ignore::Error) -> Self { - Self::InvalidGlobPatterns(value) - } -} + #[error("Failed to compute root node")] + MissingRoot, -impl From for Error { - fn from(value: IoError) -> Self { - Self::PathCanonicalizationError(value) - } + #[error("{0}")] + PathCanonicalization(#[from] IoError), } diff --git a/src/render/tree/mod.rs b/src/render/tree/mod.rs index 13ce0014..189758d1 100644 --- a/src/render/tree/mod.rs +++ b/src/render/tree/mod.rs @@ -1,5 +1,4 @@ use crate::render::{context::Context, disk_usage::FileSize, order::Order}; -use crossbeam::channel::{self, Sender}; use error::Error; use ignore::{WalkBuilder, WalkParallel}; use indextree::{Arena, NodeId}; @@ -10,6 +9,8 @@ use std::{ fmt::{self, Display, Formatter}, fs, path::PathBuf, + result::Result as StdResult, + sync::mpsc::{self, Sender}, thread, }; use visitor::{BranchVisitorBuilder, TraversalState}; @@ -37,16 +38,16 @@ pub struct Tree { ctx: Context, } -pub type TreeResult = Result; +pub type Result = StdResult; impl Tree { /// Constructor for [Tree]. - pub fn new(inner: Arena, root: NodeId, ctx: Context) -> Self { + pub const fn new(inner: Arena, root: NodeId, ctx: Context) -> Self { Self { inner, root, ctx } } /// Initiates file-system traversal and [Tree construction]. - pub fn init(ctx: Context) -> TreeResult { + pub fn init(ctx: Context) -> Result { let (inner, root) = Self::traverse(&ctx)?; Ok(Self::new(inner, root, ctx)) @@ -58,12 +59,12 @@ impl Tree { } /// Grab a reference to [Context]. - fn context(&self) -> &Context { + const fn context(&self) -> &Context { &self.ctx } /// Grabs a reference to `inner`. - fn inner(&self) -> &Arena { + const fn inner(&self) -> &Arena { &self.inner } @@ -71,11 +72,11 @@ impl Tree { /// `WalkParallel`. Any filesystem I/O or related system calls are expected to occur during /// parallel traversal; post-processing post-processing of all directory entries should /// be completely CPU-bound. - fn traverse(ctx: &Context) -> TreeResult<(Arena, NodeId)> { - let (tx, rx) = channel::unbounded::(); + fn traverse(ctx: &Context) -> Result<(Arena, NodeId)> { + let (tx, rx) = mpsc::channel(); thread::scope(|s| { - let res = s.spawn(|| { + let res = s.spawn(move || { let mut tree = Arena::new(); let mut branches: HashMap> = HashMap::new(); let mut inodes = HashSet::new(); @@ -98,10 +99,8 @@ impl Tree { // If a hard-link is already accounted for, skip all subsequent ones. if let Some(inode) = node.inode() { - if inode.nlink > 1 { - if !inodes.insert(inode.properties()) { - continue; - } + if inode.nlink > 1 && !inodes.insert(inode.properties()) { + continue; } } @@ -109,9 +108,10 @@ impl Tree { let node_id = tree.new_node(node); - if let None = branches + if branches .get_mut(&parent) .map(|mut_ref| mut_ref.push(node_id)) + .is_none() { branches.insert(parent, vec![]); } @@ -154,7 +154,7 @@ impl Tree { let mut dir_size = FileSize::new(0, ctx.disk_usage, ctx.prefix, ctx.scale); - for child_id in children.iter() { + for child_id in &children { let index = *child_id; let is_dir = { @@ -167,7 +167,7 @@ impl Tree { } if let Some(file_size) = tree[index].get().file_size() { - dir_size += file_size.bytes + dir_size += file_size.bytes; } } @@ -197,15 +197,13 @@ impl Tree { for node_id in root_id.descendants(tree) { let node = tree[node_id].get(); - if node.is_dir() { - if node_id.children(tree).peekable().peek().is_none() { - to_prune.push(node_id); - } + if node.is_dir() && node_id.children(tree).peekable().peek().is_none() { + to_prune.push(node_id); } } for node_id in to_prune { - node_id.remove_subtree(tree) + node_id.remove_subtree(tree); } } } @@ -213,7 +211,7 @@ impl Tree { impl TryFrom<&Context> for WalkParallel { type Error = Error; - fn try_from(clargs: &Context) -> Result { + fn try_from(clargs: &Context) -> StdResult { let root = fs::canonicalize(clargs.dir())?; fs::metadata(&root).map_err(|e| Error::DirNotFound(format!("{}: {e}", root.display())))?; @@ -251,10 +249,10 @@ impl Display for Tree { node.display_size_right(f, base_prefix, ctx)?; } - writeln!(f, "") + writeln!(f) } - display_node(&root_node, "", ctx, f)?; + display_node(root_node, "", ctx, f)?; let mut prefix_components = vec![""]; @@ -282,7 +280,7 @@ impl Display for Tree { let prefix = current_prefix_components.join(""); if current_node.depth <= level { - display_node(¤t_node, &prefix, ctx, f)?; + display_node(current_node, &prefix, ctx, f)?; } if let Some(next_id) = descendants.peek() { diff --git a/src/render/tree/node.rs b/src/render/tree/node.rs index eebdaa17..2ecd83e7 100644 --- a/src/render/tree/node.rs +++ b/src/render/tree/node.rs @@ -13,7 +13,7 @@ use ignore::DirEntry; use indextree::{Arena, Node as NodeWrapper, NodeId}; use lscolors::Style as LS_Style; use std::{ - borrow::Cow, + borrow::{Cow, ToOwned}, convert::From, ffi::{OsStr, OsString}, fmt::{self, Formatter}, @@ -42,7 +42,7 @@ pub struct Node { impl Node { /// Initializes a new [Node]. - pub fn new( + pub const fn new( depth: usize, file_size: Option, file_name: OsString, @@ -55,8 +55,8 @@ impl Node { ) -> Self { Self { depth, - file_name, file_size, + file_name, file_type, inode, path, @@ -87,11 +87,11 @@ impl Node { /// Returns `true` if node is a directory. pub fn is_dir(&self) -> bool { - self.file_type().map(|ft| ft.is_dir()).unwrap_or(false) + self.file_type().map_or(false, FileType::is_dir) } /// Is the Node a symlink. - pub fn is_symlink(&self) -> bool { + pub const fn is_symlink(&self) -> bool { self.symlink_target.is_some() } @@ -102,11 +102,11 @@ impl Node { /// Returns the file name of the symlink target if [Node] represents a symlink. pub fn symlink_target_file_name(&self) -> Option<&OsStr> { - self.symlink_target_path().and_then(|path| path.file_name()) + self.symlink_target_path().and_then(Path::file_name) } /// Returns reference to underlying [FileType]. - pub fn file_type(&self) -> Option<&FileType> { + pub const fn file_type(&self) -> Option<&FileType> { self.file_type.as_ref() } @@ -121,7 +121,7 @@ impl Node { } /// Gets 'file_size'. - pub fn file_size(&self) -> Option<&FileSize> { + pub const fn file_size(&self) -> Option<&FileSize> { self.file_size.as_ref() } @@ -131,12 +131,12 @@ impl Node { } /// Sets 'style'. - pub fn style(&self) -> &Style { + pub const fn style(&self) -> &Style { &self.style } /// Returns reference to underlying [Inode] if any. - pub fn inode(&self) -> Option<&Inode> { + pub const fn inode(&self) -> Option<&Inode> { self.inode.as_ref() } @@ -209,7 +209,7 @@ impl Node { let icon = if self.show_icon { self.get_icon().unwrap() } else { - "".to_owned() + String::new() }; let icon_padding = if icon.len() > 1 { icon.len() - 1 } else { 0 }; @@ -285,7 +285,7 @@ impl From<(&DirEntry, &Context)> for Node { let file_name = path.file_name().map_or_else( || OsString::from(path.display().to_string()), - |os_str| os_str.to_owned(), + ToOwned::to_owned, ); let metadata = dir_entry.metadata().ok(); @@ -343,19 +343,17 @@ enum SizeLocation { impl SizeLocation { /// Returns a string to use when a node has no filesize, such as empty directories fn default_string(self, ctx: &Context) -> String { - use SizeLocation::*; match self { - Right => "".to_owned(), - Left => FileSize::empty_string(ctx), + Self::Right => String::new(), + Self::Left => FileSize::empty_string(ctx), } } /// Given a [`FileSize`], style it in the expected way for its printing location fn format(self, size: &FileSize) -> String { - use SizeLocation::*; match self { - Right => format!("({})", size.format(false)), - Left => size.format(true), + Self::Right => format!("({})", size.format(false)), + Self::Left => size.format(true), } } } diff --git a/src/render/tree/visitor.rs b/src/render/tree/visitor.rs index e893dbcb..8b135577 100644 --- a/src/render/tree/visitor.rs +++ b/src/render/tree/visitor.rs @@ -1,5 +1,6 @@ +use std::sync::mpsc::Sender; + use super::{Context, Node}; -use crossbeam::channel::Sender; use ignore::{DirEntry, Error as IgnoreError, ParallelVisitor, ParallelVisitorBuilder, WalkState}; pub enum TraversalState { @@ -7,7 +8,7 @@ pub enum TraversalState { Done, } -pub struct BranchVisitor<'a> { +pub struct Branch<'a> { ctx: &'a Context, tx: Sender, } @@ -23,7 +24,7 @@ impl<'a> BranchVisitorBuilder<'a> { } } -impl<'a> BranchVisitor<'a> { +impl<'a> Branch<'a> { pub fn new(ctx: &'a Context, tx: Sender) -> Self { Self { ctx, tx } } @@ -31,11 +32,11 @@ impl<'a> BranchVisitor<'a> { impl From for TraversalState { fn from(node: Node) -> Self { - TraversalState::Ongoing(node) + Self::Ongoing(node) } } -impl ParallelVisitor for BranchVisitor<'_> { +impl ParallelVisitor for Branch<'_> { fn visit(&mut self, entry: Result) -> WalkState { entry .map(|e| TraversalState::from(Node::from((&e, self.ctx)))) @@ -47,7 +48,7 @@ impl ParallelVisitor for BranchVisitor<'_> { impl<'s> ParallelVisitorBuilder<'s> for BranchVisitorBuilder<'s> { fn build(&mut self) -> Box { - let visitor = BranchVisitor::new(self.ctx, self.tx.clone()); + let visitor = Branch::new(self.ctx, self.tx.clone()); Box::new(visitor) } } diff --git a/src/utils.rs b/src/utils.rs index 18c49601..47f88214 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -13,7 +13,7 @@ macro_rules! hash { } /// Ensure every item in a `Vec` is unique. -pub fn uniq(items: Vec) -> Vec +pub fn uniq(items: Vec) -> Vec where T: Eq + Hash + ToOwned, ::Owned: Hash + Eq,