improve error messages for the enum parameters

This commit is contained in:
dusk 2025-10-15 20:18:53 +00:00
parent 2fe747d704
commit 376f688ff4
No known key found for this signature in database
2 changed files with 125 additions and 104 deletions

View file

@ -1,5 +1,6 @@
#![feature(anonymous_lifetime_in_impl_trait)] #![feature(anonymous_lifetime_in_impl_trait)]
#![feature(round_char_boundary)] #![feature(round_char_boundary)]
#![feature(iter_intersperse)]
pub mod command; pub mod command;
pub mod flag; pub mod flag;

View file

@ -8,6 +8,55 @@ use smol_str::{SmolStr, format_smolstr};
use crate::token::{Token, TokenMatchResult}; use crate::token::{Token, TokenMatchResult};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ParameterKind {
OpaqueString,
OpaqueInt,
OpaqueStringRemainder,
MemberRef,
MemberRefs,
GroupRef,
GroupRefs,
SystemRef,
UserRef,
MessageRef,
ChannelRef,
GuildRef,
MemberPrivacyTarget,
GroupPrivacyTarget,
SystemPrivacyTarget,
PrivacyLevel,
Toggle,
Avatar,
ProxySwitchAction,
}
impl ParameterKind {
pub(crate) fn default_name(&self) -> &str {
match self {
ParameterKind::OpaqueString => "string",
ParameterKind::OpaqueInt => "number",
ParameterKind::OpaqueStringRemainder => "string",
ParameterKind::MemberRef => "target",
ParameterKind::MemberRefs => "targets",
ParameterKind::GroupRef => "target",
ParameterKind::GroupRefs => "targets",
ParameterKind::SystemRef => "target",
ParameterKind::UserRef => "target",
ParameterKind::MessageRef => "target",
ParameterKind::ChannelRef => "target",
ParameterKind::GuildRef => "target",
ParameterKind::MemberPrivacyTarget => "member_privacy_target",
ParameterKind::GroupPrivacyTarget => "group_privacy_target",
ParameterKind::SystemPrivacyTarget => "system_privacy_target",
ParameterKind::PrivacyLevel => "privacy_level",
ParameterKind::Toggle => "toggle",
ParameterKind::Avatar => "avatar",
ParameterKind::ProxySwitchAction => "proxy_switch_action",
}
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum ParameterValue { pub enum ParameterValue {
OpaqueString(String), OpaqueString(String),
@ -284,65 +333,44 @@ impl<P: Into<Parameter>> From<Skip<P>> for Parameter {
} }
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] macro_rules! impl_enum {
pub enum ParameterKind { ($name:ident ($pretty_name:expr): $($variant:ident),*) => {
OpaqueString, #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
OpaqueInt, pub enum $name {
OpaqueStringRemainder, $($variant),*
MemberRef,
MemberRefs,
GroupRef,
GroupRefs,
SystemRef,
UserRef,
MessageRef,
ChannelRef,
GuildRef,
MemberPrivacyTarget,
GroupPrivacyTarget,
SystemPrivacyTarget,
PrivacyLevel,
Toggle,
Avatar,
ProxySwitchAction,
}
impl ParameterKind {
pub(crate) fn default_name(&self) -> &str {
match self {
ParameterKind::OpaqueString => "string",
ParameterKind::OpaqueInt => "number",
ParameterKind::OpaqueStringRemainder => "string",
ParameterKind::MemberRef => "target",
ParameterKind::MemberRefs => "targets",
ParameterKind::GroupRef => "target",
ParameterKind::GroupRefs => "targets",
ParameterKind::SystemRef => "target",
ParameterKind::UserRef => "target",
ParameterKind::MessageRef => "target",
ParameterKind::ChannelRef => "target",
ParameterKind::GuildRef => "target",
ParameterKind::MemberPrivacyTarget => "member_privacy_target",
ParameterKind::GroupPrivacyTarget => "group_privacy_target",
ParameterKind::SystemPrivacyTarget => "system_privacy_target",
ParameterKind::PrivacyLevel => "privacy_level",
ParameterKind::Toggle => "toggle",
ParameterKind::Avatar => "avatar",
ParameterKind::ProxySwitchAction => "proxy_switch_action",
} }
}
impl $name {
pub const PRETTY_NAME: &'static str = $pretty_name;
pub fn variants() -> impl Iterator<Item = Self> {
[$(Self::$variant),*].into_iter()
}
pub fn variants_str() -> impl Iterator<Item = &'static str> {
[$(Self::$variant.as_ref()),*].into_iter()
}
pub fn get_error() -> SmolStr {
let pretty_name = Self::PRETTY_NAME;
let vars = Self::variants_str().intersperse("/").collect::<SmolStr>();
format_smolstr!("invalid {pretty_name}, must be one of {vars}")
}
}
};
} }
pub enum MemberPrivacyTargetKind { impl_enum! {
Visibility, MemberPrivacyTargetKind("member privacy target"):
Name, Visibility,
Description, Name,
Banner, Description,
Avatar, Banner,
Birthday, Avatar,
Pronouns, Birthday,
Proxy, Pronouns,
Metadata, Proxy,
Metadata
} }
impl AsRef<str> for MemberPrivacyTargetKind { impl AsRef<str> for MemberPrivacyTargetKind {
@ -362,7 +390,6 @@ impl AsRef<str> for MemberPrivacyTargetKind {
} }
impl FromStr for MemberPrivacyTargetKind { impl FromStr for MemberPrivacyTargetKind {
// todo: figure out how to represent these errors best
type Err = SmolStr; type Err = SmolStr;
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
@ -377,19 +404,20 @@ impl FromStr for MemberPrivacyTargetKind {
"pronouns" => Ok(Self::Pronouns), "pronouns" => Ok(Self::Pronouns),
"proxy" => Ok(Self::Proxy), "proxy" => Ok(Self::Proxy),
"metadata" => Ok(Self::Metadata), "metadata" => Ok(Self::Metadata),
_ => Err("invalid member privacy target".into()), _ => Err(Self::get_error()),
} }
} }
} }
pub enum GroupPrivacyTargetKind { impl_enum! {
Name, GroupPrivacyTargetKind("group privacy target"):
Icon, Name,
Description, Icon,
Banner, Description,
List, Banner,
Metadata, List,
Visibility, Metadata,
Visibility
} }
impl AsRef<str> for GroupPrivacyTargetKind { impl AsRef<str> for GroupPrivacyTargetKind {
@ -419,21 +447,22 @@ impl FromStr for GroupPrivacyTargetKind {
"list" => Ok(Self::List), "list" => Ok(Self::List),
"metadata" => Ok(Self::Metadata), "metadata" => Ok(Self::Metadata),
"visibility" => Ok(Self::Visibility), "visibility" => Ok(Self::Visibility),
_ => Err("invalid group privacy target".into()), _ => Err(Self::get_error()),
} }
} }
} }
pub enum SystemPrivacyTargetKind { impl_enum! {
Name, SystemPrivacyTargetKind("system privacy target"):
Avatar, Name,
Description, Avatar,
Banner, Description,
Pronouns, Banner,
MemberList, Pronouns,
GroupList, MemberList,
Front, GroupList,
FrontHistory, Front,
FrontHistory
} }
impl AsRef<str> for SystemPrivacyTargetKind { impl AsRef<str> for SystemPrivacyTargetKind {
@ -466,15 +495,12 @@ impl FromStr for SystemPrivacyTargetKind {
"groups" | "gs" => Ok(Self::GroupList), "groups" | "gs" => Ok(Self::GroupList),
"front" | "fronter" | "fronters" => Ok(Self::Front), "front" | "fronter" | "fronters" => Ok(Self::Front),
"fronthistory" | "fh" | "switches" => Ok(Self::FrontHistory), "fronthistory" | "fh" | "switches" => Ok(Self::FrontHistory),
_ => Err("invalid system privacy target".into()), _ => Err(Self::get_error()),
} }
} }
} }
pub enum PrivacyLevelKind { impl_enum!(PrivacyLevelKind("privacy level"): Public, Private);
Public,
Private,
}
impl AsRef<str> for PrivacyLevelKind { impl AsRef<str> for PrivacyLevelKind {
fn as_ref(&self) -> &str { fn as_ref(&self) -> &str {
@ -492,15 +518,20 @@ impl FromStr for PrivacyLevelKind {
match s { match s {
"public" => Ok(PrivacyLevelKind::Public), "public" => Ok(PrivacyLevelKind::Public),
"private" => Ok(PrivacyLevelKind::Private), "private" => Ok(PrivacyLevelKind::Private),
_ => Err("invalid privacy level".into()), _ => Err(Self::get_error()),
} }
} }
} }
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)] impl_enum!(Toggle("toggle"): On, Off);
pub enum Toggle {
On, impl AsRef<str> for Toggle {
Off, fn as_ref(&self) -> &str {
match self {
Self::On => "on",
Self::Off => "off",
}
}
} }
impl FromStr for Toggle { impl FromStr for Toggle {
@ -513,10 +544,9 @@ impl FromStr for Toggle {
Some(TokenMatchResult::MatchedValue) Some(TokenMatchResult::MatchedValue)
) )
}; };
[Self::On, Self::Off] Self::variants()
.into_iter()
.find(matches_self) .find(matches_self)
.ok_or_else(|| SmolStr::new("invalid toggle, must be on/off")) .ok_or_else(Self::get_error)
} }
} }
@ -538,12 +568,7 @@ impl Into<bool> for Toggle {
} }
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] impl_enum!(ProxySwitchAction("proxy switch action"): New, Add, Off);
pub enum ProxySwitchAction {
New,
Add,
Off,
}
impl AsRef<str> for ProxySwitchAction { impl AsRef<str> for ProxySwitchAction {
fn as_ref(&self) -> &str { fn as_ref(&self) -> &str {
@ -559,14 +584,9 @@ impl FromStr for ProxySwitchAction {
type Err = SmolStr; type Err = SmolStr;
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
[ Self::variants()
ProxySwitchAction::New, .find(|action| action.as_ref() == s)
ProxySwitchAction::Add, .ok_or_else(Self::get_error)
ProxySwitchAction::Off,
]
.into_iter()
.find(|action| action.as_ref() == s)
.ok_or_else(|| SmolStr::new("invalid proxy switch action, must be new/add/off"))
} }
} }