Skip to content

Instantly share code, notes, and snippets.

@soulsource
Last active November 6, 2023 21:26
Show Gist options
  • Save soulsource/3b7e136f2e4ec039f4a1b1bfe72ce2da to your computer and use it in GitHub Desktop.
Save soulsource/3b7e136f2e4ec039f4a1b1bfe72ce2da to your computer and use it in GitHub Desktop.
Draft: tiny macro-by-example alternative to enum_map. Not as fast, but way simpler. Enum needs Eq and Sequence from enum_iterator.
use enum_iterator::Sequence;
macro_rules! enum_map {
($vis:vis $n:ident, $e:ty, $v:ty) => {
$vis struct $n {
elements : [$v; <$e>::CARDINALITY],
}
impl $n{
$vis fn new<F>(initializer : F) -> Self where F : Fn(&$e)->$v {
Self {
elements : {
let mut elem = <$e>::first();
//the unwrap() in the next line is fiiiiiine. It really is, the option can never be None in that context.
[(); <$e>::CARDINALITY].map(|_| { let r = initializer(elem.as_ref().unwrap()); elem = <$e>::next(elem.as_ref().unwrap()); r})
}
}
}
$vis fn get(&self, e : &$e) -> &$v {
//this isn't particularly fast, but hey, the goal here is type safety, not speed.
&self.elements[enum_iterator::all::<$e>().position(|v| &v == e).unwrap()]
}
}
};
}
@soulsource
Copy link
Author

soulsource commented Nov 6, 2023

Usage:

use enum_iterator::Sequence;

#[derive(Sequence, PartialEq, Eq)]
enum Test{
    Beer,
    Wine,
    Schnapps
}

enum_map!(TestMap, Test, i32);

#[test]
fn blah(){
    let x = TestMap::new(|e| match e {
        Test::Beer => 4,
        Test::Wine => 3,
        Test::Schnapps => 7,
    });
    assert_eq!(*x.get(&Test::Schnapps),7)
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment