Skip to main content

imago/macros/
mod.rs

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