use core::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum ErrorKind {
UnknownArgument,
MissingValue,
MissingRequired,
DuplicateArgument,
TooManyPositionals,
TooManyArguments,
InvalidValue,
InvalidChoice,
EmptyFlag,
}
impl ErrorKind {
#[inline]
pub const fn as_str(&self) -> &'static str {
match self {
ErrorKind::UnknownArgument => "unknown argument",
ErrorKind::MissingValue => "missing value",
ErrorKind::MissingRequired => "missing required argument",
ErrorKind::DuplicateArgument => "duplicate argument",
ErrorKind::TooManyPositionals => "too many positional arguments",
ErrorKind::TooManyArguments => "too many argument definitions",
ErrorKind::InvalidValue => "invalid value",
ErrorKind::InvalidChoice => "invalid choice",
ErrorKind::EmptyFlag => "empty flag",
}
}
}
impl fmt::Display for ErrorKind {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct ParseError<'a> {
pub kind: ErrorKind,
pub token: Option<&'a str>,
pub name: Option<&'a str>,
pub offset: Option<usize>,
pub len: Option<usize>,
pub possible: Option<&'a [&'a str]>,
}
impl<'a> ParseError<'a> {
#[inline]
pub const fn new(kind: ErrorKind) -> Self {
Self {
kind,
token: None,
name: None,
offset: None,
len: None,
possible: None,
}
}
#[inline]
pub const fn with_token(mut self, token: &'a str) -> Self {
self.token = Some(token);
self
}
#[inline]
pub const fn with_name(mut self, name: &'a str) -> Self {
self.name = Some(name);
self
}
#[inline]
pub const fn with_offset(mut self, offset: usize) -> Self {
self.offset = Some(offset);
self
}
#[inline]
pub const fn with_len(mut self, len: usize) -> Self {
self.len = Some(len);
self
}
#[inline]
pub const fn with_possible(mut self, values: &'a [&'a str]) -> Self {
self.possible = Some(values);
self
}
}
impl<'a> fmt::Display for ParseError<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.kind {
ErrorKind::MissingValue => {
let arg = self.token.or(self.name).unwrap_or("unknown");
write!(f, "argument '{arg}' requires a value")
}
ErrorKind::UnknownArgument => {
let arg = self.token.or(self.name).unwrap_or("unknown");
write!(f, "unknown argument '{arg}'")
}
ErrorKind::MissingRequired => {
let arg = self.name.or(self.token).unwrap_or("unknown");
write!(f, "required argument '{arg}' was not provided")
}
ErrorKind::DuplicateArgument => {
let arg = self.token.or(self.name).unwrap_or("unknown");
write!(f, "argument '{arg}' was provided more than once")
}
ErrorKind::InvalidValue => {
let val = self.token.unwrap_or("unknown");
let arg = self.name.unwrap_or("unknown");
write!(f, "invalid value '{val}' for argument '{arg}'")
}
ErrorKind::InvalidChoice => {
let val = self.token.unwrap_or("unknown");
let arg = self.name.unwrap_or("unknown");
write!(f, "invalid value '{val}' for argument '{arg}'")?;
if let Some(values) = self.possible {
f.write_str(", expected one of: ")?;
for (i, v) in values.iter().enumerate() {
if i > 0 {
f.write_str(", ")?;
}
f.write_str(v)?;
}
}
Ok(())
}
ErrorKind::TooManyPositionals => {
let arg = self.token.unwrap_or("value");
write!(f, "unexpected positional argument '{arg}'")
}
ErrorKind::TooManyArguments => f.write_str("too many arguments provided"),
ErrorKind::EmptyFlag => f.write_str("empty flag '-'"),
}
}
}
#[cfg(feature = "std")]
impl<'a> std::error::Error for ParseError<'a> {}
pub type ParseResult<'a, T> = Result<T, ParseError<'a>>;