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,71 @@ 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+ An enum where no constructors contain fields are called a
62+ * <span  id =" field-less-enum " >field-less enum</span >* . For example, this is a fieldless enum:
6563
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.
64+ ``` rust 
65+ enum  Fieldless  {
66+     Tuple (),
67+     Struct {},
68+     Unit ,
69+ }
70+ ``` 
71+ 
72+ If a field-less enum only contains unit variants, the enum is called an
73+ * <span  id =" unit-only-enum " >unit-only enum</span >* . For example:
74+ 
75+ ``` rust 
76+ enum  Enum  {
77+     Foo  =  3 ,
78+     Bar  =  2 ,
79+     Baz  =  1 ,
80+ }
81+ ``` 
82+ 
83+ <span  id =" custom-discriminant-values-for-fieldless-enumerations " ></span >
84+ ## Discriminants  
85+ 
86+ Each enum instance has a _ discriminant_ : an integer logically associated to it
87+ that is used to determine which variant it holds.
88+ 
89+ Under the [ default representation] , the discriminant is interpreted as
90+ an ` isize `  value. However, the compiler is allowed to use a smaller type (or
91+ another means of distinguishing variants) in its actual memory layout.
92+ 
93+ ### Assigning discriminant values  
94+ 
95+ #### Explicit discriminants  
6896
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.
97+ In two circumstances, the discriminant of a variant may be explicitly set by
98+ following the variant name with ` = `  and a [ constant expression] :
99+ 
100+ 
101+ 1 .  if the enumeration is "[ unit-only] ".
102+ 
103+ 
104+ 2 .  if a [ primitive representation]  is used. For example:
105+ 
106+    ``` rust 
107+    #[repr(u8 )]
108+    enum  Enum  {
109+        Unit  =  3 ,
110+        Tuple (u16 ),
111+        Struct  {
112+            a :  u8 ,
113+            b :  u16 ,
114+        } =  1 ,
115+    }
116+    ``` 
117+ 
118+ #### Implicit discriminants  
119+ 
120+ If a discriminant for a variant is not specified, then it is set to one higher
121+ than the discriminant of the previous variant in the declaration. If the
122+ discriminant of the first variant in the declaration is unspecified, then
123+ it is set to zero.
75124
76125``` rust 
77126enum  Foo  {
@@ -84,10 +133,7 @@ let baz_discriminant = Foo::Baz as u32;
84133assert_eq! (baz_discriminant , 123 );
85134``` 
86135
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] .
136+ #### Restrictions  
91137
92138It is an error when two variants share the same discriminant.
93139
@@ -122,7 +168,89 @@ enum OverflowingDiscriminantError2 {
122168} 
123169``` 
124170
125- ## Zero-variant Enums  
171+ ### Accessing discriminant  
172+ 
173+ #### Via ` mem::discriminant `   
174+ 
175+ [ ` mem::discriminant ` ]  returns an opaque reference to the discriminant of
176+ an enum value which can be compared. This cannot be used to get the value
177+ of the discriminant.
178+ 
179+ #### Casting  
180+ 
181+ If an enumeration is [ unit-only]  (with no tuple and struct variants), then its
182+ discriminant can be directly accessed with a [ numeric cast] ; e.g.:
183+ 
184+ ``` rust 
185+ enum  Enum  {
186+     Foo ,
187+     Bar ,
188+     Baz ,
189+ }
190+ 
191+ assert_eq! (0 , Enum :: Foo  as  isize );
192+ assert_eq! (1 , Enum :: Bar  as  isize );
193+ assert_eq! (2 , Enum :: Baz  as  isize );
194+ ``` 
195+ 
196+ [ Field-less enums]  can be casted if they do not have explicit discriminants, or where only unit variants are explicit.
197+ 
198+ ``` rust 
199+ enum  Fieldless  {
200+     Tuple (),
201+     Struct {},
202+     Unit ,
203+ }
204+ 
205+ assert_eq! (0 , Fieldless :: Tuple () as  isize );
206+ assert_eq! (1 , Fieldless :: Struct {} as  isize );
207+ assert_eq! (2 , Fieldless :: Unit  as  isize );
208+ 
209+ #[repr(u8 )]
210+ enum  FieldlessWithDiscrimants  {
211+     First  =  10 ,
212+     Tuple (),
213+     Second  =  20 ,
214+     Struct {},
215+     Unit ,
216+ }
217+ 
218+ assert_eq! (10 , FieldlessWithDiscrimants :: First  as  u8 );
219+ assert_eq! (11 , FieldlessWithDiscrimants :: Tuple () as  u8 );
220+ assert_eq! (20 , FieldlessWithDiscrimants :: Second  as  u8 );
221+ assert_eq! (21 , FieldlessWithDiscrimants :: Struct {} as  u8 );
222+ assert_eq! (22 , FieldlessWithDiscrimants :: Unit  as  u8 );
223+ ``` 
224+ 
225+ #### Pointer casting  
226+ 
227+ If the enumeration specifies a [ primitive representation] , then the
228+ discriminant may be reliably accessed via unsafe pointer casting:
229+ 
230+ ``` rust 
231+ #[repr(u8 )]
232+ enum  Enum  {
233+     Unit ,
234+     Tuple (bool ),
235+     Struct {a :  bool },
236+ }
237+ 
238+ impl  Enum  {
239+     fn  discriminant (& self ) ->  u8  {
240+         unsafe  { * (self  as  * const  Self  as  * const  u8 ) }
241+     }
242+ }
243+ 
244+ let  unit_like  =  Enum :: Unit ;
245+ let  tuple_like  =  Enum :: Tuple (true );
246+ let  struct_like  =  Enum :: Struct {a :  false };
247+ 
248+ assert_eq! (0 , unit_like . discriminant ());
249+ assert_eq! (1 , tuple_like . discriminant ());
250+ assert_eq! (2 , struct_like . discriminant ());
251+ ``` 
252+ 
253+ ## Zero-variant enums  
126254
127255Enums with zero variants are known as * zero-variant enums* . As they have
128256no valid values, they cannot be instantiated.
@@ -181,8 +309,10 @@ enum E {
181309[ enumerated type ] : ../types/enum.md 
182310[ `mem::discriminant` ] : ../../std/mem/fn.discriminant.html 
183311[ never type ] : ../types/never.md 
312+ [ unit-only ] : #unit-only-enum 
184313[ numeric cast ] : ../expressions/operator-expr.md#semantics 
185314[ constant expression ] : ../const_eval.md#constant-expressions 
186315[ default representation ] : ../type-layout.md#the-default-representation 
187316[ primitive representation ] : ../type-layout.md#primitive-representations 
188317[ `C` representation ] : ../type-layout.md#the-c-representation 
318+ [ Field-less enums ] : #field-less-enum 
0 commit comments