Last active
June 3, 2020 03:28
-
-
Save matematikaadit/c4cfb1c5aba1ec0cd13baa9bba257a2f to your computer and use it in GitHub Desktop.
Array literal, but using enum for indexing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#[macro_export] | |
macro_rules! varmap { | |
($enum_ty:ty => $val_ty:ty ; $($enum:pat => $val:expr),+ $(,)?) => { | |
{ | |
const SIZE: usize = $crate::varmap!(@count $($val),*); | |
struct Wrapper([$val_ty; SIZE]); | |
impl std::ops::Index<$enum_ty> for Wrapper { | |
type Output = $val_ty; | |
#[allow(unreachable_patterns)] | |
fn index(&self, index: $enum_ty) -> &Self::Output { | |
let index: usize = $crate::varmap!{@into_match | |
saved { index } | |
repeat { $($enum),* } | |
num { 0 } | |
collect { } | |
}; | |
&self.0[index] | |
} | |
} | |
Wrapper([$($val),*]) | |
} | |
}; | |
// helper macro | |
// turn a list of pattern into match expression | |
// one | |
(@into_match | |
saved { $index:expr } | |
repeat { $x:pat } | |
num { $n:expr } | |
collect { $($tt:tt)* } | |
) => { | |
match $index { | |
$($tt)* | |
$x => $n, | |
_ => panic!("index not supported"), | |
} | |
}; | |
// recursive | |
(@into_match | |
saved { $index:expr } | |
repeat { $x:pat, $($enum:pat),* } | |
num { $n:expr } | |
collect { $($tt:tt)* } | |
) => { | |
$crate::varmap!{@into_match | |
saved { $index } | |
repeat { $($enum),* } | |
num { $n + 1 } | |
collect { $($tt)* $x => $n, } | |
} | |
}; | |
// for counting the number of term | |
(@count) => { 0usize }; | |
(@count $expr:expr) => { 1usize }; | |
(@count $($expr:expr, $_e:expr),*) => { $crate::varmap!(@count $($expr),*) << 1usize }; | |
(@count $odd:expr, $($expr:expr),*) => { $crate::varmap!(@count $($expr),*) | 1usize }; | |
} | |
#[cfg(test)] | |
mod tests { | |
use crate::varmap; | |
enum Foo { | |
A, B, C, | |
} | |
#[test] | |
fn should_index_properly() { | |
use Foo::*; | |
let xs = varmap![ Foo => i32; A => 42, B => 43, C => 44, ]; | |
assert_eq!(xs[A], 42); | |
assert_eq!(xs[B], 43); | |
assert_eq!(xs[C], 44); | |
} | |
#[test] | |
fn works_with_any_value_expression() { | |
use Foo::*; | |
fn random() -> i32 { | |
// imagine this is a random generator | |
// please ignore this hardcoded number | |
4 | |
} | |
let xs = varmap![ Foo => i32; A => random(), B => random(), C => random()]; | |
assert_eq!(xs[A], 4); | |
assert_eq!(xs[B], 4); | |
assert_eq!(xs[C], 4); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment