-
Notifications
You must be signed in to change notification settings - Fork 492
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update documentation for arbitrary_enum_discriminant feature #639
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -13,8 +13,8 @@ | |||||
> | ||||||
> _EnumItem_ :\ | ||||||
> _OuterAttribute_<sup>\*</sup>\ | ||||||
> [IDENTIFIER] ( _EnumItemTuple_ | _EnumItemStruct_ | ||||||
> | _EnumItemDiscriminant_ )<sup>?</sup> | ||||||
> [IDENTIFIER] ( _EnumItemTuple_ | _EnumItemStruct_ )<sup>?</sup> | ||||||
> _EnumItemDiscriminant_<sup>?</sup> | ||||||
> | ||||||
> _EnumItemTuple_ :\ | ||||||
> `(` [_TupleFields_]<sup>?</sup> `)` | ||||||
|
@@ -56,22 +56,68 @@ a = Animal::Cat { name: "Spotty".to_string(), weight: 2.7 }; | |||||
``` | ||||||
|
||||||
In this example, `Cat` is a _struct-like enum variant_, whereas `Dog` is simply | ||||||
called an enum variant. Each enum instance has a _discriminant_ which is an | ||||||
integer associated to it that is used to determine which variant it holds. An | ||||||
opaque reference to this discriminant can be obtained with the | ||||||
[`mem::discriminant`] function. | ||||||
called an enum variant. | ||||||
|
||||||
## Custom Discriminant Values for Field-Less Enumerations | ||||||
## Discriminants | ||||||
|
||||||
If there is no data attached to *any* of the variants of an enumeration, | ||||||
then the discriminant can be directly chosen and accessed. | ||||||
Each enum instance has a _discriminant_: an integer logically associated to it | ||||||
that is used to determine which variant it holds. An opaque reference to this | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using |
||||||
discriminant can be obtained with the [`mem::discriminant`] function. | ||||||
|
||||||
These enumerations can be cast to integer types with the `as` operator by a | ||||||
[numeric cast]. The enumeration can optionally specify which integer each | ||||||
discriminant gets by following the variant name with `=` followed by a [constant | ||||||
expression]. If the first variant in the declaration is unspecified, then it is | ||||||
set to zero. For every other unspecified discriminant, it is set to one higher | ||||||
than the previous variant in the declaration. | ||||||
Under the [default representation], the discriminant is interpreted as | ||||||
an `isize` value. However, the compiler is allowed to use a smaller type (or | ||||||
another means of distinguishing variants) in its actual memory layout. | ||||||
|
||||||
If the [primitive representation] or the [`C` representation] is used, the | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand what this paragraph is trying to say. |
||||||
leading bytes of a variant (for example, two bytes if `#[repr(u16)]` is used), will | ||||||
correspond exactly to the discriminant. | ||||||
|
||||||
### Assigning Discriminant Values | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For this entire section, it only makes sense for field-less enums or enums with a primitive representation (or the |
||||||
|
||||||
#### Explicit Discriminants | ||||||
|
||||||
In two circumstances, the discriminant of a variant may be explicitly set by | ||||||
following the variant name with `=` and a [constant expression]: | ||||||
|
||||||
<ol> | ||||||
<li> | ||||||
|
||||||
if the enumeration is "C-like" (i.e., it has no tuple or struct variants); e.g.: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Per #639 (comment), these terms may not be truly interchangeable. |
||||||
|
||||||
```rust | ||||||
# #![feature(arbitrary_enum_discriminant)] | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Feature flags aren't needed; the prose will only be merged after the feature is stable.
Suggested change
|
||||||
enum Enum { | ||||||
Foo = 3, | ||||||
Bar = 2, | ||||||
Baz = 1, | ||||||
} | ||||||
``` | ||||||
</li> | ||||||
<li> | ||||||
|
||||||
if a [primitive representation] is used. For example: | ||||||
|
||||||
```rust | ||||||
# #![feature(arbitrary_enum_discriminant)] | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Feature flag not needed.
Suggested change
|
||||||
#[repr(u8)] | ||||||
enum Enum { | ||||||
Unit = 3, | ||||||
Tuple(u16), | ||||||
Struct { | ||||||
a: u8, | ||||||
b: u16, | ||||||
} = 1, | ||||||
} | ||||||
``` | ||||||
</li> | ||||||
</ol> | ||||||
|
||||||
#### Implicit Discriminants | ||||||
|
||||||
If a discriminant for a variant is not specified, then it is set to one higher | ||||||
than the discriminant of the previous variant in the declaration. If the | ||||||
discriminant of the first variant in the declaration is unspecified, then | ||||||
it is set to zero. | ||||||
|
||||||
```rust | ||||||
enum Foo { | ||||||
|
@@ -84,14 +130,11 @@ let baz_discriminant = Foo::Baz as u32; | |||||
assert_eq!(baz_discriminant, 123); | ||||||
``` | ||||||
|
||||||
Under the [default representation], the specified discriminant is interpreted as | ||||||
an `isize` value although the compiler is allowed to use a smaller type in the | ||||||
actual memory layout. The size and thus acceptable values can be changed by | ||||||
using a [primitive representation] or the [`C` representation]. | ||||||
#### Restrictions | ||||||
|
||||||
It is an error when two variants share the same discriminant. | ||||||
|
||||||
```rust,ignore | ||||||
```rust,compile_fail | ||||||
enum SharedDiscriminantError { | ||||||
SharedA = 1, | ||||||
SharedB = 1 | ||||||
|
@@ -107,7 +150,7 @@ enum SharedDiscriminantError2 { | |||||
It is also an error to have an unspecified discriminant where the previous | ||||||
discriminant is the maximum value for the size of the discriminant. | ||||||
|
||||||
```rust,ignore | ||||||
```rust,compile_fail | ||||||
#[repr(u8)] | ||||||
enum OverflowingDiscriminantError { | ||||||
Max = 255, | ||||||
|
@@ -122,6 +165,53 @@ enum OverflowingDiscriminantError2 { | |||||
} | ||||||
``` | ||||||
|
||||||
### Accessing Discriminant Values | ||||||
|
||||||
#### Casting | ||||||
|
||||||
If there is no data attached to *any* of the variants of an enumeration, then | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's no need to describe a field-less enum here. Just use the term.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Per #639 (comment), these terms may not be completely interchangeable. If "field-less" is meant to be synonymous to "C-like", then this change would be incorrect. |
||||||
the discriminant can be directly accessed with a [numeric cast]; e.g.: | ||||||
|
||||||
```rust | ||||||
enum Enum { | ||||||
Unit, | ||||||
Tuple(), | ||||||
Struct{}, | ||||||
} | ||||||
|
||||||
assert_eq!(0, Enum::Unit as isize); | ||||||
assert_eq!(1, Enum::Tuple() as isize); | ||||||
assert_eq!(2, Enum::Struct{} as isize); | ||||||
``` | ||||||
|
||||||
#### Pointer Casting | ||||||
|
||||||
If the enumeration specifies a [primitive representation], then the | ||||||
discriminant may be reliably accessed via unsafe pointer casting: | ||||||
|
||||||
```rust | ||||||
#[repr(u8)] | ||||||
enum Enum { | ||||||
Unit, | ||||||
Tuple(bool), | ||||||
Struct{a: bool}, | ||||||
} | ||||||
|
||||||
impl Enum { | ||||||
fn discriminant(&self) -> u8 { | ||||||
unsafe { *(self as *const Self as *const u8) } | ||||||
} | ||||||
} | ||||||
|
||||||
let unit_like = Enum::Unit; | ||||||
let tuple_like = Enum::Tuple(true); | ||||||
let struct_like = Enum::Struct{a: false}; | ||||||
|
||||||
assert_eq!(0, unit_like.discriminant()); | ||||||
assert_eq!(1, tuple_like.discriminant()); | ||||||
assert_eq!(2, struct_like.discriminant()); | ||||||
``` | ||||||
|
||||||
## Zero-variant Enums | ||||||
|
||||||
Enums with zero variants are known as *zero-variant enums*. As they have | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -357,7 +357,7 @@ used with any other representation. | |
[`size_of`]: ../std/mem/fn.size_of.html | ||
[`Sized`]: ../std/marker/trait.Sized.html | ||
[dynamically sized types]: dynamically-sized-types.html | ||
[C-like enumerations]: items/enumerations.html#custom-discriminant-values-for-field-less-enumerations | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This link change is wrong. We aren't properly defining a field-less enum anywhere after this PR. |
||
[C-like enumerations]: items/enumerations.html#explicit-discriminants | ||
[zero-variant enumerations]: items/enumerations.html#zero-variant-enums | ||
[undefined behavior]: behavior-considered-undefined.html | ||
[27060]: https://github.com/rust-lang/rust/issues/27060 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The re-organization looks fine, but we lose our definition of a field-less enum. This suggestion re-adds it. I don't actually know if the anchor actually works. It should just create an anchor that can be linked too without changing any styles or making it clickable.