refactor(command_parser): simplify how tokens are defined in commands

This commit is contained in:
dusk 2025-01-24 04:08:59 +09:00
parent f804e7629f
commit 071db3d6d6
No known key found for this signature in database
9 changed files with 114 additions and 76 deletions

View file

@ -90,27 +90,7 @@ impl Display for Command {
// (and something like &dyn Trait would require everything to be referenced which doesnt look nice anyway)
#[macro_export]
macro_rules! command {
([$($v:expr),+] => $cb:expr$(,)*) => {
($($v:expr),+ => $cb:expr$(,)*) => {
$crate::command::Command::new($crate::tokens!($($v),+), $cb)
};
($tokens:expr => $cb:expr$(,)*) => {
$crate::command::Command::new($tokens.clone(), $cb)
};
($tokens:expr, $($v:expr),+ => $cb:expr$(,)*) => {
$crate::command::Command::new($crate::concat_tokens!($tokens.clone(), [$($v),+]), $cb)
};
}
#[macro_export]
macro_rules! tokens {
($($v:expr),+$(,)*) => {
[$($crate::token::Token::from($v)),+]
};
}
#[macro_export]
macro_rules! concat_tokens {
($tokens:expr, [$($v:expr),+]$(,)*) => {
$tokens.clone().into_iter().chain($crate::tokens!($($v),+).into_iter()).collect::<Vec<_>>()
};
}

View file

@ -2,6 +2,8 @@ use std::{fmt::Debug, str::FromStr};
use smol_str::SmolStr;
use crate::token::Token;
#[derive(Debug, Clone)]
pub enum ParameterValue {
OpaqueString(String),
@ -180,10 +182,7 @@ impl FromStr for PrivacyLevelKind {
}
}
pub const ENABLE: [&str; 5] = ["on", "yes", "true", "enable", "enabled"];
pub const DISABLE: [&str; 5] = ["off", "no", "false", "disable", "disabled"];
#[derive(Debug, Clone, Eq, Hash, PartialEq)]
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
pub enum Toggle {
On,
Off,
@ -193,10 +192,20 @@ impl FromStr for Toggle {
type Err = SmolStr;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
ref s if ENABLE.contains(s) => Ok(Self::On),
ref s if DISABLE.contains(s) => Ok(Self::Off),
_ => Err("invalid toggle, must be on/off".into()),
let matches_self =
|toggle: &Self| matches!(Token::from(*toggle).try_match(Some(s)), Some(Ok(None)));
[Self::On, Self::Off]
.into_iter()
.find(matches_self)
.ok_or_else(|| SmolStr::new("invalid toggle, must be on/off"))
}
}
impl From<Toggle> for Token {
fn from(toggle: Toggle) -> Self {
match toggle {
Toggle::On => Self::from(("on", ["yes", "true", "enable", "enabled"])),
Toggle::Off => Self::from(("off", ["no", "false", "disable", "disabled"])),
}
}
}
@ -209,5 +218,3 @@ impl Into<bool> for Toggle {
}
}
}
pub const RESET: [&str; 3] = ["reset", "clear", "default"];

View file

@ -104,46 +104,96 @@ impl Token {
impl Display for Token {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Token::Empty => write!(f, ""),
Token::Value { name, .. } => write!(f, "{name}"),
Token::Parameter(param) => param.kind().format(f, param.name()),
Self::Empty => write!(f, ""),
Self::Value { name, .. } => write!(f, "{name}"),
Self::Parameter(param) => param.kind().format(f, param.name()),
}
}
}
impl<const L: usize> From<(&str, [&str; L])> for Token {
fn from((name, aliases): (&str, [&str; L])) -> Self {
Self::Value {
name: name.into(),
aliases: aliases.into_iter().map(SmolStr::new).collect::<Vec<_>>(),
}
}
}
impl From<&str> for Token {
fn from(name: &str) -> Self {
Token::Value {
name: SmolStr::new(name),
aliases: Vec::new(),
}
}
}
impl<const L: usize> From<[&str; L]> for Token {
fn from(value: [&str; L]) -> Self {
assert!(value.len() > 0, "can't create a Token::Value from nothing");
Token::Value {
name: value[0].into(),
aliases: value.into_iter().skip(1).map(SmolStr::new).collect::<Vec<_>>(),
}
fn from(value: &str) -> Self {
Self::from((value, []))
}
}
impl From<Parameter> for Token {
fn from(value: Parameter) -> Self {
Token::Parameter(value)
Self::Parameter(value)
}
}
impl From<ParameterKind> for Token {
fn from(value: ParameterKind) -> Self {
Token::from(Parameter::from(value))
Self::from(Parameter::from(value))
}
}
impl From<(&str, ParameterKind)> for Token {
fn from(value: (&str, ParameterKind)) -> Self {
Token::from(Parameter::from(value))
Self::from(Parameter::from(value))
}
}
#[derive(Debug, Clone)]
pub struct TokensIterator {
inner: Vec<Token>,
}
impl Iterator for TokensIterator {
type Item = Token;
fn next(&mut self) -> Option<Self::Item> {
(self.inner.len() > 0).then(|| self.inner.remove(0))
}
}
impl<T: Into<Token>> From<T> for TokensIterator {
fn from(value: T) -> Self {
Self {
inner: vec![value.into()],
}
}
}
impl<const L: usize> From<[Token; L]> for TokensIterator {
fn from(value: [Token; L]) -> Self {
Self {
inner: value.into_iter().collect(),
}
}
}
impl<const L: usize> From<[Self; L]> for TokensIterator {
fn from(value: [Self; L]) -> Self {
Self {
inner: value
.into_iter()
.map(|t| t.collect::<Vec<_>>())
.flatten()
.collect(),
}
}
}
impl From<Vec<Token>> for TokensIterator {
fn from(value: Vec<Token>) -> Self {
Self { inner: value }
}
}
#[macro_export]
macro_rules! tokens {
($($v:expr),+$(,)*) => {
$crate::token::TokensIterator::from([$($crate::token::TokensIterator::from($v.clone())),+])
};
}