1macro_rules! impl_error {
18 (
19 individual:
38 $(#[$attributes:meta])*
39 $struct_vis:vis struct $struct_name:ident
40 $(( $($e_vis:vis $e_ty:ty),+ $(,)? ))? $(;$($_a:lifetime)?)? $({ $($(#[$f_attr:meta])* $f_vis:vis $f_name:ident: $f_ty:ty),+ $(,)? })? $DOC_NAME:ident = $doc_str:literal,
43 $self:ident + $fmt:ident => $display_expr:expr
44 $(,)?
45 ) => {
46 $(#[$attributes])*
47 $crate::CONST! { pub(crate) $DOC_NAME = $doc_str; }
48
49 $(#[$attributes])*
50 #[doc = crate::TAG_ERROR!()]
51 #[doc = $DOC_NAME!()]
52 #[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq)]
53 $struct_vis struct $struct_name
54 $(( $($e_vis $e_ty),+ ) )? $(; $($_a)?)? $({ $( $(#[$f_attr])* $f_vis $f_name: $f_ty),+ })? $(#[$attributes])*
58 impl $crate::Display for $struct_name {
59 fn fmt(&$self, $fmt: &mut $crate::Formatter<'_>) -> $crate::FmtResult<()> {
60 $display_expr
61 }
62 }
63 $(#[$attributes])*
64 impl $crate::Error for $struct_name {}
65 $(#[$attributes])*
66 impl $crate::ExtError for $struct_name {
67 type Kind = ();
68 fn error_eq(&self, other: &Self) -> bool { self == other }
69 fn error_kind(&self) -> Self::Kind {}
70 }
71 };
72 (
73 composite: fmt($fmt:ident)
77 $(#[$enum_attr:meta])*
78 $vis:vis enum $composite_error_name:ident { $(
79 $(#[$variant_attr:meta])*
80 $DOC_VARIANT:ident:
81 $variant_name:ident
82 $(( $($e_name:ident| $e_numb:literal: $e_ty:ty),+ ))? $({ $($(#[$f_attr:meta])* $f_name:ident: $f_ty:ty),+ })? => $individual_error_name:ident
85 $(( $($e_display_expr:expr),+ ))? $({ $($f_display_name:ident: $f_display_exp:expr),+ })? ),+ $(,)? }
88 ) => {
89 #[doc = crate::TAG_ERROR_COMPOSITE!()]
90 $(#[$enum_attr])*
91 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
92 $vis enum $composite_error_name { $(
93 $(#[$variant_attr])*
94 #[doc = $DOC_VARIANT!()]
95 $variant_name
96 $(( $($e_ty),+ ))? $({ $($(#[$f_attr])* $f_name: $f_ty),+ })? ),+ }
99
100 impl $crate::Error for $composite_error_name {}
102 impl $crate::ExtError for $composite_error_name {
103 type Kind = ();
104 fn error_eq(&self, other: &Self) -> bool { self == other }
105 fn error_kind(&self) -> Self::Kind {}
106 }
107 impl $crate::Display for $composite_error_name {
108 fn fmt(&self, $fmt: &mut $crate::Formatter<'_>) -> $crate::FmtResult<()> {
109 match self { $(
110 $(#[$variant_attr])*
111 $composite_error_name::$variant_name
112 $(( $($e_name),+ ))? $({ $($f_name),+ })? =>
115 $crate::Display::fmt(&$individual_error_name
116 $(( $($e_display_expr),+ ))? $({ $($f_display_name: $f_display_exp),+})? , $fmt),
119 )+ }
120 }
121 }
122 $(
125 $(#[$variant_attr])*
126 $crate::impl_error! { from(_f): $individual_error_name, for: $composite_error_name
127 => $variant_name
128 $(( $($e_name, $crate::field_of![_f, $e_numb] ),+ ))? $({ $($f_name, $crate::field_of![_f, $f_name] ),+ })? }
131 )+
132 };
133 (
134 from($fn_arg:ident): $from_individual:ident, for: $for_composite:ident
137 => $variant_name:ident
138 $(( $($e_name:ident, $e_expr:expr),+ ))? $({ $($f_name:ident, $f_expr:expr),+ })? $(,)? ) => {
141 $crate::paste! {
142 impl $for_composite {
143 #[doc = "*const* version of `From<" $from_individual "> for " $for_composite "`."]
144 #[allow(dead_code, reason = "seldomly used")]
145 pub const fn [<from_ $from_individual:snake:lower>]($fn_arg: $from_individual)
147 -> $for_composite {
148 $for_composite::$variant_name
149 $(( $($e_expr),+ ))? $({ $($f_name: $f_expr),+ })? }
152 }
153 }
154
155 impl From<$from_individual> for $for_composite {
162 fn from($fn_arg: $from_individual) -> $for_composite {
163 $for_composite::$variant_name
164 $(( $($e_expr),+ ))? $({ $($f_name: $f_expr),+ })? }
167 }
168 impl TryFrom<$for_composite> for $from_individual {
179 type Error = crate::FailedErrorConversion;
180 fn try_from($fn_arg: $for_composite) -> Result<$from_individual, Self::Error> {
181 match $fn_arg {
182 $for_composite::$variant_name
183 $(( $($e_name),+ ))? $({ $($f_name),+ })? => Ok($from_individual
186 $(( $($e_name),+ ))? $({ $($f_name),+ })? ),
189 #[allow(unreachable_patterns)]
190 _ => Err(crate::FailedErrorConversion)
191 }
192 }
193 }
194 };
195 (
196 composite: from($fn_arg:ident): $from_subset:ident, for: $for_superset:ident { $(
200 $from_variant:ident
201 $(( $($from_elem:ident),+ ))? $({ $($from_field:ident),+ })? => $for_variant:ident
204 $(( $($for_elem:ident),+ ))? $({ $($for_field:ident),+ })? ),+ $(,)? }
207 ) => {
208 impl From<$from_subset> for $for_superset {
209 fn from($fn_arg: $from_subset) -> $for_superset { match $fn_arg { $(
210 $from_subset::$from_variant
211 $(( $($from_elem),+ ))? $({ $($from_field),+ })? => $for_superset::$for_variant
214 $(( $($for_elem),+ ))? $({ $($for_field),+ })? ),+ } }
217 }
218 impl TryFrom<$for_superset> for $from_subset {
219 type Error = crate::FailedErrorConversion;
220 fn try_from($fn_arg: $for_superset)
221 -> Result<$from_subset, crate::FailedErrorConversion> { match $fn_arg { $(
222 $for_superset::$for_variant
223 $(( $($for_elem),+ ))? $({ $($for_field),+ })? => Ok($from_subset::$from_variant
226 $(( $($from_elem),+ ))? $({ $($from_field),+ })? ),)+
229 _ => Err(crate::FailedErrorConversion)
230 }
231 }
232 }
233 };
234}
235pub(crate) use impl_error;
236
237#[cfg(test)]
238mod tests {
239 use super::impl_error;
240
241 #[test]
242 fn impl_error() {
243 impl_error! { individual: pub struct UnitStruct;
246 DOC_UNIT_STRUCT = "docstring", self+f => write!(f, "display"),
247 }
248 impl_error! { individual: pub struct SingleElement(pub(crate) Option<u8>);
249 DOC_SINGLE_ELEMENT = "docstring", self+f => write!(f, "display"),
250 }
251 impl_error! { individual: pub struct MultipleElements(pub i32, u32,);
252 DOC_MULTI_ELEMENT = "docstring", self+f => write!(f, "display")
253 }
254 impl_error! { individual: pub struct StructFields {
255 #[doc = "field1"] pub f1: bool,
256 #[doc = "field2"] f2: Option<char>
257 }
258 DOC_STRUCT_FIELDS = "docstring", self+f => write!(f, "display")
259 }
260
261 impl_error! { composite: fmt(f)
265 pub enum CompositeSuperset {
267 DOC_UNIT_STRUCT: SuperUnit => UnitStruct,
268 DOC_SINGLE_ELEMENT: SuperSingle(i|0: Option<u8>) => SingleElement(*i),
269 DOC_MULTI_ELEMENT: SuperMultiple(i|0: i32, j|1: u32) => MultipleElements(*i, *j),
270 DOC_STRUCT_FIELDS: SuperStruct { f1: bool, f2: Option<char> }
271 => StructFields { f1: *f1, f2: *f2 },
272 }
273 }
274 impl_error! { composite: fmt(f)
275 pub enum CompositeSubset {
278 DOC_SINGLE_ELEMENT: SubSingle(i|0: Option<u8>) => SingleElement(*i),
279 DOC_MULTI_ELEMENT: SubMultiple(i|0: i32, j|1: u32) => MultipleElements(*i, *j),
280 DOC_STRUCT_FIELDS: SubStruct { f1: bool, f2: Option<char> }
281 => StructFields { f1: *f1, f2: *f2 },
282 }
283 }
284
285 impl_error! { composite: from(f): CompositeSubset, for: CompositeSuperset {
288 SubSingle(i) => SuperSingle(i),
289 SubMultiple(i, j) => SuperMultiple(i, j),
290 SubStruct { f1, f2 } => SuperStruct { f1, f2 },
291 }}
292
293 assert_eq![CompositeSuperset::SuperUnit, UnitStruct.into()];
296 assert![UnitStruct::try_from(CompositeSuperset::SuperUnit).is_ok()];
297 assert![UnitStruct::try_from(CompositeSuperset::SuperSingle(None)).is_err()];
298
299 assert_eq![CompositeSuperset::SuperSingle(Some(1)), SingleElement(Some(1)).into()];
300 assert![SingleElement::try_from(CompositeSuperset::SuperSingle(Some(2))).is_ok()];
301
302 assert_eq![CompositeSuperset::SuperMultiple(3, 5), MultipleElements(3, 5).into()];
303 assert![MultipleElements::try_from(CompositeSuperset::SuperMultiple(7, 13)).is_ok()];
304
305 assert_eq![
306 CompositeSuperset::SuperStruct { f1: true, f2: Some('a') },
307 StructFields { f1: true, f2: Some('a') }.into()
308 ];
309 assert![
310 StructFields::try_from(CompositeSuperset::SuperStruct { f1: false, f2: None }).is_ok()
311 ];
312
313 assert_eq![
316 CompositeSuperset::SuperSingle(Some(1)),
317 CompositeSubset::SubSingle(Some(1)).into()
318 ];
319 assert_eq![
320 CompositeSubset::try_from(CompositeSuperset::SuperSingle(Some(2))),
321 Ok(CompositeSubset::SubSingle(Some(2)))
322 ];
323
324 assert_eq![
325 CompositeSuperset::SuperMultiple(4, 6),
326 CompositeSubset::SubMultiple(4, 6).into()
327 ];
328 assert_eq![
329 CompositeSubset::try_from(CompositeSuperset::SuperMultiple(5, 7)),
330 Ok(CompositeSubset::SubMultiple(5, 7))
331 ];
332
333 assert_eq![
334 CompositeSuperset::SuperStruct { f1: true, f2: Some('z') },
335 CompositeSubset::SubStruct { f1: true, f2: Some('z') }.into()
336 ];
337 assert_eq![
338 CompositeSubset::try_from(CompositeSuperset::SuperStruct { f1: true, f2: None }),
339 Ok(CompositeSubset::SubStruct { f1: true, f2: None })
340 ];
341 }
342}