Skip to main content

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            #[cfg_attr(feature = "macro-export", macro_export)]
21            macro_rules! $name {
22                ($this:expr,$a:expr, $body:expr) => {
23                    match  $a {
24                        ($a0) => $body($crate::enum_field_use!($this , $a0)),
25                        ($a1) => $body($crate::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            #[cfg_attr(feature = "macro-export", macro_export)]
37            macro_rules! $name {
38                ($this:expr,$a:expr,$b:expr, $body:expr) => {
39                    match  ($a,$b) {
40                        ($a0, $b0) => $body($crate::enum_field_use!($this , $a0 _ $b0)),
41                        ($a1, $b0) => $body($crate::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        #[cfg_attr(feature = "macro-export", macro_export)]
53        macro_rules! $name {
54            (mut $this:expr, $a:ident _ $b:ident , |$param:ident| $body:expr) => {
55                match  ($a,$b) {
56                    ($a0, $b0) => {
57                        let mut $param = $coproduct::from(enum_field_use!(mut $this , $a0 _ $b0));
58                        $body
59                    },
60                    ($a0, $b1) => {
61                        let mut $param = $coproduct::from(enum_field_use!(mut $this , $a0 _ $b1));
62                        $body
63                    },
64                    ($a1, $b0) => {
65                        let mut $param = $coproduct::from(enum_field_use!(mut $this , $a1 _ $b0));
66                        $body
67                    },
68                    ($a1, $b1) => {
69                        let mut $param = $coproduct::from(enum_field_use!(mut $this , $a1 _ $b1));
70                        $body
71                    }
72                }
73            };
74            ($this:expr,$a:ident _ $b:ident , |$param:ident| $body:expr) => {
75                match  ($a,$b) {
76                    ($a0, $b0) => {
77                        let $param = $coproduct::from($crate::enum_field_use!($this , $a0 _ $b0));
78                        $body
79                    },
80                    ($a0, $b1) => {
81                        let $param = $coproduct::from($crate::enum_field_use!($this , $a0 _ $b1));
82                        $body
83                    },
84                    ($a1, $b0) => {
85                        let $param = $coproduct::from($crate::enum_field_use!($this , $a1 _ $b0));
86                        $body
87                    },
88                    ($a1, $b1) => {
89                        let $param = $coproduct::from($crate::enum_field_use!($this , $a1 _ $b1));
90                        $body
91                    }
92                }
93            };
94        }
95    };
96    ($name:ident, $A:ty {$a0:ident, $a1:ident}, $B:ty {$b0:ident,$b1:ident}) => {
97        enum_field_match!($name, $A{$a0, $a1}, $B{$b0, $b1}, $);
98    };
99    ($name:ident, $A:ty {$a0:ident, $a1:ident}, $B:ty {$b0:ident,$b1:ident}, $d:tt) => {
100            /// Allows accessing a field on `this` by enum values (a, b) within the closure `body`
101            #[cfg_attr(feature = "macro-export", macro_export)]
102            macro_rules! $name {
103                (mut $this:expr,$a:ident _ $b:ident , |$param:ident| $body:expr) => {
104                    match  ($a,$b) {
105                        ($a0, $b0) => {
106                            let mut $param = enum_field_use!(mut $this , $a0 _ $b0);
107                            $body
108                        },
109                        ($a0, $b1) => {
110                            let mut $param = enum_field_use!(mut $this , $a0 _ $b1);
111                            $body
112                        },
113                        ($a1, $b0) => {
114                            let mut $param = enum_field_use!(mut $this , $a1 _ $b0);
115                            $body
116                        },
117                        ($a1, $b1) => {
118                            let mut $param = enum_field_use!(mut $this , $a1 _ $b1);
119                            $body
120                        }
121                    }
122                };
123                (($this:expr, mut $that:expr), $a:ident _ $b:ident , |($param_this:ident, $param_that:ident)| $body:expr) => {
124                    match  ($a,$b) {
125                        ($a0, $b0) => {
126                            let $param_this = enum_field_use!($this , $a0 _ $b0);
127                            let mut $param_that = enum_field_use!(mut $that , $a0 _ $b0);
128                            $body
129                        },
130                        ($a0, $b1) => {
131                            let $param_this = enum_field_use!($this , $a0 _ $b1);
132                            let mut $param_that = enum_field_use!(mut $that , $a0 _ $b1);
133                            $body
134                        },
135                        ($a1, $b0) => {
136                            let $param_this = enum_field_use!($this , $a1 _ $b0);
137                            let mut $param_that = enum_field_use!(mut $that , $a1 _ $b0);
138                            $body
139                        },
140                        ($a1, $b1) => {
141                            let $param_this = enum_field_use!($this , $a1 _ $b1);
142                            let mut $param_that = enum_field_use!(mut $that , $a1 _ $b1);
143                            $body
144                        }
145                    }
146                };
147                ($this:expr,$a:ident _ $b:ident , |$param:ident| $body:expr) => {
148                    match  ($a,$b) {
149                        ($a0, $b0) => {
150                            let $param = $crate::enum_field_use!($this , $a0 _ $b0);
151                            $body
152                        },
153                        ($a0, $b1) => {
154                            let $param = $crate::enum_field_use!($this , $a0 _ $b1);
155                            $body
156                        },
157                        ($a1, $b0) => {
158                            let $param = $crate::enum_field_use!($this , $a1 _ $b0);
159                            $body
160                        },
161                        ($a1, $b1) => {
162                            let $param = $crate::enum_field_use!($this , $a1 _ $b1);
163                            $body
164                        }
165                    }
166                };
167            }
168
169            ::paste::paste! {
170                /// Constant product of all combinations of the enum variants
171                pub const [<$name:snake:upper>] : [($A, $B); 4] = [
172                    ($A::$a0, $B::$b0),
173                    ($A::$a0, $B::$b1),
174                    ($A::$a1, $B::$b0),
175                    ($A::$a1, $B::$b1),
176                ];
177            }
178    };
179}
180
181// TODO: simplify $$ by using feature(macro_metavar_expr) after stabilization
182// NOTE: unfortunately could not expand depth and at the same time grab previous idents (tried tt muncher too)
183
184/// Combines one or more unit-enum idents to form a snake_case field name.
185#[macro_export]
186macro_rules! enum_field_use {
187    (mut $self:expr, $a:ident) => {
188        ::paste::paste! {
189            &mut $self.[<$a:snake>]
190        }
191    };
192    (mut $self:expr, $a:ident _ $b:ident) => {
193        ::paste::paste! {
194            &mut $self.[<$a:snake _ $b:snake>]
195        }
196    };
197
198    (mut $self:expr, $a:ident _ $b:ident _ $c:ident) => {
199        ::paste::paste! {
200            &mut $self.[<$a:snake _ $b:snake _ $c:snake>]
201        }
202    };
203    ($self:expr, $a:ident) => {
204        ::paste::paste! {
205            &$self.[<$a:snake>]
206        }
207    };
208    ($self:expr, $a:ident _ $b:ident) => {
209        ::paste::paste! {
210            &$self.[<$a:snake _ $b:snake>]
211        }
212    };
213    ($self:expr, $a:ident _ $b:ident _ $c:ident) => {
214        ::paste::paste! {
215            &$self.[<$a:snake _ $b:snake _ $c:snake>]
216        }
217    };
218}