13
13
>
14
14
> _ EnumItem_ :\
15
15
>   ;  ; _ OuterAttribute_ <sup >\* </sup > [ _ Visibility_ ] <sup >?</sup >\
16
- >   ;  ; [ IDENTIFIER]   ; ( _ EnumItemTuple_ | _ EnumItemStruct_
17
- > | _ EnumItemDiscriminant_ ) <sup >?</sup >
16
+ >   ;  ; [ IDENTIFIER]   ; ( _ EnumItemTuple_ | _ EnumItemStruct_ )< sup >?</ sup >
17
+ > _ EnumItemDiscriminant_ <sup >?</sup >
18
18
>
19
19
> _ EnumItemTuple_ :\
20
20
>   ;  ; ` ( ` [ _ TupleFields_ ] <sup >?</sup > ` ) `
@@ -56,22 +56,68 @@ a = Animal::Cat { name: "Spotty".to_string(), weight: 2.7 };
56
56
```
57
57
58
58
In 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.
63
60
64
- ## Custom Discriminant Values for Fieldless Enumerations
61
+ ## Discriminants
65
62
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.
68
66
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.
75
121
76
122
``` rust
77
123
enum Foo {
@@ -84,10 +130,7 @@ let baz_discriminant = Foo::Baz as u32;
84
130
assert_eq! (baz_discriminant , 123 );
85
131
```
86
132
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
91
134
92
135
It is an error when two variants share the same discriminant.
93
136
@@ -122,6 +165,53 @@ enum OverflowingDiscriminantError2 {
122
165
}
123
166
```
124
167
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
+
125
215
## Zero-variant Enums
126
216
127
217
Enums with zero variants are known as * zero-variant enums* . As they have
0 commit comments