enum_field/
lib.rs

1/// Generates heterogeneous field accessors by enum variant values.
2/// `$name` - name of the generated macro
3///
4/// Cases:
5/// `$a` - access a field by one enum single variant value
6///
7///
8/// [a<1-3>] - comma-separated variants of the first enum
9///
10///
11/// [a<1-3>] - comma-separated variants of the first enum
12/// [b<1-3>] - comma-separated variants of the second enum
13#[macro_export]
14macro_rules! enum_field_match {
15    ($name:ident, $a0:ident, $a1:ident) => {
16        enum_field_match!($name, $a0, $a1, $);
17    };
18    ($name:ident, $a0:ident, $a1:ident, $d:tt) => {
19        ::paste::paste! {
20            #[macro_export]
21            macro_rules! $name {
22                ($this:ident,$a:expr, $body:expr) => {
23                    match  $a {
24                        ($a0) => $body(enum_field_use!($this . $a0)),
25                        ($a1) => $body(enum_field_use!($this . $a1)),
26                    }
27                };
28            }
29        }
30    };
31    ($name:ident, [$a0:ident, $a1:ident], $b0:ident) => {
32        enum_field_match!($name, [$a0, $a1], $b0, $);
33    };
34    ($name:ident, [$a0:ident, $a1:ident], $b0:ident, $d:tt) => {
35        ::paste::paste! {
36            #[macro_export]
37            macro_rules! $name {
38                ($this:ident,$a:expr,$b:expr, $body:expr) => {
39                    match  ($a,$b) {
40                        ($a0, $b0) => $body(enum_field_use!($this . $a0 _ $b0)),
41                        ($a1, $b0) => $body(enum_field_use!($this . $a1 _ $b0)),
42                    }
43                };
44            }
45        }
46    };
47    ($name:ident, [$a0:ident, $a1:ident], [$b0:ident,$b1:ident], $coproduct:ty) => {
48        enum_field_match!($name, [$a0, $a1], [$b0, $b1], $coproduct, $);
49    };
50    ($name:ident, [$a0:ident, $a1:ident], [$b0:ident,$b1:ident], $coproduct:ty, $d:tt) => {
51        /// Allows accessing a field on `this` by enum values (a, b) within the closure `body`
52        #[macro_export]
53        macro_rules! $name {
54            ($this:ident.$a:ident _ $b:ident <- |$param:ident| $body:expr) => {
55                match  ($a,$b) {
56                    ($a0, $b0) => {
57                        let $param = $coproduct::from(enum_field_use!($this . $a0 _ $b0));
58                        $body
59                    },
60                    ($a0, $b1) => {
61                        let $param = $coproduct::from(enum_field_use!($this . $a0 _ $b1));
62                        $body
63                    },
64                    ($a1, $b0) => {
65                        let $param = $coproduct::from(enum_field_use!($this . $a1 _ $b0));
66                        $body
67                    },
68                    ($a1, $b1) => {
69                        let $param = $coproduct::from(enum_field_use!($this . $a1 _ $b1));
70                        $body
71                    }
72                }
73            };
74            (mut $this:ident.$a:ident _ $b:ident <- |$param:ident| $body:expr) => {
75                match  ($a,$b) {
76                    ($a0, $b0) => {
77                        let mut $param = $coproduct::from(enum_field_use!(mut $this . $a0 _ $b0));
78                        $body
79                    },
80                    ($a0, $b1) => {
81                        let mut $param = $coproduct::from(enum_field_use!(mut $this . $a0 _ $b1));
82                        $body
83                    },
84                    ($a1, $b0) => {
85                        let mut $param = $coproduct::from(enum_field_use!(mut $this . $a1 _ $b0));
86                        $body
87                    },
88                    ($a1, $b1) => {
89                        let mut $param = $coproduct::from(enum_field_use!(mut $this . $a1 _ $b1));
90                        $body
91                    }
92                }
93            };
94        }
95    };
96    ($name:ident, [$a0:ident, $a1:ident], [$b0:ident,$b1:ident]) => {
97        enum_field_match!($name, [$a0, $a1], [$b0, $b1], $);
98    };
99    ($name:ident, [$a0:ident, $a1:ident], [$b0:ident,$b1:ident], $d:tt) => {
100            /// Allows accessing a field on `this` by enum values (a, b) within the closure `body`
101            #[macro_export]
102            macro_rules! $name {
103                ($this:ident.$a:ident _ $b:ident <- |$param:ident| $body:expr) => {
104                    match  ($a,$b) {
105                        ($a0, $b0) => {
106                            let $param = enum_field_use!($this . $a0 _ $b0);
107                            $body
108                        },
109                        ($a0, $b1) => {
110                            let $param = enum_field_use!($this . $a0 _ $b1);
111                            $body
112                        },
113                        ($a1, $b0) => {
114                            let $param = enum_field_use!($this . $a1 _ $b0);
115                            $body
116                        },
117                        ($a1, $b1) => {
118                            let $param = enum_field_use!($this . $a1 _ $b1);
119                            $body
120                        }
121                    }
122                };
123                (mut $this:ident.$a:ident _ $b:ident <- |$param:ident| $body:expr) => {
124                    match  ($a,$b) {
125                        ($a0, $b0) => {
126                            let mut $param = enum_field_use!(mut $this . $a0 _ $b0);
127                            $body
128                        },
129                        ($a0, $b1) => {
130                            let mut $param = enum_field_use!(mut $this . $a0 _ $b1);
131                            $body
132                        },
133                        ($a1, $b0) => {
134                            let mut $param = enum_field_use!(mut $this . $a1 _ $b0);
135                            $body
136                        },
137                        ($a1, $b1) => {
138                            let mut $param = enum_field_use!(mut $this . $a1 _ $b1);
139                            $body
140                        }
141                    }
142                };
143            }
144    };
145}
146
147// TODO: simplify $$ by using feature(macro_metavar_expr) after stabilization
148// NOTE: unfortunately could not expand depth and at the same time grab previous idents (tried tt muncher too)
149
150/// Combines one or more unit-enum idents to form a snake_case field name.
151#[macro_export]
152macro_rules! enum_field_use {
153    ($self:ident . $a:ident) => {
154        ::paste::paste! {
155            &$self.[<$a:snake>]
156        }
157    };
158    (mut $self:ident . $a:ident) => {
159        ::paste::paste! {
160            &mut $self.[<$a:snake>]
161        }
162    };
163    ($self:ident . $a:ident _ $b:ident) => {
164        ::paste::paste! {
165            &$self.[<$a:snake _ $b:snake>]
166        }
167    };
168    (mut $self:ident . $a:ident _ $b:ident) => {
169        ::paste::paste! {
170            &mut $self.[<$a:snake _ $b:snake>]
171        }
172    };
173    ($self:ident . $a:ident _ $b:ident _ $c:ident) => {
174        ::paste::paste! {
175            &$self.[<$a:snake _ $b:snake _ $c:snake>]
176        }
177    };
178    (mut $self:ident . $a:ident _ $b:ident _ $c:ident) => {
179        ::paste::paste! {
180            &mut $self.[<$a:snake _ $b:snake _ $c:snake>]
181        }
182    };
183}