1313>
1414> _ EnumItem_ :\
1515>   ;  ; _ OuterAttribute_ <sup >\* </sup > [ _ Visibility_ ] <sup >?</sup >\
16- >   ;  ; [ IDENTIFIER]   ; ( _ EnumItemTuple_ | _ EnumItemStruct_
17- > | _ EnumItemDiscriminant_ ) <sup >?</sup >
16+ >   ;  ; [ IDENTIFIER]   ; ( _ EnumItemTuple_ | _ EnumItemStruct_ )< sup >?</ sup >
17+ > _ EnumItemDiscriminant_ <sup >?</sup >
1818>
1919> _ EnumItemTuple_ :\
2020>   ;  ; ` ( ` [ _ TupleFields_ ] <sup >?</sup > ` ) `
@@ -56,22 +56,68 @@ a = Animal::Cat { name: "Spotty".to_string(), weight: 2.7 };
5656```
5757
5858In this example, ` Cat ` is a _ struct-like enum variant_ , whereas ` Dog ` is simply
59- called an enum variant. Each enum instance has a _ discriminant_ which is an
60- integer associated to it that is used to determine which variant it holds. An
61- opaque reference to this discriminant can be obtained with the
62- [ ` mem::discriminant ` ] function.
59+ called an enum variant.
6360
64- ## Custom Discriminant Values for Fieldless Enumerations
61+ ## Discriminants
6562
66- If there is no data attached to * any* of the variants of an enumeration,
67- then the discriminant can be directly chosen and accessed.
63+ Each enum instance has a _ discriminant_ : an integer logically associated to it
64+ that is used to determine which variant it holds. An opaque reference to this
65+ discriminant can be obtained with the [ ` mem::discriminant ` ] function.
6866
69- These enumerations can be cast to integer types with the ` as ` operator by a
70- [ numeric cast] . The enumeration can optionally specify which integer each
71- discriminant gets by following the variant name with ` = ` followed by a [ constant
72- expression] . If the first variant in the declaration is unspecified, then it is
73- set to zero. For every other unspecified discriminant, it is set to one higher
74- than the previous variant in the declaration.
67+ Under the [ default representation] , the discriminant is interpreted as
68+ an ` isize ` value. However, the compiler is allowed to use a smaller type (or
69+ another means of distinguishing variants) in its actual memory layout.
70+
71+ If the [ primitive representation] or the [ ` C ` representation] is used, the
72+ leading bytes of a variant (e.g., two bytes if ` #[repr(u16)] ` is used), will
73+ correspond exactly to the discriminant.
74+
75+ ### Assigning Discriminant Values
76+
77+ #### Explicit Discriminants
78+
79+ In two circumstances, the discriminant of a variant may be explicitly set by
80+ following the variant name with ` = ` and a [ constant expression] :
81+
82+ <ol >
83+ <li >
84+
85+ if the enumeration is "C-like" (i.e., it has no tuple or struct variants); e.g.:
86+
87+ ``` rust
88+ # #![feature(arbitrary_enum_discriminant)]
89+ enum Enum {
90+ Foo = 3 ,
91+ Bar = 2 ,
92+ Baz = 1 ,
93+ }
94+ ```
95+ </li >
96+ <li >
97+
98+ if a [ primitive representation] is used; e.g.:
99+
100+ ``` rust
101+ # #![feature(arbitrary_enum_discriminant)]
102+ #[repr(u8 )]
103+ enum Enum {
104+ Unit = 3 ,
105+ Tuple (u16 ),
106+ Struct {
107+ a : u8 ,
108+ b : u16 ,
109+ } = 1 ,
110+ }
111+ ```
112+ </li >
113+ </ol >
114+
115+ #### Implicit Discriminants
116+
117+ If a discriminant for a variant is not specified, then it is set to one higher
118+ than the discriminant of the previous variant in the declaration. If the
119+ discriminant of the first variant in the declaration is unspecified, then
120+ it is set to zero.
75121
76122``` rust
77123enum Foo {
@@ -84,10 +130,7 @@ let baz_discriminant = Foo::Baz as u32;
84130assert_eq! (baz_discriminant , 123 );
85131```
86132
87- Under the [ default representation] , the specified discriminant is interpreted as
88- an ` isize ` value although the compiler is allowed to use a smaller type in the
89- actual memory layout. The size and thus acceptable values can be changed by
90- using a [ primitive representation] or the [ ` C ` representation] .
133+ #### Restrictions
91134
92135It is an error when two variants share the same discriminant.
93136
@@ -122,6 +165,53 @@ enum OverflowingDiscriminantError2 {
122165}
123166```
124167
168+ ### Accessing Discriminant Values
169+
170+ #### Casting
171+
172+ If there is no data attached to * any* of the variants of an enumeration, then
173+ the discriminant can be directly accessed with a [ numeric cast] ; e.g.:
174+
175+ ``` rust
176+ enum Enum {
177+ Unit ,
178+ Tuple (),
179+ Struct {},
180+ }
181+
182+ assert_eq! (0 , Enum :: Unit as isize );
183+ assert_eq! (1 , Enum :: Tuple () as isize );
184+ assert_eq! (2 , Enum :: Struct {} as isize );
185+ ```
186+
187+ #### Pointer Casting
188+
189+ If the enumeration specifies a [ primitive representation] , then the
190+ discriminant may be reliably accessed via unsafe pointer casting:
191+
192+ ``` rust
193+ #[repr(u8 )]
194+ enum Enum {
195+ Unit ,
196+ Tuple (bool ),
197+ Struct {a : bool },
198+ }
199+
200+ impl Enum {
201+ fn discriminant (& self ) -> u8 {
202+ unsafe { * (self as * const Self as * const u8 ) }
203+ }
204+ }
205+
206+ let unit_like = Enum :: Unit ;
207+ let tuple_like = Enum :: Tuple (true );
208+ let struct_like = Enum :: Struct {a : false };
209+
210+ assert_eq! (0 , unit_like . discriminant ());
211+ assert_eq! (1 , tuple_like . discriminant ());
212+ assert_eq! (2 , struct_like . discriminant ());
213+ ```
214+
125215## Zero-variant Enums
126216
127217Enums with zero variants are known as * zero-variant enums* . As they have
0 commit comments