flood_tide/
err.rs

1//! Parse error module.
2//!
3//! # Examples
4//! ```
5//! use flood_tide::err::OptParseError;
6//! let err = OptParseError::invalid_option("abc");
7//! ```
8//!
9#[cfg(not(feature = "no_std"))]
10use std::fmt::{Display, Error, Formatter};
11#[cfg(not(feature = "no_std"))]
12use std::slice::Iter;
13
14#[cfg(feature = "no_std")]
15use core::fmt::{Display, Error, Formatter};
16#[cfg(feature = "no_std")]
17use core::slice::Iter;
18
19#[cfg(feature = "no_std")]
20use alloc::string::{String, ToString};
21#[cfg(feature = "no_std")]
22use alloc::vec::Vec;
23
24use crate::HelpVersion;
25
26#[derive(Debug, Clone, PartialEq, Eq)]
27pub enum OptParseErrorKind {
28    HelpMessage,
29    VersionMessage,
30    //
31    InvalidOption,
32    MissingOption,
33    //
34    #[cfg(feature = "option_argument")]
35    InvalidOptionArgument,
36    #[cfg(feature = "option_argument")]
37    UnexpectedOptionArgument,
38    #[cfg(feature = "option_argument")]
39    MissingOptionArgument,
40    //
41    #[cfg(feature = "argument")]
42    UnexpectedArgument,
43    #[cfg(feature = "argument")]
44    MissingArgument,
45    //
46    #[cfg(feature = "subcommand")]
47    InvalidSubcommand,
48    #[cfg(feature = "subcommand")]
49    MissingSubcommand,
50    //
51    #[cfg(feature = "abbreviate")]
52    AmbiguousOption,
53    #[cfg(all(feature = "abbreviate", feature = "subcommand"))]
54    AmbiguousSubcommand,
55}
56
57/// Single option parse error
58#[derive(Debug, PartialEq, Eq)]
59pub struct OptParseError {
60    kind: OptParseErrorKind,
61    desc1: String,
62    desc2: Option<String>,
63}
64
65impl HelpVersion for OptParseError {
66    fn is_help(&self) -> bool {
67        self.kind == OptParseErrorKind::HelpMessage
68    }
69    fn is_version(&self) -> bool {
70        self.kind == OptParseErrorKind::VersionMessage
71    }
72}
73
74impl OptParseError {
75    pub fn kind(&self) -> OptParseErrorKind {
76        self.kind.clone()
77    }
78    pub fn desc1_str(&self) -> &str {
79        self.desc1.as_str()
80    }
81}
82
83impl OptParseError {
84    #[inline(never)]
85    fn new_p1(a_kind: OptParseErrorKind, a_desc1: &str) -> Self {
86        Self {
87            kind: a_kind,
88            desc1: a_desc1.to_string(),
89            desc2: None,
90        }
91    }
92    #[cfg(any(feature = "option_argument", feature = "abbreviate"))]
93    #[inline(never)]
94    fn new_p2(a_kind: OptParseErrorKind, a_desc1: &str, a_desc2: &str) -> Self {
95        let mut r = Self::new_p1(a_kind, a_desc1);
96        r.desc2 = Some(a_desc2.to_string());
97        r
98    }
99    pub fn help_message(desc1: &str) -> Self {
100        Self::new_p1(OptParseErrorKind::HelpMessage, desc1)
101    }
102    pub fn version_message(desc1: &str) -> Self {
103        Self::new_p1(OptParseErrorKind::VersionMessage, desc1)
104    }
105    //
106    pub fn invalid_option(desc1: &str) -> Self {
107        Self::new_p1(OptParseErrorKind::InvalidOption, desc1)
108    }
109    pub fn missing_option(desc1: &str) -> Self {
110        Self::new_p1(OptParseErrorKind::MissingOption, desc1)
111    }
112    //
113    #[cfg(any(feature = "option_argument", feature = "dox"))]
114    pub fn invalid_option_argument(desc1: &str, desc2: &str) -> Self {
115        Self::new_p2(OptParseErrorKind::InvalidOptionArgument, desc1, desc2)
116    }
117    #[cfg(any(feature = "option_argument", feature = "dox"))]
118    pub fn unexpected_option_argument(desc1: &str, desc2: &str) -> Self {
119        Self::new_p2(OptParseErrorKind::UnexpectedOptionArgument, desc1, desc2)
120    }
121    #[cfg(any(feature = "option_argument", feature = "dox"))]
122    pub fn missing_option_argument(desc1: &str) -> Self {
123        Self::new_p1(OptParseErrorKind::MissingOptionArgument, desc1)
124    }
125    //
126    #[cfg(any(feature = "argument", feature = "dox"))]
127    pub fn unexpected_argument(desc1: &str) -> Self {
128        Self::new_p1(OptParseErrorKind::UnexpectedArgument, desc1)
129    }
130    #[cfg(any(feature = "argument", feature = "dox"))]
131    pub fn missing_argument(desc1: &str) -> Self {
132        Self::new_p1(OptParseErrorKind::MissingArgument, desc1)
133    }
134    //
135    #[cfg(any(feature = "subcommand", feature = "dox"))]
136    pub fn invalid_subcommand(desc1: &str) -> Self {
137        Self::new_p1(OptParseErrorKind::InvalidSubcommand, desc1)
138    }
139    #[cfg(any(feature = "subcommand", feature = "dox"))]
140    pub fn missing_subcommand(desc1: &str) -> Self {
141        Self::new_p1(OptParseErrorKind::MissingSubcommand, desc1)
142    }
143    //
144    #[cfg(any(feature = "abbreviate", feature = "dox"))]
145    pub fn ambiguous_option(desc1: &str, desc2: &str) -> Self {
146        Self::new_p2(OptParseErrorKind::AmbiguousOption, desc1, desc2)
147    }
148    #[cfg(any(all(feature = "abbreviate", feature = "subcommand"), feature = "dox"))]
149    pub fn ambiguous_subcommand(desc1: &str, desc2: &str) -> Self {
150        Self::new_p2(OptParseErrorKind::AmbiguousSubcommand, desc1, desc2)
151    }
152}
153
154impl Display for OptParseError {
155    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
156        use self::OptParseErrorKind::*;
157        //
158        let msg: &str = match self.kind {
159            HelpMessage | VersionMessage => {
160                return write!(fmt, "{}", &self.desc1);
161            }
162            //
163            InvalidOption => "Invalid option",
164            MissingOption => "Missing option",
165            //
166            #[cfg(feature = "option_argument")]
167            InvalidOptionArgument => "Invalid option argument",
168            #[cfg(feature = "option_argument")]
169            UnexpectedOptionArgument => "Unexpected option argument",
170            #[cfg(feature = "option_argument")]
171            MissingOptionArgument => "Missing option argument",
172            //
173            #[cfg(feature = "argument")]
174            UnexpectedArgument => "Unexpected argument",
175            #[cfg(feature = "argument")]
176            MissingArgument => "Missing argument",
177            //
178            #[cfg(feature = "subcommand")]
179            InvalidSubcommand => "Invalid subcommand",
180            #[cfg(feature = "subcommand")]
181            MissingSubcommand => "Missing subcommand",
182            //
183            #[cfg(feature = "abbreviate")]
184            AmbiguousOption => "Ambiguous option",
185            #[cfg(all(feature = "abbreviate", feature = "subcommand"))]
186            AmbiguousSubcommand => "Ambiguous subcommand",
187        };
188        match self.desc2 {
189            Some(ref s) => write!(fmt, "{}: {}: {}", msg, &self.desc1, &s),
190            None => write!(fmt, "{}: {}", msg, &self.desc1),
191        }
192    }
193}
194
195#[cfg(any(not(feature = "no_std"), feature = "dox"))]
196impl std::error::Error for OptParseError {}
197
198/// Multiple option parse errors
199#[derive(Debug, PartialEq, Eq)]
200pub struct OptParseErrors(Vec<OptParseError>);
201
202impl OptParseErrors {
203    pub fn new() -> OptParseErrors {
204        OptParseErrors(Vec::with_capacity(0))
205    }
206    pub fn is_empty(&self) -> bool {
207        self.0.is_empty()
208    }
209    pub fn len(&self) -> usize {
210        self.0.len()
211    }
212    pub fn push(&mut self, e: OptParseError) {
213        self.0.push(e)
214    }
215    pub fn iter(&self) -> Iter<'_, OptParseError> {
216        self.0.iter()
217    }
218    pub fn append(&mut self, other: Self) {
219        self.0.extend(other.0)
220    }
221}
222impl Default for OptParseErrors {
223    fn default() -> Self {
224        Self::new()
225    }
226}
227impl Display for OptParseErrors {
228    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
229        use std::fmt::Write;
230        //
231        if self.is_empty() {
232            write!(fmt, "")
233        } else {
234            let mut s = String::new();
235            for err in self.iter() {
236                let _ = writeln!(s, "{err}");
237            }
238            write!(fmt, "{}", &s[0..(s.len() - 1)])
239        }
240    }
241}
242#[cfg(any(not(feature = "no_std"), feature = "dox"))]
243impl std::error::Error for OptParseErrors {}