Skip to content

Commit dd3c111

Browse files
jswrennfee1-dead
authored andcommitted
Update enum documentation for arbitrary_enum_discriminant feature.
1 parent 7ab0256 commit dd3c111

File tree

2 files changed

+110
-20
lines changed

2 files changed

+110
-20
lines changed

src/expressions/operator-expr.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ reference types and `mut` or `const` in pointer types.
314314
| Type of `e` | `U` | Cast performed by `e as U` |
315315
|-----------------------|-----------------------|----------------------------------|
316316
| Integer or Float type | Integer or Float type | Numeric cast |
317-
| C-like enum | Integer type | Enum cast |
317+
| Field-less enum | Integer type | Enum cast |
318318
| `bool` or `char` | Integer type | Primitive to integer cast |
319319
| `u8` | `char` | `u8` to `char` cast |
320320
| `*T` | `*V` where `V: Sized` \* | Pointer to pointer cast |

src/items/enumerations.md

+109-19
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
>
1414
> _EnumItem_ :\
1515
> &nbsp;&nbsp; _OuterAttribute_<sup>\*</sup> [_Visibility_]<sup>?</sup>\
16-
> &nbsp;&nbsp; [IDENTIFIER]&nbsp;( _EnumItemTuple_ | _EnumItemStruct_
17-
> | _EnumItemDiscriminant_ )<sup>?</sup>
16+
> &nbsp;&nbsp; [IDENTIFIER]&nbsp;( _EnumItemTuple_ | _EnumItemStruct_ )<sup>?</sup>
17+
> _EnumItemDiscriminant_<sup>?</sup>
1818
>
1919
> _EnumItemTuple_ :\
2020
> &nbsp;&nbsp; `(` [_TupleFields_]<sup>?</sup> `)`
@@ -56,22 +56,68 @@ a = Animal::Cat { name: "Spotty".to_string(), weight: 2.7 };
5656
```
5757

5858
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.
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
77123
enum Foo {
@@ -84,10 +130,7 @@ let baz_discriminant = Foo::Baz as u32;
84130
assert_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

92135
It 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

127217
Enums with zero variants are known as *zero-variant enums*. As they have

0 commit comments

Comments
 (0)