mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
explain how to get the discriminant out of a #[repr(T)] enum
This commit is contained in:
parent
8a75c5a9b5
commit
e06b61c8f9
@ -1113,7 +1113,10 @@ impl<T> fmt::Debug for Discriminant<T> {
|
|||||||
/// # Stability
|
/// # Stability
|
||||||
///
|
///
|
||||||
/// The discriminant of an enum variant may change if the enum definition changes. A discriminant
|
/// The discriminant of an enum variant may change if the enum definition changes. A discriminant
|
||||||
/// of some variant will not change between compilations with the same compiler.
|
/// of some variant will not change between compilations with the same compiler. See the [Reference]
|
||||||
|
/// for more information.
|
||||||
|
///
|
||||||
|
/// [Reference]: ../../reference/items/enumerations.html#discriminants
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
@ -1129,6 +1132,62 @@ impl<T> fmt::Debug for Discriminant<T> {
|
|||||||
/// assert_eq!(mem::discriminant(&Foo::B(1)), mem::discriminant(&Foo::B(2)));
|
/// assert_eq!(mem::discriminant(&Foo::B(1)), mem::discriminant(&Foo::B(2)));
|
||||||
/// assert_ne!(mem::discriminant(&Foo::B(3)), mem::discriminant(&Foo::C(3)));
|
/// assert_ne!(mem::discriminant(&Foo::B(3)), mem::discriminant(&Foo::C(3)));
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## Accessing the numeric value of the discriminant
|
||||||
|
///
|
||||||
|
/// Note that it is *undefined behavior* to [`transmute`] from [`Discriminant`] to a primitive!
|
||||||
|
///
|
||||||
|
/// If an enum has only unit variants, then the numeric value of the discriminant can be accessed
|
||||||
|
/// with an [`as`] cast:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// enum Enum {
|
||||||
|
/// Foo,
|
||||||
|
/// Bar,
|
||||||
|
/// Baz,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// assert_eq!(0, Enum::Foo as isize);
|
||||||
|
/// assert_eq!(1, Enum::Bar as isize);
|
||||||
|
/// assert_eq!(2, Enum::Baz as isize);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// If an enum has opted-in to having a [primitive representation] for its discriminant,
|
||||||
|
/// then it's possible to use pointers to read the memory location storing the discriminant.
|
||||||
|
/// That **cannot** be done for enums using the [default representation], however, as it's
|
||||||
|
/// undefined what layout the discriminant has and where it's stored — it might not even be
|
||||||
|
/// stored at all!
|
||||||
|
///
|
||||||
|
/// [`as`]: ../../std/keyword.as.html
|
||||||
|
/// [primitive representation]: ../../reference/type-layout.html#primitive-representations
|
||||||
|
/// [default representation]: ../../reference/type-layout.html#the-default-representation
|
||||||
|
/// ```
|
||||||
|
/// #[repr(u8)]
|
||||||
|
/// enum Enum {
|
||||||
|
/// Unit,
|
||||||
|
/// Tuple(bool),
|
||||||
|
/// Struct { a: bool },
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl Enum {
|
||||||
|
/// fn discriminant(&self) -> u8 {
|
||||||
|
/// // SAFETY: Because `Self` is marked `repr(u8)`, its layout is a `repr(C)` `union`
|
||||||
|
/// // between `repr(C)` structs, each of which has the `u8` discriminant as its first
|
||||||
|
/// // field, so we can read the discriminant without offsetting the pointer.
|
||||||
|
/// unsafe { *<*const _>::from(self).cast::<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());
|
||||||
|
///
|
||||||
|
/// // ⚠️ This is undefined behavior. Don't do this. ⚠️
|
||||||
|
/// // assert_eq!(0, unsafe { std::mem::transmute::<_, u8>(std::mem::discriminant(&unit_like)) });
|
||||||
|
/// ```
|
||||||
#[stable(feature = "discriminant_value", since = "1.21.0")]
|
#[stable(feature = "discriminant_value", since = "1.21.0")]
|
||||||
#[rustc_const_unstable(feature = "const_discriminant", issue = "69821")]
|
#[rustc_const_unstable(feature = "const_discriminant", issue = "69821")]
|
||||||
#[cfg_attr(not(test), rustc_diagnostic_item = "mem_discriminant")]
|
#[cfg_attr(not(test), rustc_diagnostic_item = "mem_discriminant")]
|
||||||
|
Loading…
Reference in New Issue
Block a user