diff options
25 files changed, 322 insertions, 304 deletions
diff --git a/arg_picker/src/arg.rs b/arg_picker/src/arg.rs index 32824ea..c36fba4 100644 --- a/arg_picker/src/arg.rs +++ b/arg_picker/src/arg.rs @@ -20,7 +20,7 @@ use std::marker::PhantomData; /// than by a `--name` or `-n` flag. /// - `false`: The parameter is a named (flag-based) parameter. /// -/// - `_type`: PhantomData to hold the type parameter. +/// - `_type`: [`PhantomData`] to hold the type parameter. #[derive(Default, Clone, Copy)] pub struct PickerArg<'a, Type> where @@ -35,16 +35,16 @@ where /// Whether the parameter is positional (no flag, matched by position). pub positional: bool, - /// PhantomData to hold the type parameter. + /// [`PhantomData`] to hold the type parameter. pub internal_type: PhantomData<Type>, } -impl<'a, Type> From<&'a PickerArg<'a, Type>> for PickerArg<'a, Type> +impl<'a, Type> From<&'a Self> for PickerArg<'a, Type> where Type: Pickable<'a>, { - fn from(value: &'a PickerArg<'a, Type>) -> Self { - PickerArg { + fn from(value: &'a Self) -> Self { + Self { full: value.full, short: value.short, positional: value.positional, @@ -58,7 +58,8 @@ where Type: Pickable<'a>, { /// Creates a new `PickerArg` with the provided parameters. - pub fn new(full: &'a [&'a str], short: Option<char>, positional: bool) -> Self { + #[must_use] + pub const fn new(full: &'a [&'a str], short: Option<char>, positional: bool) -> Self { Self { full, short, @@ -68,12 +69,14 @@ where } /// Returns the full name list (including aliases). - pub fn full(&self) -> &'a [&'a str] { + #[must_use] + pub const fn full(&self) -> &'a [&'a str] { self.full } /// Returns the short name, if any. - pub fn short(&self) -> Option<char> { + #[must_use] + pub const fn short(&self) -> Option<char> { self.short } @@ -81,7 +84,8 @@ where /// /// If `full` is empty or `short` is `None`, the parameter is considered positional /// regardless of the stored value. - pub fn is_positional(&self) -> bool { + #[must_use] + pub const fn is_positional(&self) -> bool { if self.full.is_empty() && self.short.is_none() { true } else { @@ -90,46 +94,51 @@ where } /// Sets the full name list. - pub fn set_full(&mut self, full: &'a [&'a str]) { + pub const fn set_full(&mut self, full: &'a [&'a str]) { self.full = full; } /// Sets the short name. - pub fn set_short(&mut self, short: Option<char>) { + pub const fn set_short(&mut self, short: Option<char>) { self.short = short; } /// Sets whether the parameter is positional. - pub fn set_positional(&mut self, positional: bool) { + pub const fn set_positional(&mut self, positional: bool) { self.positional = positional; } /// Sets the full name list and returns self. - pub fn with_full(mut self, full: &'a [&'a str]) -> Self { + #[must_use] + pub const fn with_full(mut self, full: &'a [&'a str]) -> Self { self.full = full; self } /// Clears the full name list (sets it to an empty slice) and returns self. - pub fn without_full(mut self) -> Self { + #[must_use] + pub const fn without_full(mut self) -> Self { self.full = &[]; self } /// Sets the short name to the given character and returns self. - pub fn with_short(mut self, short: char) -> Self { + #[must_use] + pub const fn with_short(mut self, short: char) -> Self { self.short = Some(short); self } /// Clears the short name (sets it to None) and returns self. - pub fn without_short(mut self) -> Self { + #[must_use] + pub const fn without_short(mut self) -> Self { self.short = None; self } /// Sets whether the parameter is positional and returns self. - pub fn with_positional(mut self, positional: bool) -> Self { + #[must_use] + pub const fn with_positional(mut self, positional: bool) -> Self { self.positional = positional; self } @@ -137,19 +146,19 @@ where /// Converts this `PickerArg` into a `PickerArgInfo` value. /// /// This is a convenience method equivalent to calling `PickerArgInfo::from(self)`. + #[must_use] pub fn into_info(self) -> PickerArgInfo<'a> { let value = self; - let (long, alias) = match value.full.len() { - 0 => (None, None), - _ => { - let long = Some(value.full[0]); - let alias = if value.full.len() > 1 { - Some(value.full[1..].to_vec()) - } else { - None - }; - (long, alias) - } + let (long, alias) = if value.full.is_empty() { + (None, None) + } else { + let long = Some(value.full[0]); + let alias = if value.full.len() > 1 { + Some(value.full[1..].to_vec()) + } else { + None + }; + (long, alias) }; PickerArgInfo { @@ -169,7 +178,7 @@ where Type: Pickable<'a>, { fn from(value: PickerArg<'a, Type>) -> Self { - let mut result = Vec::new(); + let mut result = Self::new(); let info = PickerArgInfo::from(value); let possible_flags = crate::parselib::build_possible_flags(ParserStyle::global_style(), &info); @@ -231,81 +240,81 @@ impl PickerArgAttr { /// Determines if the given `PickerArg` represents a positional parameter. /// /// If the flag is positional (determined by `flag.is_positional()`), returns - /// `PickerArgAttr::Positional`. Otherwise, invokes the `other` closure to - /// produce and return a `PickerArgAttr`. + /// `Self::Positional`. Otherwise, invokes the `other` closure to + /// produce and return a `Self`. /// /// # Parameters /// /// - `flag`: A reference to the [`PickerArg`] to evaluate. /// - `other`: A closure that returns a [`PickerArgAttr`] when the flag is /// **not** positional. - #[inline(always)] - pub fn positional_or_else<'a, T>( - flag: &PickerArg<'a, T>, - other: fn() -> PickerArgAttr, - ) -> PickerArgAttr + #[inline] + pub fn positional_or_else<'a, T>(flag: &PickerArg<'a, T>, other: fn() -> Self) -> Self where T: Pickable<'a>, { if flag.is_positional() { - PickerArgAttr::Positional + Self::Positional } else { other() } } /// Determines if the given `PickerArg` represents a positional parameter and returns - /// `PickerArgAttr::Positional` if so. Otherwise, returns the provided `default` attribute. + /// `Self::Positional` if so. Otherwise, returns the provided `default` attribute. /// /// # Parameters /// /// - `flag`: A reference to the [`PickerArg`] to evaluate. /// - `default`: The [`PickerArgAttr`] to return if the flag is not positional. - #[inline(always)] - pub fn positional_or<'a, T>(flag: &PickerArg<'a, T>, default: PickerArgAttr) -> PickerArgAttr + #[must_use] + #[inline] + pub const fn positional_or<'a, T>(flag: &PickerArg<'a, T>, default: Self) -> Self where T: Pickable<'a>, { if flag.is_positional() { - PickerArgAttr::Positional + Self::Positional } else { default } } /// Determines if the given `PickerArg` represents a positional parameter and returns - /// `PickerArgAttr::Positional` if so. Otherwise, returns `PickerArgAttr::Single`. + /// `Self::Positional` if so. Otherwise, returns `Self::Single`. /// /// # Parameters /// /// - `flag`: A reference to the [`PickerArg`] to evaluate. - #[inline(always)] - pub fn positional_or_single<'a, T>(flag: &PickerArg<'a, T>) -> PickerArgAttr + #[must_use] + #[inline] + pub const fn positional_or_single<'a, T>(flag: &PickerArg<'a, T>) -> Self where T: Pickable<'a>, { if flag.is_positional() { - PickerArgAttr::Positional + Self::Positional } else { - PickerArgAttr::Single + Self::Single } } /// Determines if the given `PickerArg` represents a positional parameter and returns - /// `PickerArgAttr::PositionalMulti` if so. Otherwise, returns `PickerArgAttr::Multi`. + /// `Self::PositionalMulti` if so. Otherwise, returns `Self::Multi`. /// /// # Parameters /// /// - `flag`: A reference to the [`PickerArg`] to evaluate. - #[inline(always)] - pub fn positional_or_multi<'a, T>(flag: &PickerArg<'a, T>) -> PickerArgAttr + #[must_use] + #[inline] + pub const fn positional_or_multi<'a, T>(flag: &PickerArg<'a, T>) -> Self where T: Pickable<'a>, { if flag.is_positional() { - PickerArgAttr::PositionalMulti + Self::PositionalMulti } else { - PickerArgAttr::Multi + Self::Multi } } } diff --git a/arg_picker/src/builtin/pick_flag.rs b/arg_picker/src/builtin/pick_flag.rs index b642a9a..8afc0fc 100644 --- a/arg_picker/src/builtin/pick_flag.rs +++ b/arg_picker/src/builtin/pick_flag.rs @@ -13,9 +13,9 @@ impl<'a> Pickable<'a> for Flag { fn pick(raw_strs: &[&str]) -> PickerArgResult<Self> { if raw_strs.is_empty() { - PickerArgResult::Parsed(Flag::Inactive) + PickerArgResult::Parsed(Self::Inactive) } else { - PickerArgResult::Parsed(Flag::Active) + PickerArgResult::Parsed(Self::Active) } } } diff --git a/arg_picker/src/builtin/pick_ip_attr.rs b/arg_picker/src/builtin/pick_ip_attr.rs index d68fa15..57ac80e 100644 --- a/arg_picker/src/builtin/pick_ip_attr.rs +++ b/arg_picker/src/builtin/pick_ip_attr.rs @@ -4,36 +4,33 @@ use crate::SinglePickable; impl SinglePickable for IpAddr { fn pick_single(str: Option<&str>) -> crate::PickerArgResult<Self> { - match str { - Some(s) => match s.parse::<IpAddr>() { - Ok(addr) => crate::PickerArgResult::Parsed(addr), - Err(_) => crate::PickerArgResult::NotFound, - }, - None => crate::PickerArgResult::NotFound, - } + str.map_or(crate::PickerArgResult::NotFound, |s| { + s.parse::<Self>() + .map_or(crate::PickerArgResult::NotFound, |addr| { + crate::PickerArgResult::Parsed(addr) + }) + }) } } impl SinglePickable for Ipv4Addr { fn pick_single(str: Option<&str>) -> crate::PickerArgResult<Self> { - match str { - Some(s) => match s.parse::<Ipv4Addr>() { - Ok(addr) => crate::PickerArgResult::Parsed(addr), - Err(_) => crate::PickerArgResult::NotFound, - }, - None => crate::PickerArgResult::NotFound, - } + str.map_or(crate::PickerArgResult::NotFound, |s| { + s.parse::<Self>() + .map_or(crate::PickerArgResult::NotFound, |addr| { + crate::PickerArgResult::Parsed(addr) + }) + }) } } impl SinglePickable for Ipv6Addr { fn pick_single(str: Option<&str>) -> crate::PickerArgResult<Self> { - match str { - Some(s) => match s.parse::<Ipv6Addr>() { - Ok(addr) => crate::PickerArgResult::Parsed(addr), - Err(_) => crate::PickerArgResult::NotFound, - }, - None => crate::PickerArgResult::NotFound, - } + str.map_or(crate::PickerArgResult::NotFound, |s| { + s.parse::<Self>() + .map_or(crate::PickerArgResult::NotFound, |addr| { + crate::PickerArgResult::Parsed(addr) + }) + }) } } diff --git a/arg_picker/src/builtin/pick_numbers.rs b/arg_picker/src/builtin/pick_numbers.rs index a5ab0a9..6cbd4fc 100644 --- a/arg_picker/src/builtin/pick_numbers.rs +++ b/arg_picker/src/builtin/pick_numbers.rs @@ -21,10 +21,7 @@ fn is_int_like(raw: &str) -> bool { if bytes.is_empty() { return false; } - let mut i = 0; - if bytes[0] == b'-' || bytes[0] == b'+' { - i = 1; - } + let i = usize::from(bytes[0] == b'-' || bytes[0] == b'+'); if i >= bytes.len() { return false; } @@ -69,12 +66,12 @@ impl_boundary_check_int! { // Integer-like strings trigger a boundary. impl BoundaryCheck for f32 { fn check_boundary(raw: &str) -> bool { - !is_float_like(raw) || raw.parse::<f32>().is_err() + !is_float_like(raw) || raw.parse::<Self>().is_err() } } impl BoundaryCheck for f64 { fn check_boundary(raw: &str) -> bool { - !is_float_like(raw) || raw.parse::<f64>().is_err() + !is_float_like(raw) || raw.parse::<Self>().is_err() } } diff --git a/arg_picker/src/builtin/pick_pathbuf.rs b/arg_picker/src/builtin/pick_pathbuf.rs index 3bd4410..2b48e3d 100644 --- a/arg_picker/src/builtin/pick_pathbuf.rs +++ b/arg_picker/src/builtin/pick_pathbuf.rs @@ -7,12 +7,8 @@ use crate::{ impl SinglePickable for PathBuf { fn pick_single(str: Option<&str>) -> crate::PickerArgResult<Self> { - match str { - Some(str) => match just_fmt::fmt_path_str(str) { - Ok(formated) => Parsed(PathBuf::from(formated)), - Err(_) => NotFound, - }, - None => NotFound, - } + str.map_or(NotFound, |str| { + just_fmt::fmt_path_str(str).map_or(NotFound, |formated| Parsed(Self::from(formated))) + }) } } diff --git a/arg_picker/src/builtin/pick_paths.rs b/arg_picker/src/builtin/pick_paths.rs index 8e6c0fd..954464b 100644 --- a/arg_picker/src/builtin/pick_paths.rs +++ b/arg_picker/src/builtin/pick_paths.rs @@ -17,7 +17,7 @@ impl SinglePickable for FilePath { match <PathBuf as SinglePickable>::pick_single(str) { Parsed(path) => { if path.exists() && path.is_file() { - Parsed(FilePath::from(path)) + Parsed(Self::from(path)) } else { NotFound } @@ -33,7 +33,7 @@ impl SinglePickable for NoFilePath { match <PathBuf as SinglePickable>::pick_single(str) { Parsed(path) => { if !path.exists() || !path.is_file() { - Parsed(NoFilePath::from(path)) + Parsed(Self::from(path)) } else { NotFound } @@ -49,7 +49,7 @@ impl SinglePickable for DirPath { match <PathBuf as SinglePickable>::pick_single(str) { Parsed(path) => { if path.exists() && path.is_dir() { - Parsed(DirPath::from(path)) + Parsed(Self::from(path)) } else { NotFound } @@ -65,7 +65,7 @@ impl SinglePickable for NoDirPath { match <PathBuf as SinglePickable>::pick_single(str) { Parsed(path) => { if !path.exists() || !path.is_dir() { - Parsed(NoDirPath::from(path)) + Parsed(Self::from(path)) } else { NotFound } @@ -81,7 +81,7 @@ impl SinglePickable for SymlinkPath { match <PathBuf as SinglePickable>::pick_single(str) { Parsed(path) => { if path.exists() && path.is_symlink() { - Parsed(SymlinkPath::from(path)) + Parsed(Self::from(path)) } else { NotFound } @@ -97,7 +97,7 @@ impl SinglePickable for NoSymlinkPath { match <PathBuf as SinglePickable>::pick_single(str) { Parsed(path) => { if !path.exists() || !path.is_symlink() { - Parsed(NoSymlinkPath::from(path)) + Parsed(Self::from(path)) } else { NotFound } @@ -112,10 +112,10 @@ impl SinglePickable for NoPath { fn pick_single(str: Option<&str>) -> PickerArgResult<Self> { match <PathBuf as SinglePickable>::pick_single(str) { Parsed(path) => { - if !path.exists() { - Parsed(NoPath::from(path)) - } else { + if path.exists() { NotFound + } else { + Parsed(Self::from(path)) } } Unparsed => Unparsed, @@ -132,7 +132,7 @@ impl SinglePickable for RecursiveFiles { return NotFound; } if path.is_file() || path.is_symlink() { - return Parsed(RecursiveFiles::from(vec![path])); + return Parsed(Self::from(vec![path])); } let mut entries = Vec::new(); if let Ok(dir_entries) = fs::read_dir(&path) { @@ -145,7 +145,7 @@ impl SinglePickable for RecursiveFiles { } } } - Parsed(RecursiveFiles::from(entries)) + Parsed(Self::from(entries)) } Unparsed => Unparsed, NotFound => NotFound, diff --git a/arg_picker/src/builtin/pick_picker_args.rs b/arg_picker/src/builtin/pick_picker_args.rs index 419cbc8..618960f 100644 --- a/arg_picker/src/builtin/pick_picker_args.rs +++ b/arg_picker/src/builtin/pick_picker_args.rs @@ -15,7 +15,7 @@ impl<'a> Pickable<'a> for PickerArgs<'a> { } fn pick(raw_strs: &[&str]) -> PickerArgResult<Self> { - let remains: Vec<String> = raw_strs.iter().map(|s| s.to_string()).collect(); + let remains: Vec<String> = raw_strs.iter().map(ToString::to_string).collect(); Parsed(PickerArgs::Owned(remains)) } } diff --git a/arg_picker/src/builtin/pick_socket_attr.rs b/arg_picker/src/builtin/pick_socket_attr.rs index 0c0dd71..ba9a410 100644 --- a/arg_picker/src/builtin/pick_socket_attr.rs +++ b/arg_picker/src/builtin/pick_socket_attr.rs @@ -4,36 +4,33 @@ use crate::SinglePickable; impl SinglePickable for SocketAddr { fn pick_single(str: Option<&str>) -> crate::PickerArgResult<Self> { - match str { - Some(s) => match s.parse::<SocketAddr>() { - Ok(addr) => crate::PickerArgResult::Parsed(addr), - Err(_) => crate::PickerArgResult::NotFound, - }, - None => crate::PickerArgResult::NotFound, - } + str.map_or(crate::PickerArgResult::NotFound, |s| { + s.parse::<Self>() + .map_or(crate::PickerArgResult::NotFound, |addr| { + crate::PickerArgResult::Parsed(addr) + }) + }) } } impl SinglePickable for SocketAddrV4 { fn pick_single(str: Option<&str>) -> crate::PickerArgResult<Self> { - match str { - Some(s) => match s.parse::<SocketAddrV4>() { - Ok(addr) => crate::PickerArgResult::Parsed(addr), - Err(_) => crate::PickerArgResult::NotFound, - }, - None => crate::PickerArgResult::NotFound, - } + str.map_or(crate::PickerArgResult::NotFound, |s| { + s.parse::<Self>() + .map_or(crate::PickerArgResult::NotFound, |addr| { + crate::PickerArgResult::Parsed(addr) + }) + }) } } impl SinglePickable for SocketAddrV6 { fn pick_single(str: Option<&str>) -> crate::PickerArgResult<Self> { - match str { - Some(s) => match s.parse::<SocketAddrV6>() { - Ok(addr) => crate::PickerArgResult::Parsed(addr), - Err(_) => crate::PickerArgResult::NotFound, - }, - None => crate::PickerArgResult::NotFound, - } + str.map_or(crate::PickerArgResult::NotFound, |s| { + s.parse::<Self>() + .map_or(crate::PickerArgResult::NotFound, |addr| { + crate::PickerArgResult::Parsed(addr) + }) + }) } } diff --git a/arg_picker/src/builtin/pick_string.rs b/arg_picker/src/builtin/pick_string.rs index c96f667..c7bdd4a 100644 --- a/arg_picker/src/builtin/pick_string.rs +++ b/arg_picker/src/builtin/pick_string.rs @@ -3,9 +3,6 @@ use crate::{SinglePickable, pickable_needed::*}; impl SinglePickable for String { fn pick_single(str: Option<&str>) -> PickerArgResult<Self> { - match str { - Some(str) => PickerArgResult::Parsed(str.to_string()), - None => NotFound, - } + str.map_or(NotFound, |str| PickerArgResult::Parsed(str.to_string())) } } diff --git a/arg_picker/src/infos.rs b/arg_picker/src/infos.rs index c17b6a2..08b2be7 100644 --- a/arg_picker/src/infos.rs +++ b/arg_picker/src/infos.rs @@ -3,9 +3,9 @@ use crate::{Pickable, PickerArg, parselib::ParserStyle}; /// Represents the result of parsing or looking up a value. /// /// This enum is generic over the type being parsed. It models three possible outcomes: -/// - [`Unparsed`](PickerArgResult::Unparsed): The value has not yet been parsed (default). -/// - [`Parsed`](PickerArgResult::Parsed): The value was successfully parsed into `Type`. -/// - [`NotFound`](PickerArgResult::NotFound): The requested value could not be found. +/// - [`Unparsed`](Self::Unparsed): The value has not yet been parsed (default). +/// - [`Parsed`](Self::Parsed): The value was successfully parsed into `Type`. +/// - [`NotFound`](Self::NotFound): The requested value could not be found. #[derive(Default)] pub enum PickerArgResult<Type> { /// The value has not yet been parsed (default). @@ -22,31 +22,25 @@ pub enum PickerArgResult<Type> { impl<Type, E> From<Result<Type, E>> for PickerArgResult<Type> { /// Converts a `Result<Type, E>` into a `PickerArgResult<Type>`. /// - /// - `Ok(value)` maps to [`Parsed(value)`](PickerArgResult::Parsed). - /// - `Err(_)` maps to [`NotFound`](PickerArgResult::NotFound). + /// - `Ok(value)` maps to [`Parsed(value)`](Self::Parsed). + /// - `Err(_)` maps to [`NotFound`](Self::NotFound). fn from(result: Result<Type, E>) -> Self { - match result { - Ok(value) => PickerArgResult::Parsed(value), - Err(_) => PickerArgResult::NotFound, - } + result.map_or_else(|_| Self::NotFound, |value| Self::Parsed(value)) } } impl<Type> From<Option<Type>> for PickerArgResult<Type> { /// Converts an `Option<Type>` into a `PickerArgResult<Type>`. /// - /// - `Some(value)` maps to [`Parsed(value)`](PickerArgResult::Parsed). - /// - `None` maps to [`NotFound`](PickerArgResult::NotFound). + /// - `Some(value)` maps to [`Parsed(value)`](Self::Parsed). + /// - `None` maps to [`NotFound`](Self::NotFound). fn from(option: Option<Type>) -> Self { - match option { - Some(value) => PickerArgResult::Parsed(value), - None => PickerArgResult::NotFound, - } + option.map_or_else(|| Self::NotFound, |value| Self::Parsed(value)) } } impl<Type> PickerArgResult<Type> { - /// Returns `true` if the result is [`Parsed`](PickerArgResult::Parsed). + /// Returns `true` if the result is [`Parsed`](Self::Parsed). /// /// # Examples /// @@ -59,11 +53,11 @@ impl<Type> PickerArgResult<Type> { /// let result: PickerArgResult<i32> = PickerArgResult::NotFound; /// assert!(!result.is_parsed()); /// ``` - pub fn is_parsed(&self) -> bool { - matches!(self, PickerArgResult::Parsed(_)) + pub const fn is_parsed(&self) -> bool { + matches!(self, Self::Parsed(_)) } - /// Returns `true` if the result is [`Parsed`](PickerArgResult::Parsed) or [`NotFound`](PickerArgResult::NotFound). + /// Returns `true` if the result is [`Parsed`](Self::Parsed) or [`NotFound`](Self::NotFound). /// i.e., the value exists (was either found or not yet parsed). /// Typically indicates the value was "found" in some sense. /// @@ -78,11 +72,11 @@ impl<Type> PickerArgResult<Type> { /// let result: PickerArgResult<i32> = PickerArgResult::NotFound; /// assert!(result.is_found()); /// ``` - pub fn is_found(&self) -> bool { - matches!(self, PickerArgResult::Parsed(_) | PickerArgResult::NotFound) + pub const fn is_found(&self) -> bool { + matches!(self, Self::Parsed(_) | Self::NotFound) } - /// Returns `true` if the result is [`Unparsed`](PickerArgResult::Unparsed) or [`NotFound`](PickerArgResult::NotFound). + /// Returns `true` if the result is [`Unparsed`](Self::Unparsed) or [`NotFound`](Self::NotFound). /// /// # Examples /// @@ -95,11 +89,11 @@ impl<Type> PickerArgResult<Type> { /// let result: PickerArgResult<i32> = PickerArgResult::Parsed(10); /// assert!(!result.is_err()); /// ``` - pub fn is_err(&self) -> bool { - !matches!(self, PickerArgResult::Parsed(_)) + pub const fn is_err(&self) -> bool { + !matches!(self, Self::Parsed(_)) } - /// Returns `Some(&Type)` if [`Parsed`](PickerArgResult::Parsed), otherwise `None`. + /// Returns `Some(&Type)` if [`Parsed`](Self::Parsed), otherwise `None`. /// /// # Examples /// @@ -112,18 +106,18 @@ impl<Type> PickerArgResult<Type> { /// let result: PickerArgResult<i32> = PickerArgResult::NotFound; /// assert_eq!(result.parsed(), None); /// ``` - pub fn parsed(&self) -> Option<&Type> { - if let PickerArgResult::Parsed(value) = self { + pub const fn parsed(&self) -> Option<&Type> { + if let Self::Parsed(value) = self { Some(value) } else { None } } - /// Returns the contained [`Parsed`](PickerArgResult::Parsed) value or panics with a given message. + /// Returns the contained [`Parsed`](Self::Parsed) value or panics with a given message. /// /// # Panics - /// Panics if the value is not [`Parsed`](PickerArgResult::Parsed), with a message including the provided `msg`. + /// Panics if the value is not [`Parsed`](Self::Parsed), with a message including the provided `msg`. /// /// # Examples /// @@ -135,15 +129,15 @@ impl<Type> PickerArgResult<Type> { /// ``` pub fn expect(self, msg: &str) -> Type { match self { - PickerArgResult::Parsed(value) => value, + Self::Parsed(value) => value, _ => panic!("{}", msg), } } - /// Returns the contained [`Parsed`](PickerArgResult::Parsed) value or panics. + /// Returns the contained [`Parsed`](Self::Parsed) value or panics. /// /// # Panics - /// Panics if the value is not [`Parsed`](PickerArgResult::Parsed). + /// Panics if the value is not [`Parsed`](Self::Parsed). /// /// # Examples /// @@ -162,17 +156,17 @@ impl<Type> PickerArgResult<Type> { /// ``` pub fn unwrap(self) -> Type { match self { - PickerArgResult::Parsed(value) => value, - PickerArgResult::Unparsed => { + Self::Parsed(value) => value, + Self::Unparsed => { panic!("called `PickerArgResult::unwrap()` on an `Unparsed` value") } - PickerArgResult::NotFound => { + Self::NotFound => { panic!("called `PickerArgResult::unwrap()` on a `NotFound` value") } } } - /// Returns the contained [`Parsed`](PickerArgResult::Parsed) value or a provided `default`. + /// Returns the contained [`Parsed`](Self::Parsed) value or a provided `default`. /// /// # Examples /// @@ -187,12 +181,12 @@ impl<Type> PickerArgResult<Type> { /// ``` pub fn unwrap_or(self, default: Type) -> Type { match self { - PickerArgResult::Parsed(value) => value, + Self::Parsed(value) => value, _ => default, } } - /// Returns the contained [`Parsed`](PickerArgResult::Parsed) value or computes it from a closure. + /// Returns the contained [`Parsed`](Self::Parsed) value or computes it from a closure. /// /// # Examples /// @@ -207,12 +201,12 @@ impl<Type> PickerArgResult<Type> { /// ``` pub fn unwrap_or_else<F: FnOnce() -> Type>(self, f: F) -> Type { match self { - PickerArgResult::Parsed(value) => value, + Self::Parsed(value) => value, _ => f(), } } - /// Returns the contained [`Parsed`](PickerArgResult::Parsed) value or the default value of `Type`. + /// Returns the contained [`Parsed`](Self::Parsed) value or the default value of `Type`. /// /// # Examples /// @@ -230,14 +224,14 @@ impl<Type> PickerArgResult<Type> { Type: Default, { match self { - PickerArgResult::Parsed(value) => value, + Self::Parsed(value) => value, _ => Type::default(), } } /// Converts `PickerArgResult<Type>` into `Option<Type>`. /// - /// Returns `Some(Type)` if [`Parsed`](PickerArgResult::Parsed), otherwise `None`. + /// Returns `Some(Type)` if [`Parsed`](Self::Parsed), otherwise `None`. /// /// # Examples /// @@ -255,12 +249,14 @@ impl<Type> PickerArgResult<Type> { /// ``` pub fn to_option(self) -> Option<Type> { match self { - PickerArgResult::Parsed(value) => Some(value), + Self::Parsed(value) => Some(value), _ => None, } } } +// In PickerArgInfo, positional, optional, multi, and is_flag may coexist. +#[allow(clippy::struct_excessive_bools)] /// Represents metadata about a command-line argument or flag. /// /// This struct stores all relevant information about a tag/argument that can be used @@ -294,17 +290,16 @@ where impl<'a, T: Pickable<'a>> From<&'a PickerArg<'a, T>> for PickerArgInfo<'a> { fn from(value: &'a PickerArg<'a, T>) -> Self { - let (long, alias) = match value.full.len() { - 0 => (None, None), - _ => { - let long = Some(value.full[0]); - let alias = if value.full.len() > 1 { - Some(value.full[1..].to_vec()) - } else { - None - }; - (long, alias) - } + let (long, alias) = if value.full.is_empty() { + (None, None) + } else { + let long = Some(value.full[0]); + let alias = if value.full.len() > 1 { + Some(value.full[1..].to_vec()) + } else { + None + }; + (long, alias) }; Self { @@ -321,7 +316,8 @@ impl<'a, T: Pickable<'a>> From<&'a PickerArg<'a, T>> for PickerArgInfo<'a> { impl<'a> PickerArgInfo<'a> { /// Create a new `PickerTag` with default values. - pub fn new() -> Self { + #[must_use] + pub const fn new() -> Self { Self { short: None, long: None, @@ -334,55 +330,62 @@ impl<'a> PickerArgInfo<'a> { } /// Set the short flag (e.g., `'n'` for `-n`). - pub fn with_short(mut self, short: char) -> Self { + #[must_use] + pub const fn with_short(mut self, short: char) -> Self { self.short = Some(short); self } /// Set the long flag (e.g., `"name"` for `--name`). - pub fn with_long(mut self, long: &'a str) -> Self { + #[must_use] + pub const fn with_long(mut self, long: &'a str) -> Self { self.long = Some(long); self } /// Set aliases for the tag. + #[must_use] pub fn with_alias(mut self, alias: Vec<&'a str>) -> Self { self.alias = Some(alias); self } /// Mark the tag as positional. - pub fn with_positional(mut self, positional: bool) -> Self { + #[must_use] + pub const fn with_positional(mut self, positional: bool) -> Self { self.positional = positional; self } /// Mark the tag as optional. - pub fn with_optional(mut self, optional: bool) -> Self { + #[must_use] + pub const fn with_optional(mut self, optional: bool) -> Self { self.optional = optional; self } /// Mark the tag as multi-value. - pub fn with_multi(mut self, multi: bool) -> Self { + #[must_use] + pub const fn with_multi(mut self, multi: bool) -> Self { self.multi = multi; self } /// Mark the tag as a flag that participates in parsing after `--`. - pub fn with_is_flag(mut self, is_flag: bool) -> Self { + #[must_use] + pub const fn with_is_flag(mut self, is_flag: bool) -> Self { self.is_flag = is_flag; self } /// Set the short flag (e.g., `'n'` for `-n`). - pub fn set_short(&mut self, short: char) -> &mut Self { + pub const fn set_short(&mut self, short: char) -> &mut Self { self.short = Some(short); self } /// Set the long flag (e.g., `"name"` for `--name`). - pub fn set_long(&mut self, long: &'a str) -> &mut Self { + pub const fn set_long(&mut self, long: &'a str) -> &mut Self { self.long = Some(long); self } @@ -394,25 +397,25 @@ impl<'a> PickerArgInfo<'a> { } /// Set whether this tag is positional. - pub fn set_positional(&mut self, positional: bool) -> &mut Self { + pub const fn set_positional(&mut self, positional: bool) -> &mut Self { self.positional = positional; self } /// Set whether this tag is optional. - pub fn set_optional(&mut self, optional: bool) -> &mut Self { + pub const fn set_optional(&mut self, optional: bool) -> &mut Self { self.optional = optional; self } /// Set whether this tag accepts multiple values. - pub fn set_multi(&mut self, multi: bool) -> &mut Self { + pub const fn set_multi(&mut self, multi: bool) -> &mut Self { self.multi = multi; self } /// Set whether this tag participates in parsing after a `--` separator. - pub fn set_is_flag(&mut self, is_flag: bool) -> &mut Self { + pub const fn set_is_flag(&mut self, is_flag: bool) -> &mut Self { self.is_flag = is_flag; self } @@ -437,6 +440,7 @@ impl<'a> PickerArgInfo<'a> { /// let info = PickerArgInfo::new(); /// assert_eq!(info.short_flag(), None); /// ``` + #[must_use] pub fn short_flag(&self) -> Option<String> { let short = self.short?; Some(ParserStyle::global_style().flag_string(short)) @@ -462,13 +466,14 @@ impl<'a> PickerArgInfo<'a> { /// let info = PickerArgInfo::new(); /// assert_eq!(info.long_flag(), None); /// ``` + #[must_use] pub fn long_flag(&self) -> Option<String> { let long = self.long?; Some(ParserStyle::global_style().flag_string(long)) } } -impl<'a> Default for PickerArgInfo<'a> { +impl Default for PickerArgInfo<'_> { fn default() -> Self { Self::new() } diff --git a/arg_picker/src/lib.rs b/arg_picker/src/lib.rs index d292826..06ae959 100644 --- a/arg_picker/src/lib.rs +++ b/arg_picker/src/lib.rs @@ -1,5 +1,9 @@ #![doc = include_str!("../README.md")] #![deny(missing_docs)] +#![deny(clippy::pedantic)] +#![deny(clippy::nursery)] +// Some code requires wildcard imports to reduce boilerplate code +#![allow(clippy::wildcard_imports)] mod builtin; diff --git a/arg_picker/src/parselib.rs b/arg_picker/src/parselib.rs index 0fcd583..edb03bb 100644 --- a/arg_picker/src/parselib.rs +++ b/arg_picker/src/parselib.rs @@ -58,14 +58,16 @@ pub trait Matcher { /// Convenience method that builds masked arguments from `PickerArgs` and a mask, /// then calls `on_match_one`. - fn match_one<'a>(ctx: MatcherContext<'a>) -> Option<usize> { + #[must_use] + fn match_one(ctx: MatcherContext<'_>) -> Option<usize> { let masked_args = build_masked_args(ctx.args, ctx.mask); Self::on_match_one(masked_args.as_slice(), ctx.style, ctx.arg_info) } /// Convenience method that builds masked arguments from `PickerArgs` and a mask, /// then calls `on_match_all`. - fn match_all<'a>(ctx: MatcherContext<'a>) -> Vec<usize> { + #[must_use] + fn match_all(ctx: MatcherContext<'_>) -> Vec<usize> { let masked_args = build_masked_args(ctx.args, ctx.mask); Self::on_match_all(masked_args.as_slice(), ctx.style, ctx.arg_info) } @@ -90,7 +92,7 @@ pub struct MatcherContext<'a> { /// Metadata about the command-line argument/flag being processed. /// /// Contains information such as short form (`-n`), long form (`--name`), - /// aliases, and parsing flags (positional, optional, multi, is_flag). + /// aliases, and parsing flags (positional, optional, multi, `is_flag`). /// Used by matchers to make decisions based on argument characteristics. pub arg_info: &'a PickerArgInfo<'a>, } @@ -126,7 +128,8 @@ impl<'a> From<crate::TagPhaseContext<'a>> for MatcherContext<'a> { /// /// * `mask` - A byte slice where non-zero values indicate claimed arguments. /// * `idx` - The index to check in the mask. -#[inline(always)] +#[inline] +#[must_use] pub fn is_masked(mask: &[u8], idx: usize) -> bool { idx < mask.len() && mask[idx] != 0 } @@ -141,7 +144,8 @@ pub fn is_masked(mask: &[u8], idx: usize) -> bool { /// /// * `args` - The full set of parsed arguments. /// * `mask` - A byte slice where `0` means available and non-zero means already claimed. -#[inline(always)] +#[inline] +#[must_use] pub fn build_masked_args<'a>(args: &'a PickerArgs, mask: &'a [u8]) -> Vec<MaskedArg<'a>> { let mut cidx = 0; args.iter() @@ -150,13 +154,13 @@ pub fn build_masked_args<'a>(args: &'a PickerArgs, mask: &'a [u8]) -> Vec<Masked cidx += 1; // Include args where mask is 0 (available/not yet claimed). // mask[i] = 0 means available; mask[i] != 0 means already claimed. - if !is_masked(mask, idx) { + if is_masked(mask, idx) { + None + } else { Some(MaskedArg { raw: r, raw_idx: idx, }) - } else { - None } }) .collect() diff --git a/arg_picker/src/parselib/arg_matcher.rs b/arg_picker/src/parselib/arg_matcher.rs index 38bb9cc..d26f6fb 100644 --- a/arg_picker/src/parselib/arg_matcher.rs +++ b/arg_picker/src/parselib/arg_matcher.rs @@ -29,7 +29,7 @@ pub struct ArgMatcher; impl ArgMatcher { /// Check whether `raw` matches `flag_str`, optionally with an inline value /// separated by the style's value separator (`=` for Unix, `:` for PowerShell). - #[inline(always)] + #[inline] fn matches(raw: &str, flag_str: &str, case_sensitive: bool, sep: char) -> bool { let eq_match = |r: &str, f: &str| r.len() > f.len() && r.as_bytes().get(f.len()) == Some(&(sep as u8)); @@ -46,7 +46,7 @@ impl ArgMatcher { /// Check whether the argument contains its value inline via the style's /// value separator (eq mode), so no extra mask slot is needed. - #[inline(always)] + #[inline] fn is_inline_value(raw: &str, flag_str: &str, sep: char) -> bool { raw.len() > flag_str.len() && raw.as_bytes().get(flag_str.len()) == Some(&(sep as u8)) } diff --git a/arg_picker/src/parselib/flag_matcher.rs b/arg_picker/src/parselib/flag_matcher.rs index e93d35a..2484cc9 100644 --- a/arg_picker/src/parselib/flag_matcher.rs +++ b/arg_picker/src/parselib/flag_matcher.rs @@ -18,7 +18,7 @@ impl Matcher for FlagMatcher { arg_info: &PickerArgInfo, ) -> Option<usize> { let possible_flags = build_possible_flags(style, arg_info); - let flag_refs: Vec<&str> = possible_flags.iter().map(|s| s.as_str()).collect(); + let flag_refs: Vec<&str> = possible_flags.iter().map(String::as_str).collect(); let end_of_options = seek_end_of_options(args, style); let result = get_seeked_first(multi_seek_eq(args, &flag_refs, style.case_sensitive)); @@ -45,7 +45,7 @@ fn single_pass_match_all( style: &ParserStyle, possible_flags: &[String], ) -> Vec<usize> { - let flag_refs: Vec<&str> = possible_flags.iter().map(|s| s.as_str()).collect(); + let flag_refs: Vec<&str> = possible_flags.iter().map(String::as_str).collect(); let eoo = style.end_of_options; let case_sensitive = style.case_sensitive; @@ -67,12 +67,12 @@ fn single_pass_match_all( // Only match flags before the end-of-options marker. if end_pos.is_none() { - let matched = if case_sensitive { + let is_matched = if case_sensitive { flag_refs.contains(&arg.raw) } else { flag_refs.iter().any(|s| arg.raw.eq_ignore_ascii_case(s)) }; - if matched { + if is_matched { matches.push(arg.raw_idx); } } diff --git a/arg_picker/src/parselib/multi_arg_matcher.rs b/arg_picker/src/parselib/multi_arg_matcher.rs index 748b1be..6791121 100644 --- a/arg_picker/src/parselib/multi_arg_matcher.rs +++ b/arg_picker/src/parselib/multi_arg_matcher.rs @@ -115,7 +115,7 @@ impl Matcher for MultiArgMatcher { } impl MultiArgMatcher { - #[inline(always)] + #[inline] fn flag_match(raw: &str, flag_str: &str, case_sensitive: bool, sep: char) -> bool { let eq = |r: &str, f: &str| r.len() > f.len() && r.as_bytes().get(f.len()) == Some(&(sep as u8)); @@ -130,7 +130,7 @@ impl MultiArgMatcher { } } - #[inline(always)] + #[inline] fn is_eq_match(raw: &str, flags: &[String], case_sensitive: bool, sep: char) -> bool { flags.iter().any(|f| { Self::flag_match(raw, f, case_sensitive, sep) diff --git a/arg_picker/src/parselib/pos_matcher.rs b/arg_picker/src/parselib/pos_matcher.rs index 279e01e..96aceb3 100644 --- a/arg_picker/src/parselib/pos_matcher.rs +++ b/arg_picker/src/parselib/pos_matcher.rs @@ -14,7 +14,7 @@ pub struct PositionalMatcher; impl PositionalMatcher { /// Check whether `raw` looks like a named flag (starts with a prefix). - #[inline(always)] + #[inline] fn is_flag_like(raw: &str, style: &ParserStyle) -> bool { raw.starts_with(style.long_prefix) || raw.starts_with(style.short_prefix) } diff --git a/arg_picker/src/parselib/single_matcher.rs b/arg_picker/src/parselib/single_matcher.rs index 25c4741..d7cf6a4 100644 --- a/arg_picker/src/parselib/single_matcher.rs +++ b/arg_picker/src/parselib/single_matcher.rs @@ -18,12 +18,11 @@ impl SingleMatcher { /// For named args, only complete pairs (flag + value) are kept. /// Flag occurrences without a following value or inline separator /// are dropped so they remain available for other matchers. - #[inline(always)] + #[inline] + #[must_use] pub fn tag(ctx: TagPhaseContext) -> Vec<usize> { if ctx.arg_info.positional { - PositionalMatcher::match_one(ctx.into()) - .map(|i| vec![i]) - .unwrap_or_default() + PositionalMatcher::match_one(ctx.into()).map_or_else(Vec::new, |i| vec![i]) } else { let args = ctx.args; let positions = ArgMatcher::match_all(ctx.into()); diff --git a/arg_picker/src/parselib/style.rs b/arg_picker/src/parselib/style.rs index 36ba8f0..81dfe72 100644 --- a/arg_picker/src/parselib/style.rs +++ b/arg_picker/src/parselib/style.rs @@ -56,7 +56,7 @@ impl<'a> ParserStyle<'a> { /// /// A `String` with the prefix and the flag name combined. #[must_use] - #[inline(always)] + #[inline] pub fn flag_string<F>(&self, flag: F) -> String where F: Into<FlagStr<'a>>, @@ -88,7 +88,7 @@ pub enum FlagStr<'a> { Long(&'a str), } -impl<'a> From<char> for FlagStr<'a> { +impl From<char> for FlagStr<'_> { /// Converts a single character into a `FlagStr::Short`. fn from(c: char) -> Self { FlagStr::Short(c) @@ -129,36 +129,36 @@ impl<'a> From<&'a String> for FlagStr<'a> { #[repr(u8)] #[derive(Default, Clone, Copy, PartialEq, Eq)] pub enum ParserStyleNamingCase { - /// snake_case format: words are separated by underscores, all lowercase. + /// `snake_case` format: words are separated by underscores, all lowercase. /// /// Example: `brew_coffee` #[default] Snake, - /// camelCase format: first word is lowercase, subsequent words are capitalized. + /// `camelCase` format: first word is lowercase, subsequent words are capitalized. /// /// Example: `brewCoffee` Camel, - /// PascalCase format: every word starts with an uppercase letter. + /// `PascalCase` format: every word starts with an uppercase letter. /// /// Example: `BrewCoffee` Pascal, - /// kebab-case format: words are separated by hyphens, all lowercase. + /// `kebab-case` format: words are separated by hyphens, all lowercase. /// /// Example: `brew-coffee` Kebab, - /// dot.case format: words are separated by dots, all lowercase. + /// `dot.case` format: words are separated by dots, all lowercase. /// /// Example: `brew.coffee` Dot, - /// Title Case format: words are separated by spaces, each word capitalized. + /// `Title Case` format: words are separated by spaces, each word capitalized. /// /// Example: `Brew Coffee` Title, - /// lower case format: words are separated by spaces, all lowercase. + /// `lower case` format: words are separated by spaces, all lowercase. /// /// Example: `brew coffee` Lower, - /// UPPER CASE format: words are separated by spaces, all uppercase. + /// `UPPER CASE` format: words are separated by spaces, all uppercase. /// /// Example: `BREW COFFEE` Upper, @@ -187,14 +187,14 @@ impl ParserStyleNamingCase { S: Into<String> + From<String>, { match self { - ParserStyleNamingCase::Camel => just_fmt::camel_case!(s.into()).into(), - ParserStyleNamingCase::Pascal => just_fmt::pascal_case!(s.into()).into(), - ParserStyleNamingCase::Kebab => just_fmt::kebab_case!(s.into()).into(), - ParserStyleNamingCase::Snake => just_fmt::snake_case!(s.into()).into(), - ParserStyleNamingCase::Dot => just_fmt::dot_case!(s.into()).into(), - ParserStyleNamingCase::Title => just_fmt::title_case!(s.into()).into(), - ParserStyleNamingCase::Lower => just_fmt::lower_case!(s.into()).into(), - ParserStyleNamingCase::Upper => just_fmt::upper_case!(s.into()).into(), + Self::Camel => just_fmt::camel_case!(s.into()).into(), + Self::Pascal => just_fmt::pascal_case!(s.into()).into(), + Self::Kebab => just_fmt::kebab_case!(s.into()).into(), + Self::Snake => just_fmt::snake_case!(s.into()).into(), + Self::Dot => just_fmt::dot_case!(s.into()).into(), + Self::Title => just_fmt::title_case!(s.into()).into(), + Self::Lower => just_fmt::lower_case!(s.into()).into(), + Self::Upper => just_fmt::upper_case!(s.into()).into(), } } } @@ -238,7 +238,7 @@ pub const WINDOWS_STYLE: ParserStyle = ParserStyle { static GLOBAL_STYLE: OnceLock<ParserStyle<'static>> = OnceLock::new(); static GLOBAL_STYLE_SET: AtomicBool = AtomicBool::new(false); -impl<'a> ParserStyle<'a> { +impl ParserStyle<'_> { /// Sets the global parser style. /// /// This function can only be called once. Subsequent calls will have no effect. diff --git a/arg_picker/src/parselib/utils.rs b/arg_picker/src/parselib/utils.rs index 47c5b55..dc4e091 100644 --- a/arg_picker/src/parselib/utils.rs +++ b/arg_picker/src/parselib/utils.rs @@ -8,7 +8,7 @@ use crate::{ /// This function generates formatted flag strings (e.g., `-h`, `--help`) from the short flag, /// long flag, and any aliases defined in the argument info. The long flag and alias names /// are converted according to the style's naming case convention before being formatted. -#[inline(always)] +#[must_use] pub fn build_possible_flags(style: &ParserStyle, arg_info: &PickerArgInfo) -> Vec<String> { let mut possible_flags = vec![]; @@ -46,11 +46,7 @@ pub fn seek_single<'a>(raw_strs: &'a [&'a str]) -> Option<&'a str> { 1 => { let s = raw_strs[0]; let sep = ParserStyle::global_style().value_separator; - if let Some(pos) = s.rfind(sep) { - Some(&s[pos + 1..]) - } else { - Some(s) - } + s.rfind(sep).map_or(Some(s), |pos| Some(&s[pos + 1..])) } _ => Some(raw_strs[1]), } @@ -79,7 +75,7 @@ pub fn seek_end_of_options(args: &[MaskedArg], style: &ParserStyle) -> Option<us /// /// Returns the indices of matching arguments. #[must_use] -#[inline(always)] +#[inline] pub fn seek_eq(args: &[MaskedArg], string: &str, case_sensitive: bool) -> Vec<usize> { args.iter() .filter(|arg| { @@ -97,7 +93,7 @@ pub fn seek_eq(args: &[MaskedArg], string: &str, case_sensitive: bool) -> Vec<us /// /// Returns the indices of matching arguments. #[must_use] -#[inline(always)] +#[inline] pub fn seek_contains(args: &[MaskedArg], string: &str, case_sensitive: bool) -> Vec<usize> { args.iter() .filter(|arg| { @@ -115,7 +111,7 @@ pub fn seek_contains(args: &[MaskedArg], string: &str, case_sensitive: bool) -> /// /// Returns the indices of matching arguments. #[must_use] -#[inline(always)] +#[inline] pub fn seek_start_with(args: &[MaskedArg], string: &str, case_sensitive: bool) -> Vec<usize> { args.iter() .filter(|arg| { @@ -133,7 +129,7 @@ pub fn seek_start_with(args: &[MaskedArg], string: &str, case_sensitive: bool) - /// /// Returns the indices of matching arguments. #[must_use] -#[inline(always)] +#[inline] pub fn seek_end_with(args: &[MaskedArg], string: &str, case_sensitive: bool) -> Vec<usize> { args.iter() .filter(|arg| { @@ -151,7 +147,7 @@ pub fn seek_end_with(args: &[MaskedArg], string: &str, case_sensitive: bool) -> /// /// Returns the indices of matching arguments. #[must_use] -#[inline(always)] +#[inline] pub fn multi_seek_eq(args: &[MaskedArg], strings: &[&str], case_sensitive: bool) -> Vec<usize> { args.iter() .filter(|arg| { @@ -169,7 +165,7 @@ pub fn multi_seek_eq(args: &[MaskedArg], strings: &[&str], case_sensitive: bool) /// /// Returns the indices of matching arguments. #[must_use] -#[inline(always)] +#[inline] pub fn multi_seek_contains( args: &[MaskedArg], strings: &[&str], @@ -194,7 +190,7 @@ pub fn multi_seek_contains( /// /// Returns the indices of matching arguments. #[must_use] -#[inline(always)] +#[inline] pub fn multi_seek_start_with( args: &[MaskedArg], strings: &[&str], @@ -219,7 +215,7 @@ pub fn multi_seek_start_with( /// /// Returns the indices of matching arguments. #[must_use] -#[inline(always)] +#[inline] pub fn multi_seek_end_with( args: &[MaskedArg], strings: &[&str], @@ -245,10 +241,10 @@ pub fn multi_seek_end_with( /// This is useful for converting owned `String` vectors into borrowed `&str` slices /// for functions that take `&[&str]` or similar parameters. #[must_use] -#[inline(always)] +#[inline] #[doc(hidden)] pub fn vec_string_to_vec_str(input: &[String]) -> Vec<&str> { - input.iter().map(|s| s.as_str()).collect() + input.iter().map(String::as_str).collect() } /// Converts a `&Vec<String>` into a `Vec<&str>` by borrowing each string's slice. @@ -270,7 +266,7 @@ macro_rules! vec_string_slice { /// /// Returns `Some(index)` if the vector is non-empty, otherwise `None`. #[must_use] -#[inline(always)] +#[inline] pub fn get_seeked_first(seeked: Vec<usize>) -> Option<usize> { seeked.into_iter().next() } diff --git a/arg_picker/src/pickable/multi_pickable.rs b/arg_picker/src/pickable/multi_pickable.rs index 404c23b..c5cd810 100644 --- a/arg_picker/src/pickable/multi_pickable.rs +++ b/arg_picker/src/pickable/multi_pickable.rs @@ -35,7 +35,7 @@ pub trait MultiPickableWithBoundary: Sized { pub struct NoBoundary; impl BoundaryCheck for NoBoundary { - #[inline(always)] + #[inline] fn check_boundary(_raw: &str) -> bool { false } @@ -46,7 +46,7 @@ impl<T: SinglePickable> MultiPickableWithBoundary for Vec<T> { type Checker = NoBoundary; fn pick_multi(raw: Vec<String>) -> PickerArgResult<Self> { - let mut result = Vec::with_capacity(raw.len()); + let mut result = Self::with_capacity(raw.len()); for s in &raw { match T::pick_single(Some(s)) { PickerArgResult::Parsed(v) => result.push(v), @@ -87,6 +87,6 @@ where fn pick(raw_strs: &[&str]) -> PickerArgResult<Self> { let strs = strip_flag(raw_strs); let owned: Vec<String> = strs.iter().map(|&s| s.to_string()).collect(); - <Vec<T> as MultiPickableWithBoundary>::pick_multi(owned) + <Self as MultiPickableWithBoundary>::pick_multi(owned) } } diff --git a/arg_picker/src/picker.rs b/arg_picker/src/picker.rs index f722fb5..a7f0dfb 100644 --- a/arg_picker/src/picker.rs +++ b/arg_picker/src/picker.rs @@ -24,7 +24,8 @@ impl<'a> Picker<'a> { /// This is equivalent to calling `std::env::args().skip(1)`, which /// collects all arguments passed to the program except the first one /// (the executable path). - pub fn from_args() -> Picker<'a, ()> { + #[must_use] + pub fn from_args() -> Self { Self::from_args_skip(1) } @@ -34,7 +35,8 @@ impl<'a> Picker<'a> { /// This method is useful when you want more control over which arguments /// are included. For example, pass `skip = 2` to skip both the program /// name and the first argument. - pub fn from_args_skip(skip: usize) -> Picker<'a, ()> { + #[must_use] + pub fn from_args_skip(skip: usize) -> Self { let args = std::env::args().skip(skip).collect::<Vec<String>>(); Picker { route_phantom: PhantomData, @@ -48,6 +50,7 @@ impl<'a> Picker<'a> { /// while preserving the same underlying arguments. The route type is typically /// used to distinguish different parsing contexts or to carry compile-time /// state information through the picking chain. + #[must_use] pub fn with_route<NewRoute>(self) -> Picker<'a, NewRoute> where Self: Sized, @@ -76,8 +79,8 @@ pub enum PickerArgs<'a> { impl<'a> From<PickerArgs<'a>> for Vec<String> { fn from(value: PickerArgs<'a>) -> Self { match value { - PickerArgs::Slice(items) => items.iter().map(|s| s.to_string()).collect(), - PickerArgs::Vec(items) => items.into_iter().map(|s| s.to_string()).collect(), + PickerArgs::Slice(items) => items.iter().map(ToString::to_string).collect(), + PickerArgs::Vec(items) => items.into_iter().map(ToString::to_string).collect(), PickerArgs::Owned(items) => items, } } @@ -88,12 +91,12 @@ impl<'a> From<&'a PickerArgs<'a>> for Vec<&'a str> { match value { PickerArgs::Slice(items) => items.to_vec(), PickerArgs::Vec(items) => items.clone(), - PickerArgs::Owned(items) => items.iter().map(|s| s.as_str()).collect(), + PickerArgs::Owned(items) => items.iter().map(String::as_str).collect(), } } } -impl<'a> Default for PickerArgs<'a> { +impl Default for PickerArgs<'_> { fn default() -> Self { Self::Vec(vec![]) } @@ -101,7 +104,8 @@ impl<'a> Default for PickerArgs<'a> { impl<'a> PickerArgs<'a> { /// Returns the number of arguments. - pub fn len(&self) -> usize { + #[must_use] + pub const fn len(&self) -> usize { match self { PickerArgs::Slice(items) => items.len(), PickerArgs::Vec(items) => items.len(), @@ -110,11 +114,13 @@ impl<'a> PickerArgs<'a> { } /// Returns `true` if there are no arguments. - pub fn is_empty(&self) -> bool { + #[must_use] + pub const fn is_empty(&self) -> bool { self.len() == 0 } /// Returns an iterator over the arguments, yielding `&str` values. + #[must_use] pub fn iter(&'a self) -> PickerIter<'a> { match self { PickerArgs::Slice(items) => PickerIter::Slice(items.iter()), @@ -124,16 +130,17 @@ impl<'a> PickerArgs<'a> { } /// Returns a reference to the argument at `index`, if it exists. + #[must_use] pub fn get(&self, index: usize) -> Option<&str> { match self { PickerArgs::Slice(items) => items.get(index).copied(), PickerArgs::Vec(items) => items.get(index).copied(), - PickerArgs::Owned(items) => items.get(index).map(|s| s.as_str()), + PickerArgs::Owned(items) => items.get(index).map(String::as_str), } } } -impl<'a> Index<usize> for PickerArgs<'a> { +impl Index<usize> for PickerArgs<'_> { type Output = str; fn index(&self, index: usize) -> &Self::Output { @@ -185,7 +192,7 @@ impl<'a, Route> From<Vec<&'a str>> for Picker<'a, Route> { } } -impl<'a, Route> From<Vec<String>> for Picker<'a, Route> { +impl<Route> From<Vec<String>> for Picker<'_, Route> { fn from(value: Vec<String>) -> Self { Picker { route_phantom: PhantomData, @@ -196,37 +203,42 @@ impl<'a, Route> From<Vec<String>> for Picker<'a, Route> { impl<'a, Route> Picker<'a, Route> { /// Returns a reference to the internal `PickerArgs`. - pub fn args(&self) -> &PickerArgs<'a> { + #[must_use] + pub const fn args(&self) -> &PickerArgs<'a> { &self.args } /// Returns a mutable reference to the internal `PickerArgs`. - pub fn args_mut(&mut self) -> &mut PickerArgs<'a> { + pub const fn args_mut(&mut self) -> &mut PickerArgs<'a> { &mut self.args } /// Consumes `self` and returns the internal `PickerArgs`. + #[must_use] pub fn into_args(self) -> PickerArgs<'a> { self.args } /// Returns the number of arguments. - pub fn len(&self) -> usize { + #[must_use] + pub const fn len(&self) -> usize { self.args.len() } /// Returns `true` if there are no arguments. - pub fn is_empty(&self) -> bool { + #[must_use] + pub const fn is_empty(&self) -> bool { self.args.is_empty() } /// Returns an iterator over the arguments, yielding `&str` values. + #[must_use] pub fn iter(&'a self) -> PickerIter<'a> { self.args.iter() } } -impl<'a, Route> Index<usize> for Picker<'a, Route> { +impl Index<usize> for Picker<'_> { type Output = str; fn index(&self, index: usize) -> &Self::Output { @@ -234,7 +246,7 @@ impl<'a, Route> Index<usize> for Picker<'a, Route> { } } -impl<'a, Route> Index<usize> for &Picker<'a, Route> { +impl<'a, Route> Index<usize> for &'a Picker<'a, Route> { type Output = str; fn index(&self, index: usize) -> &Self::Output { @@ -266,22 +278,20 @@ impl<'a> Iterator for PickerIter<'a> { fn next(&mut self) -> Option<Self::Item> { match self { - PickerIter::Slice(iter) => iter.next().copied(), - PickerIter::Vec(iter) => iter.next().copied(), - PickerIter::Owned(iter) => iter.next().map(|s| s.as_str()), + PickerIter::Slice(iter) | PickerIter::Vec(iter) => iter.next().copied(), + PickerIter::Owned(iter) => iter.next().map(String::as_str), } } fn size_hint(&self) -> (usize, Option<usize>) { match self { - PickerIter::Slice(iter) => iter.size_hint(), - PickerIter::Vec(iter) => iter.size_hint(), + PickerIter::Slice(iter) | PickerIter::Vec(iter) => iter.size_hint(), PickerIter::Owned(iter) => iter.size_hint(), } } } -impl<'a> ExactSizeIterator for PickerIter<'a> {} +impl ExactSizeIterator for PickerIter<'_> {} impl<'a, Route> Picker<'a, Route> { /// Creates a `PickerPattern1` from the given arg to start a picking chain. @@ -473,7 +483,7 @@ impl<'a> IntoPicker<'a> for &'a [&'a str] { impl<'a> IntoPicker<'a> for &'a [String] { fn to_picker(self) -> Picker<'a, ()> { - let vec: Vec<&str> = self.iter().map(|s| s.as_str()).collect(); + let vec: Vec<&str> = self.iter().map(String::as_str).collect(); Picker { route_phantom: PhantomData, args: PickerArgs::Vec(vec), @@ -492,7 +502,7 @@ impl<'a> IntoPicker<'a> for Vec<&'a str> { impl<'a> IntoPicker<'a> for &'a Vec<String> { fn to_picker(self) -> Picker<'a, ()> { - let slice: Vec<&str> = self.iter().map(|s| s.as_str()).collect(); + let slice: Vec<&str> = self.iter().map(String::as_str).collect(); Picker { route_phantom: PhantomData, args: PickerArgs::Vec(slice), @@ -510,7 +520,7 @@ impl<'a> IntoPicker<'a> for Vec<String> { } impl<'a, Route> Picker<'a, Route> { - /// Build the PickerPattern via Arguments + /// Build the `PickerPattern` via Arguments pub fn build_pattern1<N>( args: PickerArgs<'a>, arg: &'a PickerArg<'a, N>, diff --git a/arg_picker/src/picker/patterns.rs b/arg_picker/src/picker/patterns.rs index 5806605..7058d47 100644 --- a/arg_picker/src/picker/patterns.rs +++ b/arg_picker/src/picker/patterns.rs @@ -33,8 +33,7 @@ internal_repeat!(1..=32 => { #[allow(clippy::type_complexity)] pub fn or<F>(mut self, func: F) -> Self where - F: FnMut() -> T$, - F: 'static, + F: 'static + FnMut() -> T$, { self.default_$ = Some(Box::new(func)); self @@ -65,8 +64,7 @@ internal_repeat!(1..=32 => { /// pub fn or_route<F>(mut self, func: F) -> Self where - F: FnMut() -> Route, - F: 'static, + F: 'static + FnMut() -> Route, { self.route_$ = Some(Box::new(func)); self @@ -110,8 +108,7 @@ internal_repeat!(1..=32 => { #[allow(clippy::type_complexity)] pub fn post<F>(mut self, func: F) -> Self where - F: FnMut(T$) -> T$, - F: 'static, + F: 'static + FnMut(T$) -> T$, { self.post_$ = Some(Box::new(func)); self @@ -167,7 +164,6 @@ internal_repeat!(1..32 => { where N: Pickable<'a>, F: FnMut() -> N + 'static, - F: 'static, { self.pick(arg).or(func) } @@ -197,7 +193,6 @@ internal_repeat!(1..32 => { where N: Pickable<'a>, F: FnMut() -> Route + 'static, - F: 'static, { self.pick(arg).or_route(func) } diff --git a/arg_picker/src/value/flag.rs b/arg_picker/src/value/flag.rs index c0673bd..6449d65 100644 --- a/arg_picker/src/value/flag.rs +++ b/arg_picker/src/value/flag.rs @@ -80,9 +80,9 @@ impl Flag { /// [`Active`]: Flag::Active /// [`Inactive`]: Flag::Inactive #[must_use] - #[inline(always)] + #[inline] pub fn bool(&self) -> bool { - *self == Flag::Active + *self == Self::Active } } @@ -101,7 +101,7 @@ impl PartialEq<Flag> for bool { impl From<bool> for Flag { fn from(value: bool) -> Self { - if value { Flag::Active } else { Flag::Inactive } + if value { Self::Active } else { Self::Inactive } } } @@ -127,19 +127,19 @@ impl Deref for Flag { fn deref(&self) -> &bool { match self { - Flag::Active => &true, - Flag::Inactive => &false, + Self::Active => &true, + Self::Inactive => &false, } } } impl Not for Flag { - type Output = Flag; + type Output = Self; - fn not(self) -> Flag { + fn not(self) -> Self { match self { - Flag::Active => Flag::Inactive, - Flag::Inactive => Flag::Active, + Self::Active => Self::Inactive, + Self::Inactive => Self::Active, } } } diff --git a/arg_picker/src/value/paths.rs b/arg_picker/src/value/paths.rs index 403d6cc..d64a09f 100644 --- a/arg_picker/src/value/paths.rs +++ b/arg_picker/src/value/paths.rs @@ -117,7 +117,7 @@ pub struct NoPath { path: PathBuf, } -/// Implements common trait impls (From, AsRef, Deref, DerefMut) for a path wrapper type. +/// Implements common trait impls (`From`, `AsRef`, `Deref`, `DerefMut`) for a path wrapper type. macro_rules! impl_path_traits { ($type:ident) => { impl From<PathBuf> for $type { @@ -227,12 +227,14 @@ impl DerefMut for RecursiveFiles { impl RecursiveFiles { /// Returns the number of file paths. - pub fn len(&self) -> usize { + #[must_use] + pub const fn len(&self) -> usize { self.paths.len() } /// Returns `true` if there are no file paths. - pub fn is_empty(&self) -> bool { + #[must_use] + pub const fn is_empty(&self) -> bool { self.paths.is_empty() } @@ -242,8 +244,17 @@ impl RecursiveFiles { } } -impl From<Vec<RecursiveFiles>> for RecursiveFiles { - fn from(value: Vec<RecursiveFiles>) -> Self { +impl<'a> IntoIterator for &'a RecursiveFiles { + type Item = &'a PathBuf; + type IntoIter = std::slice::Iter<'a, PathBuf>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl From<Vec<Self>> for RecursiveFiles { + fn from(value: Vec<Self>) -> Self { Self { paths: value.into_iter().flat_map(|r| r.paths).collect(), } diff --git a/arg_picker/src/value/vec_until.rs b/arg_picker/src/value/vec_until.rs index 04d87ce..6394cbf 100644 --- a/arg_picker/src/value/vec_until.rs +++ b/arg_picker/src/value/vec_until.rs @@ -22,6 +22,7 @@ pub struct VecUntil<T> { impl<T> VecUntil<T> { /// Consumes `self` and returns the underlying [`Vec<T>`]. + #[must_use] pub fn into_inner(self) -> Vec<T> { self.inner } @@ -29,7 +30,7 @@ impl<T> VecUntil<T> { impl<T> From<Vec<T>> for VecUntil<T> { fn from(v: Vec<T>) -> Self { - VecUntil { + Self { inner: v, _marker: PhantomData, } @@ -72,7 +73,7 @@ where PickerArgResult::Unparsed => {} } } - PickerArgResult::Parsed(VecUntil { + PickerArgResult::Parsed(Self { inner, _marker: PhantomData, }) @@ -97,7 +98,7 @@ where return positions; } - let start = if is_positional { 0 } else { 1 }; + let start = usize::from(!is_positional); if start >= positions.len() { return positions; } @@ -118,7 +119,7 @@ where fn pick(raw_strs: &[&str]) -> PickerArgResult<Self> { let strs = strip_flag(raw_strs); let owned: Vec<String> = strs.iter().map(|&s| s.to_string()).collect(); - <VecUntil<T> as MultiPickableWithBoundary>::pick_multi(owned) + <Self as MultiPickableWithBoundary>::pick_multi(owned) } } |
