#![macro_use]
#[allow(unused_imports)]
#[macro_use] extern crate lazy_static;
pub use lazy_static::*;
pub use std::collections::HashMap;
pub use std::mem::discriminant;
pub use std::mem::Discriminant;
pub trait Meta<R> {
fn meta(&self) -> R;
}
#[macro_export]
macro_rules! meta {
($enum_type:ident, $return_type:ty;
$($enum_variant:ident, $return_value:expr);*
) => {
impl Meta<$return_type> for $enum_type {
fn meta(&self) -> $return_type {
match self {
$(
$enum_type::$enum_variant => {
$return_value
}
)*
}
}
}
};
($enum_type:ident, $return_type:ty;
$($enum_variant:ident, $return_value:expr);+ ;
) => {
meta!{
$enum_type, $return_type;
$( $enum_variant, $return_value );*
}
};
}
#[macro_export]
macro_rules! lazy_meta {
($enum_type:ident, $return_type:ty, $storage:ident;
$($enum_variant:ident, $return_expr:expr);*
) => {
lazy_static! {
static ref $storage: HashMap<Discriminant<$enum_type>,$return_type>
= {
let mut m = HashMap::new();
$(
m.insert(discriminant(&$enum_type::$enum_variant),
$return_expr);
)*
m
};
}
impl <'a> Meta<&'a $return_type> for $enum_type {
fn meta(&self) -> &'a $return_type {
$storage.get(&discriminant(&self)).unwrap()
}
}
#[allow(dead_code)]
impl $enum_type {
fn meta_check(&self) {
match self {
$(
$enum_type::$enum_variant => {}
),*
}
}
}
};
($enum_type:ident, $return_type:ty, $storage:ident;
$($enum_variant:ident, $return_expr:expr);+ ;
) => {
lazy_meta!{
$enum_type, $return_type, $storage;
$( $enum_variant, $return_expr );*
}
};
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_meta(){
enum Colour
{
Red,
Orange,
Green
}
meta!{
Colour, &'static str;
Red, "Red";
Orange, "Orange";
Green, "Green"
}
assert_eq!(Colour::Red.meta(), "Red");
assert_eq!(Colour::Orange.meta(), "Orange");
assert_eq!(Colour::Green.meta(), "Green");
}
#[test]
fn test_meta_complex_return_type(){
enum Colour
{
Red,
Orange,
Green
}
meta!{
Colour, (&'static str, i64);
Red, ("Red", 10);
Orange, ("Orange", 11);
Green, ("Green", 12)
}
assert_eq!(Colour::Red.meta(), ("Red", 10));
assert_eq!(Colour::Orange.meta(), ("Orange", 11));
assert_eq!(Colour::Green.meta(), ("Green", 12));
}
#[test]
fn test_meta_trailing_semi(){
enum Colour
{
Red,
Orange,
Green
}
meta!{
Colour, &'static str;
Red, "Red";
Orange, "Orange";
Green, "Green";
}
assert_eq!(Colour::Red.meta(), "Red");
assert_eq!(Colour::Orange.meta(), "Orange");
assert_eq!(Colour::Green.meta(), "Green");
}
#[test]
fn test_lazy_meta(){
enum Colour
{
Red,
Orange,
Green
}
lazy_meta!{
Colour, String, TEST1;
Red, "Red".to_string();
Orange, "Orange".to_string();
Green, "Green".to_string();
}
assert_eq!(Colour::Red.meta(), "Red");
assert_eq!(Colour::Orange.meta(), "Orange");
assert_eq!(Colour::Green.meta(), "Green");
}
}