lexarg_error/
lib.rs

1//! Error type for use with lexarg
2//!
3//! Inspired by [lexopt](https://crates.io/crates/lexopt), `lexarg` simplifies the formula down
4//! further so it can be used for CLI plugin systems.
5//!
6//! ## Example
7//!
8//! ```no_run
9#![doc = include_str!("../examples/hello-error.rs")]
10//! ```
11
12#![cfg_attr(docsrs, feature(doc_auto_cfg))]
13#![warn(missing_debug_implementations)]
14#![warn(missing_docs)]
15#![warn(clippy::print_stderr)]
16#![warn(clippy::print_stdout)]
17
18/// Collect context for creating an error
19#[derive(Debug)]
20pub struct LexError<'a> {
21    msg: String,
22    within: Option<lexarg_parser::Arg<'a>>,
23    unexpected: Option<lexarg_parser::Arg<'a>>,
24}
25
26impl<'a> LexError<'a> {
27    /// Create a new error object from a printable error message.
28    #[cold]
29    pub fn msg<M>(message: M) -> Self
30    where
31        M: std::fmt::Display,
32    {
33        Self {
34            msg: message.to_string(),
35            within: None,
36            unexpected: None,
37        }
38    }
39
40    /// [`Arg`][lexarg_parser::Arg] the error occurred within
41    #[cold]
42    pub fn within(mut self, within: lexarg_parser::Arg<'a>) -> Self {
43        self.within = Some(within);
44        self
45    }
46
47    /// The failing [`Arg`][lexarg_parser::Arg]
48    #[cold]
49    pub fn unexpected(mut self, unexpected: lexarg_parser::Arg<'a>) -> Self {
50        self.unexpected = Some(unexpected);
51        self
52    }
53}
54
55impl<E> From<E> for LexError<'_>
56where
57    E: std::error::Error + Send + Sync + 'static,
58{
59    #[cold]
60    fn from(error: E) -> Self {
61        Self::msg(error)
62    }
63}
64
65impl std::fmt::Display for LexError<'_> {
66    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67        self.msg.fmt(formatter)?;
68        if let Some(unexpected) = &self.unexpected {
69            write!(formatter, ", found `")?;
70            match unexpected {
71                lexarg_parser::Arg::Short(short) => write!(formatter, "-{short}")?,
72                lexarg_parser::Arg::Long(long) => write!(formatter, "--{long}")?,
73                lexarg_parser::Arg::Escape(value) => write!(formatter, "{value}")?,
74                lexarg_parser::Arg::Value(value) | lexarg_parser::Arg::Unexpected(value) => {
75                    write!(formatter, "{}", value.to_string_lossy())?;
76                }
77            }
78            write!(formatter, "`")?;
79        }
80        if let Some(within) = &self.within {
81            write!(formatter, " when parsing `")?;
82            match within {
83                lexarg_parser::Arg::Short(short) => write!(formatter, "-{short}")?,
84                lexarg_parser::Arg::Long(long) => write!(formatter, "--{long}")?,
85                lexarg_parser::Arg::Escape(value) => write!(formatter, "{value}")?,
86                lexarg_parser::Arg::Value(value) | lexarg_parser::Arg::Unexpected(value) => {
87                    write!(formatter, "{}", value.to_string_lossy())?;
88                }
89            }
90            write!(formatter, "`")?;
91        }
92        Ok(())
93    }
94}
95
96#[doc = include_str!("../README.md")]
97#[cfg(doctest)]
98pub struct ReadmeDoctests;