aboutsummaryrefslogtreecommitdiff
path: root/mingling/src/parser/picker
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-08-17 04:05:41 +0800
committer魏曹先生 <1992414357@qq.com>2026-08-17 04:05:41 +0800
commitaa251efb87b561f62266628f06ad341253fbbdc5 (patch)
tree7d2cc2f34f3e4a7282d8d6f0ec0f5ae4bfc87002 /mingling/src/parser/picker
parentc23c590330af83afb6e146bcd9b0a274b3689d22 (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.rs143
-rw-r--r--mingling/src/parser/picker/builtin.rs113
-rw-r--r--mingling/src/parser/picker/path.rs145
-rw-r--r--mingling/src/parser/picker/path/rule.rs231
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
- }
- }
-}