diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-08-17 04:05:41 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-08-17 04:05:41 +0800 |
| commit | aa251efb87b561f62266628f06ad341253fbbdc5 (patch) | |
| tree | 7d2cc2f34f3e4a7282d8d6f0ec0f5ae4bfc87002 /mingling/src/parser/picker | |
| parent | c23c590330af83afb6e146bcd9b0a274b3689d22 (diff) | |
refactor!: remove legacy parser feature and migrate to picker
The legacy `parser` feature and its module tree (`mingling::parser`,
`Argument`, `Picker`, `Pickable`, etc.) have been fully removed and
replaced by the `picker` feature powered by `arg-picker`.
BREAKING CHANGE: Remove `parser` feature and use `picker` instead.
Migration guide: Replace `features = ["parser"]` with
`features = ["picker"]` and update API usage per the provided table.
Diffstat (limited to 'mingling/src/parser/picker')
| -rw-r--r-- | mingling/src/parser/picker/bools.rs | 143 | ||||
| -rw-r--r-- | mingling/src/parser/picker/builtin.rs | 113 | ||||
| -rw-r--r-- | mingling/src/parser/picker/path.rs | 145 | ||||
| -rw-r--r-- | mingling/src/parser/picker/path/rule.rs | 231 |
4 files changed, 0 insertions, 632 deletions
diff --git a/mingling/src/parser/picker/bools.rs b/mingling/src/parser/picker/bools.rs deleted file mode 100644 index bc9fd90..0000000 --- a/mingling/src/parser/picker/bools.rs +++ /dev/null @@ -1,143 +0,0 @@ -// Doc Not Optimize -use crate::parser::Pickable; - -/// Represents a boolean-like value with `Yes` and `No` variants. -/// -/// `Yes` can be parsed from command-line arguments using positive keywords such as `"y"` or `"yes"`, -/// and defaults to `No`. -#[derive(Debug, Default)] -#[repr(u8)] -pub enum Yes { - /// The affirmative/positive variant. - Yes, - /// The negative/default variant. - #[default] - No, -} - -impl From<bool> for Yes { - fn from(b: bool) -> Self { - if b { Self::Yes } else { Self::No } - } -} - -impl From<Yes> for bool { - fn from(val: Yes) -> Self { - match val { - Yes::Yes => true, - Yes::No => false, - } - } -} - -impl std::ops::Deref for Yes { - type Target = bool; - - fn deref(&self) -> &Self::Target { - static TRUE: bool = true; - static FALSE: bool = false; - match self { - Self::Yes => &TRUE, - Self::No => &FALSE, - } - } -} - -impl Yes { - #[must_use] - pub const fn is_yes(&self) -> bool { - matches!(self, Self::Yes) - } - - #[must_use] - pub const fn is_no(&self) -> bool { - matches!(self, Self::No) - } -} - -impl Pickable for Yes { - type Output = Self; - - fn pick(args: &mut crate::parser::Argument, flag: mingling_core::Flag) -> Option<Self::Output> { - let value = pick_bool(args, flag, &["y", "yes"]); - Some(value.into()) - } -} - -/// Represents a boolean-like value with `True` and `False` variants. -/// -/// `True` can be parsed from command-line arguments using positive keywords such as `"t"` or `"true"`, -/// and defaults to `False`. -#[derive(Debug, Default)] -#[repr(u8)] -pub enum True { - /// The affirmative/positive variant. - True, - /// The negative/default variant. - #[default] - False, -} - -impl From<bool> for True { - fn from(b: bool) -> Self { - if b { Self::True } else { Self::False } - } -} - -impl From<True> for bool { - fn from(val: True) -> Self { - match val { - True::True => true, - True::False => false, - } - } -} - -impl std::ops::Deref for True { - type Target = bool; - - fn deref(&self) -> &Self::Target { - static TRUE: bool = true; - static FALSE: bool = false; - match self { - Self::True => &TRUE, - Self::False => &FALSE, - } - } -} - -impl True { - #[must_use] - pub const fn is_true(&self) -> bool { - matches!(self, Self::True) - } - - #[must_use] - pub const fn is_false(&self) -> bool { - matches!(self, Self::False) - } -} - -impl Pickable for True { - type Output = Self; - - fn pick(args: &mut crate::parser::Argument, flag: mingling_core::Flag) -> Option<Self::Output> { - let value = pick_bool(args, flag, &["true", "t"]); - Some(value.into()) - } -} - -fn pick_bool( - args: &mut crate::parser::Argument, - flag: mingling_core::Flag, - positive: &[&str], -) -> bool { - let content = args.pick_argument(flag); - content.map_or_else( - || false, - |content| { - let s = content.as_str(); - positive.contains(&s) - }, - ) -} diff --git a/mingling/src/parser/picker/builtin.rs b/mingling/src/parser/picker/builtin.rs deleted file mode 100644 index 6f67c78..0000000 --- a/mingling/src/parser/picker/builtin.rs +++ /dev/null @@ -1,113 +0,0 @@ -// Doc Not Optimize -use size::Size; - -use crate::parser::{Argument, Pickable}; - -impl Pickable for String { - type Output = Self; - - fn pick(args: &mut crate::parser::Argument, flag: mingling_core::Flag) -> Option<Self::Output> { - args.pick_argument(flag) - } -} - -impl Pickable for Vec<String> { - type Output = Self; - - fn pick(args: &mut crate::parser::Argument, flag: mingling_core::Flag) -> Option<Self::Output> { - Some(args.pick_arguments(flag)) - } -} - -macro_rules! impl_pickable_for_number { - ($($t:ty),*) => { - $( - impl Pickable for $t { - type Output = $t; - - fn pick(args: &mut crate::parser::Argument, flag: mingling_core::Flag) -> Option<Self::Output> { - let picked = args.pick_argument(flag)?; - picked.parse().ok() - } - } - - impl Pickable for Vec<$t> { - type Output = Vec<$t>; - - fn pick(args: &mut crate::parser::Argument, flag: mingling_core::Flag) -> Option<Self::Output> { - let picked_vec = args.pick_arguments(flag); - let mut result = Vec::new(); - for picked in picked_vec { - if let Ok(parsed) = picked.parse() { - result.push(parsed); - } else { - return None; - } - } - Some(result) - } - } - )* - }; -} - -impl_pickable_for_number!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, f32, f64); - -impl Pickable for bool { - type Output = Self; - - fn pick(args: &mut crate::parser::Argument, flag: mingling_core::Flag) -> Option<Self::Output> { - Some(args.pick_flag(flag)) - } -} - -/// Special: parses a size string (e.g. "10MB") into a `usize` representing the number of bytes. -impl Pickable for usize { - type Output = Self; - - fn pick(args: &mut crate::parser::Argument, flag: mingling_core::Flag) -> Option<Self::Output> { - let picked = args.pick_argument(flag)?; - let size_parse = Size::from_str(picked.as_str()); - 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<usize>`. -impl Pickable for Vec<usize> { - type Output = Self; - - fn pick(args: &mut crate::parser::Argument, flag: mingling_core::Flag) -> Option<Self::Output> { - let picked_vec = args.pick_arguments(flag); - let mut result = Self::new(); - for picked in picked_vec { - let size_parse = Size::from_str(picked.as_str()); - match size_parse { - Ok(size) => result.push(usize::try_from(size.bytes()).unwrap_or(usize::MAX)), - Err(_) => return None, - } - } - Some(result) - } -} - -/// Special: dumps the remaining arguments into an `Argument` struct. -impl Pickable for Argument { - type Output = Self; - - fn pick( - args: &mut crate::parser::Argument, - _flag: mingling_core::Flag, - ) -> Option<Self::Output> { - Some(args.dump_remains().into()) - } -} - -/// Special: parses a single value of type `T` using the `Pickable` implementation for `T`, and wraps it in an `Option`. -impl<T: Pickable<Output = T> + Default> Pickable for Option<T> { - type Output = Self; - - fn pick(args: &mut Argument, flag: mingling_core::Flag) -> Option<Self::Output> { - let r = T::pick(args, flag); - Some(r) - } -} diff --git a/mingling/src/parser/picker/path.rs b/mingling/src/parser/picker/path.rs deleted file mode 100644 index 1caecfa..0000000 --- a/mingling/src/parser/picker/path.rs +++ /dev/null @@ -1,145 +0,0 @@ -// Doc Not Optimize -use std::path::{Path, PathBuf}; - -use crate::parser::Pickable; - -mod rule; -pub use rule::*; - -impl Pickable for Vec<PathBuf> { - type Output = Self; - - fn pick(args: &mut crate::parser::Argument, flag: mingling_core::Flag) -> Option<Self::Output> { - let raw: Vec<String> = args.pick_arguments(flag); - let paths = raw.into_iter().map(PathBuf::from).collect(); - Some(paths) - } -} - -impl Pickable for PathBuf { - type Output = Self; - - fn pick(args: &mut crate::parser::Argument, flag: mingling_core::Flag) -> Option<Self::Output> { - let raw: String = args.pick_argument(flag)?; - Some(Self::from(raw)) - } -} - -/// Provides path checking methods for [`Vec<PathBuf>`] -/// -/// This trait automatically provides implementations for `Into<Vec<PathBuf>>` -pub trait PathsChecker { - /// Check if all paths in the list satisfy the rule - fn is_all_passed(&self, rule: &PathCheckRule) -> bool - where - Self: Into<Vec<PathBuf>> + Clone, - { - check_paths(self.clone(), rule).is_ok() - } - - /// Classify paths into (Passed, Stripped) - /// - /// Passed means paths that satisfy the rule, Stripped means paths that do not. - fn classify(self, rule: &PathCheckRule) -> (Vec<PathBuf>, Vec<PathBuf>) - where - Self: Into<Vec<PathBuf>>, - { - let paths = self.into(); - let mut passed = Vec::new(); - let mut stripped = Vec::new(); - for path in paths { - if check_path(&path, rule).is_ok() { - passed.push(path); - } else { - stripped.push(path); - } - } - (passed, stripped) - } - - /// Return paths that satisfy the rule - fn passed(self, rule: &PathCheckRule) -> Vec<PathBuf> - where - Self: Into<Vec<PathBuf>>, - { - self.classify(rule).0 - } - - /// Return paths that do not satisfy the rule - fn stripped(self, rule: &PathCheckRule) -> Vec<PathBuf> - where - Self: Into<Vec<PathBuf>>, - { - self.classify(rule).1 - } -} - -/// Provides path checking methods for [`PathBuf`] -/// -/// This trait automatically provides implementations for `Into<PathBuf>` -pub trait PathChecker { - fn is_passed(&self, rule: &PathCheckRule) -> bool - where - Self: Into<PathBuf> + Clone, - { - check_path(self.clone(), rule).is_ok() - } -} - -impl<T: Into<Vec<PathBuf>>> PathsChecker for T {} -impl<T: Into<PathBuf>> PathChecker for T {} - -fn check_paths(path: impl Into<Vec<PathBuf>>, rule: &PathCheckRule) -> Result<(), ()> { - let paths = path.into(); - for p in &paths { - check_exist(p, rule)?; - check_type(p, rule)?; - } - - Ok(()) -} - -fn check_path(path: impl Into<PathBuf>, rule: &PathCheckRule) -> Result<(), ()> { - let p = path.into(); - check_exist(&p, rule)?; - check_type(&p, rule)?; - - Ok(()) -} - -fn check_exist(path: &Path, rule: &PathCheckRule) -> Result<(), ()> { - let Some(exist_check) = &rule.exist_check else { - return Ok(()); - }; - - match exist_check { - PathExistCheck::Exists => bool_to_result(path.exists()), - PathExistCheck::NotExists => bool_to_result(!path.exists()), - } -} - -fn check_type(path: &Path, rule: &PathCheckRule) -> Result<(), ()> { - let Some(type_check) = &rule.type_check else { - return Ok(()); - }; - - let is_dir = path.is_dir(); - let is_file = path.is_file(); - let is_symlink = path.is_symlink(); - - if type_check.allow_dir && is_dir { - return Ok(()); - } - if type_check.allow_file && is_file { - return Ok(()); - } - if type_check.allow_symlink && is_symlink { - return Ok(()); - } - - Err(()) -} - -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 deleted file mode 100644 index 5256f35..0000000 --- a/mingling/src/parser/picker/path/rule.rs +++ /dev/null @@ -1,231 +0,0 @@ -// Doc Not Optimize -/// Path check rule -#[derive(Default)] -pub struct PathCheckRule { - pub exist_check: Option<PathExistCheck>, - pub type_check: Option<PathTypeCheck>, -} - -/// Path existence check -pub enum PathExistCheck { - Exists, - NotExists, -} - -/// Path type check -pub struct PathTypeCheck { - /// Whether the path is allowed to be a file - pub allow_file: bool, - - /// Whether the path is allowed to be a directory - pub allow_dir: bool, - - /// Whether the path is allowed to be a symlink - pub allow_symlink: bool, -} - -impl PathCheckRule { - /// Creates a new `PathCheckRule` with default values - #[must_use] - pub const fn new() -> Self { - Self { - exist_check: None, - type_check: None, - } - } - - /// Allows the path to be a file - #[must_use] - pub const fn allow_file(self) -> Self { - match self.type_check { - Some(type_check) => Self { - type_check: Some(PathTypeCheck { - allow_file: true, - allow_dir: type_check.allow_dir, - allow_symlink: type_check.allow_symlink, - }), - ..self - }, - None => Self { - type_check: Some(PathTypeCheck { - allow_file: true, - allow_dir: false, - allow_symlink: false, - }), - ..self - }, - } - } - - /// Allows the path to be a directory - #[must_use] - pub const fn allow_dir(self) -> Self { - match self.type_check { - Some(type_check) => Self { - type_check: Some(PathTypeCheck { - allow_file: type_check.allow_file, - allow_dir: true, - allow_symlink: type_check.allow_symlink, - }), - ..self - }, - None => Self { - type_check: Some(PathTypeCheck { - allow_file: false, - allow_dir: true, - allow_symlink: false, - }), - ..self - }, - } - } - - /// Allows the path to be a symlink - #[must_use] - pub const fn allow_symlink(self) -> Self { - match self.type_check { - Some(type_check) => Self { - type_check: Some(PathTypeCheck { - allow_file: type_check.allow_file, - allow_dir: type_check.allow_dir, - allow_symlink: true, - }), - ..self - }, - None => Self { - type_check: Some(PathTypeCheck { - allow_file: false, - allow_dir: false, - allow_symlink: true, - }), - ..self - }, - } - } - - /// Denies the path from being a file - #[must_use] - pub const fn deny_file(self) -> Self { - match self.type_check { - Some(type_check) => Self { - type_check: Some(PathTypeCheck { - allow_file: false, - allow_dir: type_check.allow_dir, - allow_symlink: type_check.allow_symlink, - }), - ..self - }, - None => Self { - type_check: Some(PathTypeCheck { - allow_file: false, - allow_dir: true, - allow_symlink: true, - }), - ..self - }, - } - } - - /// Denies the path from being a directory - #[must_use] - pub const fn deny_dir(self) -> Self { - match self.type_check { - Some(type_check) => Self { - type_check: Some(PathTypeCheck { - allow_file: type_check.allow_file, - allow_dir: false, - allow_symlink: type_check.allow_symlink, - }), - ..self - }, - None => Self { - type_check: Some(PathTypeCheck { - allow_file: true, - allow_dir: false, - allow_symlink: true, - }), - ..self - }, - } - } - - /// Denies the path from being a symlink - #[must_use] - pub const fn deny_symlink(self) -> Self { - match self.type_check { - Some(type_check) => Self { - type_check: Some(PathTypeCheck { - allow_file: type_check.allow_file, - allow_dir: type_check.allow_dir, - allow_symlink: false, - }), - ..self - }, - None => Self { - type_check: Some(PathTypeCheck { - allow_file: true, - allow_dir: true, - allow_symlink: false, - }), - ..self - }, - } - } - - /// Requires the path to be a file (overrides type checks) - #[must_use] - pub const fn must_file(self) -> Self { - Self { - type_check: Some(PathTypeCheck { - allow_file: true, - allow_dir: false, - allow_symlink: false, - }), - ..self - } - } - - /// Requires the path to be a directory (overrides type checks) - #[must_use] - pub const fn must_dir(self) -> Self { - Self { - type_check: Some(PathTypeCheck { - allow_file: false, - allow_dir: true, - allow_symlink: false, - }), - ..self - } - } - - /// Requires the path to be a symlink (overrides type checks) - #[must_use] - pub const fn must_symlink(self) -> Self { - Self { - type_check: Some(PathTypeCheck { - allow_file: false, - allow_dir: false, - allow_symlink: true, - }), - ..self - } - } - - /// Requires the path to exist - #[must_use] - pub const fn must_exist(self) -> Self { - Self { - exist_check: Some(PathExistCheck::Exists), - ..self - } - } - - /// Requires the path to not exist - #[must_use] - pub const fn must_not_exist(self) -> Self { - Self { - exist_check: Some(PathExistCheck::NotExists), - ..self - } - } -} |
