DanielKeep / rust-custom-derive

Custom derivation macro for Rust
Other
110 stars 17 forks source link

#[deriving(EnumKey)] - a C-like enum that enumerate variant types #17

Closed nielsle closed 8 years ago

nielsle commented 8 years ago

Given an enum it could be nice to have a macro to construct C-like enum that enumerates the variants. It could look like this

struct A{_x:f32}
struct B{_y:u32}

#[derive(EnumKey(FooKey))]
enum Foo {
    A(A), 
    B(B)
}

fn main() {
    let _a = Foo::A(A {_x:1.0});
    let _b = Foo::B(B {_y:1});
    assert!(_a.key() == FooKey::A);
    assert!(_b.key() == FooKey::B);
}

The following code could be derived behind the scenes

pub trait Key {
    type Key;
    fn key(&self) -> Self::Key;
}

#[derive(Clone,Copy,Debug,PartialEq,Eq)]
enum FooKey {A,B}

impl Key for Foo {
    type Key=FooKey;
    fn key(&self) -> Self::Key {
        match self {
            &Foo::A(..) => FooKey::A,
            &Foo::B(..) => FooKey::B,
        }
    }
}

Gist: https://gist.github.com/4a8a0275d985e975cdeb8b438db5ff5f

DanielKeep commented 8 years ago

If it weren't for it being unstable, would discriminant_value do what you want? My concern with this being an enum is that you wouldn't be able to control what traits the key enum derives (and supporting that would be a pain).

Beyond that, I'm not sure what advantage having this gets you. Let's say you can get a variant-specific value... what do you do with it?

nielsle commented 8 years ago

Hmm, I think that you are right. I will close the issue for now.

But since you ask, I was looking for something like an enum map. Given a set of structs, construct a collection in which each of the chosen struct occurs at most once... something like an enum-map.

I wanted to use this for a type-safe entity component system in which each entity could only contain one kind of each component. But I should probably make some specialized macros instead of trying to add them to rust-custom-derive.

struct A {..} 
struct B {..} 
struct C {..} 

#[deriving(Debug, EnumKeys(Key)]
 enum Component {A(A), B(B), C(C)}
 let mut entity: BTMap<Key , Component> = BTMap::new();

let component = Component::B(B{..});
entity.insert(component.key(), component);

for key in Key::iter_variants() {
    if entity.contains(key) {
        let component = my_map.get(key);
        print!("Entity contains a component named {:?}. The value is {:?} ", key, *component);
    }
}
DanielKeep commented 8 years ago

Sounds like a job for https://crates.io/crates/typemap.