Skip to content

Instantly share code, notes, and snippets.

@matematikaadit
Last active June 3, 2020 03:28
Show Gist options
  • Save matematikaadit/c4cfb1c5aba1ec0cd13baa9bba257a2f to your computer and use it in GitHub Desktop.
Save matematikaadit/c4cfb1c5aba1ec0cd13baa9bba257a2f to your computer and use it in GitHub Desktop.
Array literal, but using enum for indexing
#[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