1#![no_std]
37
38#[doc(hidden)]
39pub use core;
40
41use core::fmt;
42
43#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
45pub struct ParseError(#[doc(hidden)] pub &'static &'static [&'static str]);
46
47impl fmt::Display for ParseError {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 match self.0 {
50 [] => f.write_str("Uninhabited type is impossible to parse"),
51 [first] => f.write_fmt(format_args!("Expected string `{first}`")),
52 [first, second] => f.write_fmt(format_args!("Expected `{first}` or `{second}`")),
53 [first, rest @ .., last] => {
54 f.write_fmt(format_args!("Expected one of `{first}`"))?;
55 for it in rest {
56 f.write_fmt(format_args!(", `{it}`"))?
57 }
58 f.write_fmt(format_args!(", or `{last}`"))
59 }
60 }
61 }
62}
63
64impl fmt::Debug for ParseError {
65 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66 f.debug_tuple("ParseError")
67 .field(&DebugWithDisplay(self))
68 .finish()
69 }
70}
71
72impl core::error::Error for ParseError {}
73
74struct DebugWithDisplay<T>(T);
75impl<T: fmt::Display> fmt::Debug for DebugWithDisplay<T> {
76 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77 self.0.fmt(f)
78 }
79}
80
81#[macro_export]
101macro_rules! strum {
102 (
103 $(#[$enum_meta:meta])*
104 $enum_vis:vis enum $enum_name:ident {
105 $(
106 $(#[$variant_meta:meta])*
107 $variant_name:ident = $string:literal $(| $alias:literal)* $(= $discriminant:expr)?
108 ),* $(,)?
109 }
110 ) => {
111 $(#[$enum_meta])*
112 $enum_vis enum $enum_name {
113 $(
114 $(#[$variant_meta])*
115 #[doc = $crate::core::concat!(" String representation: `", $string, "`")]
116 $variant_name $(= $discriminant)?,
117 )*
118 }
119 const _: () = {
120 use $crate::core;
121 impl core::fmt::Display for $enum_name {
122 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
123 fn as_str(e: &$enum_name) -> &core::primitive::str {
124 match *e {
125 $($enum_name::$variant_name => $string),*
126 }
127 }
128 core::fmt::Formatter::write_str(f, as_str(self))
129 }
130 }
131 impl core::str::FromStr for $enum_name {
132 type Err = $crate::ParseError;
133 fn from_str(s: &core::primitive::str) -> core::result::Result<Self, $crate::ParseError> {
134 const ALL: &[&core::primitive::str] = &[$($string),*];
135 match s {
136 $(
137 $string $(| $alias )* => core::result::Result::Ok(Self::$variant_name),
138 )*
139 _ => core::result::Result::Err($crate::ParseError(&ALL))
140 }
141 }
142 }
143 };
144 };
145}
146
147#[macro_export]
170macro_rules! with_error {
171 (
172 $(#[$enum_meta:meta])*
173 $enum_vis:vis enum $enum_name:ident {
174 $(
175 $(#[$variant_meta:meta])*
176 $variant_name:ident = $string:literal $(| $alias:literal)* $(= $discriminant:expr)?
177 ),* $(,)?
178 }
179 throws
180 $(#[$error_meta:meta])*
181 $error_name:ident $(;)?
182 ) => {
183 $(#[$enum_meta])*
184 $enum_vis enum $enum_name {
185 $(
186 $(#[$variant_meta])*
187 #[doc = $crate::core::concat!(" String representation: `", $string, "`")]
188 $variant_name $(= $discriminant)?,
189 )*
190 }
191
192 const _: () = {
193 use $crate::core;
194 impl core::fmt::Display for $enum_name {
195 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
196 fn as_str(e: &$enum_name) -> &core::primitive::str {
197 match *e {
198 $($enum_name::$variant_name => $string),*
199 }
200 }
201 core::fmt::Formatter::write_str(f, as_str(self))
202 }
203 }
204
205 impl core::str::FromStr for $enum_name {
206 type Err = $error_name;
207 fn from_str(s: &core::primitive::str) -> core::result::Result<Self, $error_name> {
208 match s {
209 $(
210 $string $(| $alias )* => core::result::Result::Ok(Self::$variant_name),
211 )*
212 _ => core::result::Result::Err($error_name)
213 }
214 }
215 }
216 };
217
218 $(#[$error_meta])*
219 #[doc = $crate::core::concat!(" Error returned when parsing [`", $crate::core::stringify!($enum_name), "`] from a string.")]
220 $enum_vis struct $error_name;
221
222 const _: () = {
223 use $crate::core;
224 impl core::fmt::Display for $error_name {
225 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
226 let all: &[&core::primitive::str] = &[
227 $($string),*
228 ];
229 let write_fmt = core::fmt::Formatter::write_fmt;
230 match all {
231 [] => core::fmt::Formatter::write_str(f, "Uninhabited type is impossible to parse"),
232 [first] => write_fmt(f, core::format_args!("Expected string `{}`", first)),
233 [first, second] => write_fmt(f, core::format_args!("Expected `{}` or `{}`", first, second)),
234 [first, rest @ .., last] => {
235 write_fmt(f, core::format_args!("Expected one of `{}`", first))?;
236 for it in rest {
237 write_fmt(f, core::format_args!(", `{}`", it))?
238 }
239 write_fmt(f, core::format_args!(", or `{}`", last))
240 }
241 }
242 }
243 }
244 impl core::fmt::Debug for $error_name {
245 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
246 use core::fmt;
247 struct DebugWithDisplay<T>(T);
248 impl<T: fmt::Display> fmt::Debug for DebugWithDisplay<T> {
249 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
250 self.0.fmt(f)
251 }
252 }
253 let mut f = fmt::Formatter::debug_tuple(f, core::stringify!($error_name));
254 fmt::DebugTuple::field(&mut f, &DebugWithDisplay(self));
255 fmt::DebugTuple::finish(&mut f)
256 }
257 }
258 impl core::error::Error for $error_name {}
259 };
260 };
261}