imago/
macros.rs

1//! Helper macros.
2
3/// Implements `TryFrom` for enums from their numerical representation.
4macro_rules! numerical_enum {
5    (
6        $(#[$attr:meta])*
7        $vis:vis enum $enum_name:ident as $repr:tt {
8            $(
9                $(#[$id_attr:meta])*
10                $identifier:ident = $value:expr,
11            )+
12        }
13    ) => {
14        $(#[$attr])*
15        #[derive(Copy, Clone, Debug, Eq, PartialEq)]
16        #[repr($repr)]
17        $vis enum $enum_name {
18            $(
19                $(#[$id_attr])*
20                $identifier = $value,
21            )+
22        }
23
24        impl TryFrom<$repr> for $enum_name {
25            type Error = std::io::Error;
26
27            fn try_from(val: $repr) -> std::io::Result<Self> {
28                match val {
29                    $(x if x == $value => Ok($enum_name::$identifier),)*
30                    _ => Err(std::io::Error::new(
31                            std::io::ErrorKind::InvalidData,
32                            format!(
33                                "Invalid value for {}: {val:x}",
34                                stringify!($enum_name),
35                            ),
36                    )),
37                }
38            }
39        }
40    }
41}
42
43pub(crate) use numerical_enum;
44
45/// Implements a function as itself.
46///
47/// For traits that generalize interfaces that duplicate what we have on the struct itself, too.
48/// For example, we want to have `IoVectorTrait`, but not export it; requiring users to import that
49/// trait just for `.len()` is silly.  So `.len()` is implemented directly on both `IoVector` and
50/// `IoVectorMut` -- still, we want to have a generic `IoVectorTrait::len()`, too.  This is what
51/// this macro implements.
52macro_rules! passthrough_trait_fn {
53    { fn $name:ident($($param:ident: $type:ty),*) -> $ret:ty; } => {
54        fn $name($($param: $type),*) -> $ret {
55            Self::$name($($param),*)
56        }
57    };
58
59    { fn $name:ident(self$(, $param:ident: $type:ty)*) -> $ret:ty; } => {
60        passthrough_trait_fn! { fn $name(self: Self$(, $param: $type)*) -> $ret; }
61    };
62
63    { fn $name:ident(&self$(, $param:ident: $type:ty)*) -> $ret:ty; } => {
64        passthrough_trait_fn! { fn $name(self: &Self$(, $param: $type)*) -> $ret; }
65    };
66
67    { fn $name:ident(&mut self$(, $param:ident: $type:ty)*) -> $ret:ty; } => {
68        passthrough_trait_fn! { fn $name(self: &mut Self$(, $param: $type)*) -> $ret; }
69    };
70
71    { fn $name:ident(self$(, $param:ident: $type:ty)*); } => {
72        passthrough_trait_fn! { fn $name(self$(, $param: $type)*) -> (); }
73    };
74
75    { fn $name:ident(&self$(, $param:ident: $type:ty)*); } => {
76        passthrough_trait_fn! { fn $name(&self$(, $param: $type)*) -> (); }
77    };
78
79    { fn $name:ident(&mut self$(, $param:ident: $type:ty)*); } => {
80        passthrough_trait_fn! { fn $name(&mut self$(, $param: $type)*) -> (); }
81    };
82}
83
84pub(crate) use passthrough_trait_fn;