From 782d2458dc4ad4336e1407e1f107e43e39b0b991 Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Mon, 10 Aug 2026 14:57:16 +0800 Subject: chore: enforce pedantic clippy lints and fix warnings --- .../src/main.rs | 2 +- mingling/src/example_docs.rs | 2 +- mingling/src/lib.rs | 2 ++ mingling/src/parser/args.rs | 14 ++++---- mingling/src/parser/picker.rs | 12 +++---- mingling/src/parser/picker/bools.rs | 42 +++++++++++----------- mingling/src/parser/picker/builtin.rs | 21 +++++------ mingling/src/parser/picker/path.rs | 15 ++++---- mingling/src/parser/picker/path/rule.rs | 24 ++++++------- mingling/src/parser/test.rs | 4 +-- mingling/src/res/dirs/current_dir.rs | 9 +++-- mingling/src/res/dirs/current_exe.rs | 8 +++-- mingling/src/res/dirs/home_dir.rs | 4 ++- mingling/src/res/dirs/temp_dir.rs | 1 + mingling/src/setups/basic.rs | 6 ++-- mingling/src/setups/repl_basic.rs | 19 +++++----- 16 files changed, 94 insertions(+), 91 deletions(-) diff --git a/examples/example-combine-pathf-dispatch-tree/src/main.rs b/examples/example-combine-pathf-dispatch-tree/src/main.rs index 7407d32..75888ee 100644 --- a/examples/example-combine-pathf-dispatch-tree/src/main.rs +++ b/examples/example-combine-pathf-dispatch-tree/src/main.rs @@ -1,4 +1,4 @@ -//! Example: Combining pathf + dispatch_tree +//! Example: Combining `pathf` + `dispatch_tree` //! //! > This example demonstrates how to use `pathf` and `dispatch_tree` together. //! > Types are defined in a submodule (`sub`), and `gen_program!()` resolves diff --git a/mingling/src/example_docs.rs b/mingling/src/example_docs.rs index e61551b..6732050 100644 --- a/mingling/src/example_docs.rs +++ b/mingling/src/example_docs.rs @@ -703,7 +703,7 @@ pub mod example_basic {} /// gen_program!(); /// ``` pub mod example_clap_binding {} -/// Example: Combining pathf + dispatch_tree +/// Example: Combining `pathf` + `dispatch_tree` /// /// > This example demonstrates how to use `pathf` and `dispatch_tree` together. /// > Types are defined in a submodule (`sub`), and `gen_program!()` resolves diff --git a/mingling/src/lib.rs b/mingling/src/lib.rs index 470c64b..06cb21b 100644 --- a/mingling/src/lib.rs +++ b/mingling/src/lib.rs @@ -3,6 +3,8 @@ html_favicon_url = "https://github.com/mingling-rs/mingling/raw/main/docs/res/favicon_small.png" )] #![deny(missing_docs)] +#![deny(clippy::pedantic)] +#![deny(clippy::nursery)] #![doc = include_str!("docs/lib.md")] #![cfg_attr(docsrs, feature(doc_cfg))] diff --git a/mingling/src/parser/args.rs b/mingling/src/parser/args.rs index 23275c2..403f88c 100644 --- a/mingling/src/parser/args.rs +++ b/mingling/src/parser/args.rs @@ -10,7 +10,7 @@ pub struct Argument { impl From> for Argument { fn from(vec: Vec<&str>) -> Self { - Argument { + Self { vec: vec .into_iter() .map(std::string::ToString::to_string) @@ -21,7 +21,7 @@ impl From> for Argument { impl From<&'static str> for Argument { fn from(s: &'static str) -> Self { - Argument { + Self { vec: vec![s.to_string()], } } @@ -29,7 +29,7 @@ impl From<&'static str> for Argument { impl From<&'static [&'static str]> for Argument { fn from(slice: &'static [&'static str]) -> Self { - Argument { + Self { vec: slice.iter().map(|&s| s.to_string()).collect(), } } @@ -37,7 +37,7 @@ impl From<&'static [&'static str]> for Argument { impl From<[&'static str; N]> for Argument { fn from(slice: [&'static str; N]) -> Self { - Argument { + Self { vec: slice.iter().map(|&s| s.to_string()).collect(), } } @@ -45,7 +45,7 @@ impl From<[&'static str; N]> for Argument { impl From<&'static [&'static str; N]> for Argument { fn from(slice: &'static [&'static str; N]) -> Self { - Argument { + Self { vec: slice.iter().map(|&s| s.to_string()).collect(), } } @@ -53,7 +53,7 @@ impl From<&'static [&'static str; N]> for Argument { impl From> for Argument { fn from(vec: Vec) -> Self { - Argument { vec } + Self { vec } } } @@ -159,7 +159,7 @@ impl Argument { } /// Dump all remaining arguments - pub fn dump_remains(&mut self) -> Vec { + pub const fn dump_remains(&mut self) -> Vec { let new = Vec::new(); replace(&mut self.vec, new) } diff --git a/mingling/src/parser/picker.rs b/mingling/src/parser/picker.rs index ca4561c..f199f5d 100644 --- a/mingling/src/parser/picker.rs +++ b/mingling/src/parser/picker.rs @@ -22,8 +22,8 @@ pub struct Picker { impl Picker { /// Creates a new `Picker` from a value that can be converted into `Argument`. - pub fn new(args: impl Into) -> Picker { - Picker { args: args.into() } + pub fn new(args: impl Into) -> Self { + Self { args: args.into() } } /// Extracts a value for the given flag and returns a `Pick1` builder (no route). @@ -50,7 +50,7 @@ impl Picker { where TNext: Pickable, { - let v = TNext::pick(&mut self.args, val.into()).unwrap_or(or.into()); + let v = TNext::pick(&mut self.args, val.into()).unwrap_or_else(|| or.into()); Pick1 { args: self.args, val_1: v, @@ -118,7 +118,7 @@ impl Picker { impl> From for Picker { fn from(value: T) -> Self { - Picker::new(value) + Self::new(value) } } @@ -342,7 +342,7 @@ macro_rules! impl_pick_next { where TNext: Pickable, { - let v = TNext::pick(&mut self.args, val.into()).unwrap_or(or.into()); + let v = TNext::pick(&mut self.args, val.into()).unwrap_or_else(|| or.into()); $next { args: self.args, $($val: self.$val,)+ @@ -647,7 +647,7 @@ macro_rules! impl_pick_with_route_next { where TNext: Pickable, { - let v = TNext::pick(&mut self.args, val.into()).unwrap_or(or.into()); + let v = TNext::pick(&mut self.args, val.into()).unwrap_or_else(|| or.into()); $next { args: self.args, $($val: self.$val,)+ diff --git a/mingling/src/parser/picker/bools.rs b/mingling/src/parser/picker/bools.rs index 0525c52..6f866ab 100644 --- a/mingling/src/parser/picker/bools.rs +++ b/mingling/src/parser/picker/bools.rs @@ -16,7 +16,7 @@ pub enum Yes { impl From for Yes { fn from(b: bool) -> Self { - if b { Yes::Yes } else { Yes::No } + if b { Self::Yes } else { Self::No } } } @@ -36,26 +36,26 @@ impl std::ops::Deref for Yes { static TRUE: bool = true; static FALSE: bool = false; match self { - Yes::Yes => &TRUE, - Yes::No => &FALSE, + Self::Yes => &TRUE, + Self::No => &FALSE, } } } impl Yes { #[must_use] - pub fn is_yes(&self) -> bool { - matches!(self, Yes::Yes) + pub const fn is_yes(&self) -> bool { + matches!(self, Self::Yes) } #[must_use] - pub fn is_no(&self) -> bool { - matches!(self, Yes::No) + pub const fn is_no(&self) -> bool { + matches!(self, Self::No) } } impl Pickable for Yes { - type Output = Yes; + type Output = Self; fn pick(args: &mut crate::parser::Argument, flag: mingling_core::Flag) -> Option { let value = pick_bool(args, flag, &["y", "yes"]); @@ -79,7 +79,7 @@ pub enum True { impl From for True { fn from(b: bool) -> Self { - if b { True::True } else { True::False } + if b { Self::True } else { Self::False } } } @@ -99,26 +99,26 @@ impl std::ops::Deref for True { static TRUE: bool = true; static FALSE: bool = false; match self { - True::True => &TRUE, - True::False => &FALSE, + Self::True => &TRUE, + Self::False => &FALSE, } } } impl True { #[must_use] - pub fn is_true(&self) -> bool { - matches!(self, True::True) + pub const fn is_true(&self) -> bool { + matches!(self, Self::True) } #[must_use] - pub fn is_false(&self) -> bool { - matches!(self, True::False) + pub const fn is_false(&self) -> bool { + matches!(self, Self::False) } } impl Pickable for True { - type Output = True; + type Output = Self; fn pick(args: &mut crate::parser::Argument, flag: mingling_core::Flag) -> Option { let value = pick_bool(args, flag, &["true", "t"]); @@ -132,11 +132,11 @@ fn pick_bool( positive: &[&str], ) -> bool { let content = args.pick_argument(flag); - match content { - Some(content) => { + content.map_or_else( + || false, + |content| { let s = content.as_str(); positive.contains(&s) - } - None => false, - } + }, + ) } diff --git a/mingling/src/parser/picker/builtin.rs b/mingling/src/parser/picker/builtin.rs index 6194955..2a5d569 100644 --- a/mingling/src/parser/picker/builtin.rs +++ b/mingling/src/parser/picker/builtin.rs @@ -3,7 +3,7 @@ use size::Size; use crate::parser::{Argument, Pickable}; impl Pickable for String { - type Output = String; + type Output = Self; fn pick(args: &mut crate::parser::Argument, flag: mingling_core::Flag) -> Option { args.pick_argument(flag) @@ -11,7 +11,7 @@ impl Pickable for String { } impl Pickable for Vec { - type Output = Vec; + type Output = Self; fn pick(args: &mut crate::parser::Argument, flag: mingling_core::Flag) -> Option { Some(args.pick_arguments(flag)) @@ -53,7 +53,7 @@ macro_rules! impl_pickable_for_number { impl_pickable_for_number!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, f32, f64); impl Pickable for bool { - type Output = bool; + type Output = Self; fn pick(args: &mut crate::parser::Argument, flag: mingling_core::Flag) -> Option { Some(args.pick_flag(flag)) @@ -62,25 +62,22 @@ impl Pickable for bool { /// Special: parses a size string (e.g. "10MB") into a `usize` representing the number of bytes. impl Pickable for usize { - type Output = usize; + type Output = Self; fn pick(args: &mut crate::parser::Argument, flag: mingling_core::Flag) -> Option { let picked = args.pick_argument(flag)?; let size_parse = Size::from_str(picked.as_str()); - match size_parse { - Ok(size) => usize::try_from(size.bytes()).ok(), - Err(_) => None, - } + size_parse.map_or(None, |size| Self::try_from(size.bytes()).ok()) } } /// Special: parses a comma-separated list of size strings (e.g. "10MB,20KB") into a `Vec`. impl Pickable for Vec { - type Output = Vec; + type Output = Self; fn pick(args: &mut crate::parser::Argument, flag: mingling_core::Flag) -> Option { let picked_vec = args.pick_arguments(flag); - let mut result = Vec::new(); + let mut result = Self::new(); for picked in picked_vec { let size_parse = Size::from_str(picked.as_str()); match size_parse { @@ -94,7 +91,7 @@ impl Pickable for Vec { /// Special: dumps the remaining arguments into an `Argument` struct. impl Pickable for Argument { - type Output = Argument; + type Output = Self; fn pick( args: &mut crate::parser::Argument, @@ -106,7 +103,7 @@ impl Pickable for Argument { /// Special: parses a single value of type `T` using the `Pickable` implementation for `T`, and wraps it in an `Option`. impl + Default> Pickable for Option { - type Output = Option; + type Output = Self; fn pick(args: &mut Argument, flag: mingling_core::Flag) -> Option { let r = T::pick(args, flag); diff --git a/mingling/src/parser/picker/path.rs b/mingling/src/parser/picker/path.rs index 961542e..4722088 100644 --- a/mingling/src/parser/picker/path.rs +++ b/mingling/src/parser/picker/path.rs @@ -6,22 +6,21 @@ mod rule; pub use rule::*; impl Pickable for Vec { - type Output = Vec; + type Output = Self; fn pick(args: &mut crate::parser::Argument, flag: mingling_core::Flag) -> Option { let raw: Vec = args.pick_arguments(flag); - let paths: Vec = raw.into_iter().map(PathBuf::from).collect(); + let paths = raw.into_iter().map(PathBuf::from).collect(); Some(paths) } } impl Pickable for PathBuf { - type Output = PathBuf; + type Output = Self; fn pick(args: &mut crate::parser::Argument, flag: mingling_core::Flag) -> Option { let raw: String = args.pick_argument(flag)?; - let path: PathBuf = PathBuf::from(raw); - Some(path) + Some(Self::from(raw)) } } @@ -86,8 +85,8 @@ pub trait PathChecker { } } -impl>> PathsChecker for T where T: Into> {} -impl> PathChecker for T where T: Into {} +impl>> PathsChecker for T {} +impl> PathChecker for T {} fn check_paths(path: impl Into>, rule: &PathCheckRule) -> Result<(), ()> { let paths = path.into(); @@ -140,6 +139,6 @@ fn check_type(path: &Path, rule: &PathCheckRule) -> Result<(), ()> { Err(()) } -fn bool_to_result(b: bool) -> Result<(), ()> { +const fn bool_to_result(b: bool) -> Result<(), ()> { if b { Ok(()) } else { Err(()) } } diff --git a/mingling/src/parser/picker/path/rule.rs b/mingling/src/parser/picker/path/rule.rs index bf5cab3..52bf65a 100644 --- a/mingling/src/parser/picker/path/rule.rs +++ b/mingling/src/parser/picker/path/rule.rs @@ -26,7 +26,7 @@ pub struct PathTypeCheck { impl PathCheckRule { /// Creates a new `PathCheckRule` with default values #[must_use] - pub fn new() -> Self { + pub const fn new() -> Self { Self { exist_check: None, type_check: None, @@ -35,7 +35,7 @@ impl PathCheckRule { /// Allows the path to be a file #[must_use] - pub fn allow_file(self) -> Self { + pub const fn allow_file(self) -> Self { match self.type_check { Some(type_check) => Self { type_check: Some(PathTypeCheck { @@ -58,7 +58,7 @@ impl PathCheckRule { /// Allows the path to be a directory #[must_use] - pub fn allow_dir(self) -> Self { + pub const fn allow_dir(self) -> Self { match self.type_check { Some(type_check) => Self { type_check: Some(PathTypeCheck { @@ -81,7 +81,7 @@ impl PathCheckRule { /// Allows the path to be a symlink #[must_use] - pub fn allow_symlink(self) -> Self { + pub const fn allow_symlink(self) -> Self { match self.type_check { Some(type_check) => Self { type_check: Some(PathTypeCheck { @@ -104,7 +104,7 @@ impl PathCheckRule { /// Denies the path from being a file #[must_use] - pub fn deny_file(self) -> Self { + pub const fn deny_file(self) -> Self { match self.type_check { Some(type_check) => Self { type_check: Some(PathTypeCheck { @@ -127,7 +127,7 @@ impl PathCheckRule { /// Denies the path from being a directory #[must_use] - pub fn deny_dir(self) -> Self { + pub const fn deny_dir(self) -> Self { match self.type_check { Some(type_check) => Self { type_check: Some(PathTypeCheck { @@ -150,7 +150,7 @@ impl PathCheckRule { /// Denies the path from being a symlink #[must_use] - pub fn deny_symlink(self) -> Self { + pub const fn deny_symlink(self) -> Self { match self.type_check { Some(type_check) => Self { type_check: Some(PathTypeCheck { @@ -173,7 +173,7 @@ impl PathCheckRule { /// Requires the path to be a file (overrides type checks) #[must_use] - pub fn must_file(self) -> Self { + pub const fn must_file(self) -> Self { Self { type_check: Some(PathTypeCheck { allow_file: true, @@ -186,7 +186,7 @@ impl PathCheckRule { /// Requires the path to be a directory (overrides type checks) #[must_use] - pub fn must_dir(self) -> Self { + pub const fn must_dir(self) -> Self { Self { type_check: Some(PathTypeCheck { allow_file: false, @@ -199,7 +199,7 @@ impl PathCheckRule { /// Requires the path to be a symlink (overrides type checks) #[must_use] - pub fn must_symlink(self) -> Self { + pub const fn must_symlink(self) -> Self { Self { type_check: Some(PathTypeCheck { allow_file: false, @@ -212,7 +212,7 @@ impl PathCheckRule { /// Requires the path to exist #[must_use] - pub fn must_exist(self) -> Self { + pub const fn must_exist(self) -> Self { Self { exist_check: Some(PathExistCheck::Exists), ..self @@ -221,7 +221,7 @@ impl PathCheckRule { /// Requires the path to not exist #[must_use] - pub fn must_not_exist(self) -> Self { + pub const fn must_not_exist(self) -> Self { Self { exist_check: Some(PathExistCheck::NotExists), ..self diff --git a/mingling/src/parser/test.rs b/mingling/src/parser/test.rs index 29a074d..569a091 100644 --- a/mingling/src/parser/test.rs +++ b/mingling/src/parser/test.rs @@ -536,7 +536,7 @@ fn test_picker_pick_or_route_missing() { fn test_picker_require_present() { let result: Option = Picker::new(vec!["--name", "Alice"]) .require::("--name") - .map(|p| p.unpack()); + .map(super::picker::Pick1::unpack); assert_eq!(result, Some("Alice".to_string())); } @@ -705,7 +705,7 @@ fn test_pick_with_route_after_or_route_preserves_existing_route() { #[test] fn test_picker_operate_args_filter() { let result: String = Picker::new(vec!["--name", "Alice", "--verbose"]) - .operate_args(|args| args.strip_all_flags()) + .operate_args(Argument::strip_all_flags) .pick_or("--name", "fallback_name") .unpack(); // After stripping flags, "--name" and "--verbose" are gone, "Alice" is a positional arg. diff --git a/mingling/src/res/dirs/current_dir.rs b/mingling/src/res/dirs/current_dir.rs index 54d2b05..2dd6633 100644 --- a/mingling/src/res/dirs/current_dir.rs +++ b/mingling/src/res/dirs/current_dir.rs @@ -23,9 +23,12 @@ pub struct ResCurrentDir { impl ResCurrentDir { /// Creates a new `ResCurrentDir` by querying the OS for the current working directory. /// - /// Returns `Err` if the current directory cannot be determined (e.g., the directory has been - /// deleted or permissions are insufficient). Unlike the `Default` implementation, this - /// method does not panic on failure. + /// # Errors + /// + /// Returns an `Err` if the current directory cannot be determined (e.g., the directory has + /// been deleted or permissions are insufficient). + /// + /// Unlike the `Default` implementation, this method does not panic on failure. pub fn new() -> Result { Ok(Self { cwd: current_dir()?, diff --git a/mingling/src/res/dirs/current_exe.rs b/mingling/src/res/dirs/current_exe.rs index 051f380..a2afc0b 100644 --- a/mingling/src/res/dirs/current_exe.rs +++ b/mingling/src/res/dirs/current_exe.rs @@ -22,9 +22,11 @@ pub struct ResCurrentExe { impl ResCurrentExe { /// Creates a new `ResCurrentExe` by querying the OS for the current executable path. /// - /// Returns `Err` if the executable path cannot be determined (e.g., the `/proc` - /// filesystem is not available on Linux, or the process handle is invalid). - /// Unlike the `Default` implementation, this method does not panic on failure. + /// # Errors + /// + /// Returns an [`std::io::Error`] if the OS is unable to provide the path of the + /// current executable. This can occur, for example, when the `/proc` filesystem + /// is not mounted on Linux, or when the process handle is invalid on Windows. pub fn new() -> Result { Ok(Self { exe: current_exe()?, diff --git a/mingling/src/res/dirs/home_dir.rs b/mingling/src/res/dirs/home_dir.rs index fae3055..f5908de 100644 --- a/mingling/src/res/dirs/home_dir.rs +++ b/mingling/src/res/dirs/home_dir.rs @@ -21,7 +21,9 @@ pub struct ResHomeDir { impl ResHomeDir { /// Creates a new `ResHomeDir` by querying the environment for the user's home directory. /// - /// Returns `Err` if the home directory cannot be determined (e.g., the `HOME` or + /// # Errors + /// + /// Returns an error if the home directory cannot be determined (e.g., the `HOME` or /// `USERPROFILE` environment variable is not set). pub fn new() -> Result { let home = home_dir_env().ok_or_else(|| { diff --git a/mingling/src/res/dirs/temp_dir.rs b/mingling/src/res/dirs/temp_dir.rs index 343d9c7..c79a974 100644 --- a/mingling/src/res/dirs/temp_dir.rs +++ b/mingling/src/res/dirs/temp_dir.rs @@ -21,6 +21,7 @@ impl ResTempDir { /// /// This method is infallible since `std::env::temp_dir()` always succeeds, /// returning a platform-specific default when environment variables are unset. + #[must_use] pub fn new() -> Self { Self { tmp: temp_dir() } } diff --git a/mingling/src/setups/basic.rs b/mingling/src/setups/basic.rs index e081c3e..c8f8ad8 100644 --- a/mingling/src/setups/basic.rs +++ b/mingling/src/setups/basic.rs @@ -51,7 +51,7 @@ where C: ProgramCollect, { fn setup(self, program: &mut Program) { - program.global_flag(self.flag.clone(), |p| { + program.global_flag(self.flag, |p| { p.user_context.help = true; }); } @@ -90,7 +90,7 @@ where C: ProgramCollect, { fn setup(self, program: &mut Program) { - program.global_flag(self.flag.clone(), |p| { + program.global_flag(self.flag, |p| { p.stdout_setting.render_output = false; p.stdout_setting.error_output = false; }); @@ -130,7 +130,7 @@ where C: ProgramCollect, { fn setup(self, program: &mut Program) { - program.global_flag(self.flag.clone(), |p| { + program.global_flag(self.flag, |p| { p.user_context.confirm = true; }); } diff --git a/mingling/src/setups/repl_basic.rs b/mingling/src/setups/repl_basic.rs index 150048b..ea20721 100644 --- a/mingling/src/setups/repl_basic.rs +++ b/mingling/src/setups/repl_basic.rs @@ -43,24 +43,21 @@ where { fn setup(self, program: &mut Program) { match self { - BasicREPLPromptSetup::Prompt(prompt) => { + Self::Prompt(prompt) => { static PROMPT: std::sync::OnceLock = std::sync::OnceLock::new(); - let _ = PROMPT.set(prompt.clone()); - fn print_prompt() { + let _ = PROMPT.set(prompt); + program.with_hook(ProgramHook::empty().on_repl_pre_readline(|_| { print!("{}", PROMPT.get().unwrap()); let _ = std::io::stdout().flush(); - } - program.with_hook(ProgramHook::empty().on_repl_pre_readline(|_| print_prompt())); + })); } - BasicREPLPromptSetup::Func(f) => { + Self::Func(f) => { static FUNC: std::sync::OnceLock String> = std::sync::OnceLock::new(); let _ = FUNC.set(f); - fn print_func_prompt() { + program.with_hook(ProgramHook::empty().on_repl_pre_readline(|_| { print!("{}", FUNC.get().unwrap()()); let _ = std::io::stdout().flush(); - } - program - .with_hook(ProgramHook::empty().on_repl_pre_readline(|_| print_func_prompt())); + })); } } } @@ -75,7 +72,7 @@ where fn setup(self, program: &mut Program) { program.with_hook(ProgramHook::empty().on_repl_receive_result(|r| { if !r.result.is_empty() { - println!("{}", r.result) + println!("{}", r.result); } })); } -- cgit