Replies: 1 comment 17 replies
-
|
Now that I look back at the part about discriminant, I think I over-thought it. The fact that |
Beta Was this translation helpful? Give feedback.
17 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
The goal of this discussion is to design reflection on
enumtypes. Ideally,enums would at least support every case that the other types currently support.Nomenclature
I will try to use the same names as in
serde.Each variant is identified by a unique number called its discriminant. Discriminants are not indices, they may not be continuous and can even be set explicitly if all variants are unit variants (that is, in C-like
enums).Features
Let's start with a wish-list of features:
TestEnum::A), and its discriminantenums with explicit discriminantsReflect::reflect_ref()#[derive(Reflect)]Defaultif supported)DynamicEnumsDoes this look complete/reasonable?
MVP
I propose as a first step to implement features 1 to 4. This means
enums could manually implement theEnumtrait to get basic reflection. The other features can be built on it later, which gives us time tobikeshed ondesign them. I will present a possible API and associated design questions.EnumtraitHere is a first shot at the main trait that is the equivalent of the
Structtrait.Is it missing any feature? Can you think of better names?
EnumVariantThis is an
enumthat contains and describes the current variant. Following the Serde data model, it defines 4 types of variants. It is conceptually similar toenum ReflectRefforReflect.An alternative would be to not define
NewTypeand consider them as tuples of 1 element. It's unclear to me why serde makes the difference, the Rust Reference does not.DiscriminantThis is the tricky part. It's possible to get the discriminant of any variant with
std::mem::discriminant(&TestEnum::A). It returns an opaque type:std::mem::Discriminant<TestEnum>. Since ourDiscriminantis an associated type, each implementation can set it to the correctstd::mem::Discriminant<T>. That is enough for addressing since it implementsEqandHashbut in order to give an actual integer value (e.g. for serialization), we would like to convert that to anusize(enums can never have a size larger thanusize). For that we need to transmute it, however we have to avoid reading any uninitialized memory. A simple implementation of that looks like this:There is probably a better way to do it, do tell me if you know it. Also, the compiler may be smart enough to optimize everything.
Other note: I used
usizebut the real discriminant's type might be signed. As far as I can tell there is no way to know fromstd::mem::Discriminant<>since it is opaque, but it can only happen in C-likeenums with the#[repr(...)]attribute and/or explicit discriminants, so it is possible to detect it in the derive macro. Then, we would have a second associated type that is eitherusizeorisize, and transmute the discriminant to that type.Conclusion
This MVP seems to be implementable quickly when agreed on. I have not seriously investigated how to implement the other features, but I don't foresee any trouble. I will probably wait until we agree on this first part before detailing them here.
Beta Was this translation helpful? Give feedback.
All reactions