@@ -1113,7 +1113,10 @@ impl<T> fmt::Debug for Discriminant<T> {
1113
1113
/// # Stability
1114
1114
///
1115
1115
/// The discriminant of an enum variant may change if the enum definition changes. A discriminant
1116
- /// of some variant will not change between compilations with the same compiler.
1116
+ /// of some variant will not change between compilations with the same compiler. See the [Reference]
1117
+ /// for more information.
1118
+ ///
1119
+ /// [Reference]: ../../reference/items/enumerations.html#discriminants
1117
1120
///
1118
1121
/// # Examples
1119
1122
///
@@ -1129,6 +1132,62 @@ impl<T> fmt::Debug for Discriminant<T> {
1129
1132
/// assert_eq!(mem::discriminant(&Foo::B(1)), mem::discriminant(&Foo::B(2)));
1130
1133
/// assert_ne!(mem::discriminant(&Foo::B(3)), mem::discriminant(&Foo::C(3)));
1131
1134
/// ```
1135
+ ///
1136
+ /// ## Accessing the numeric value of the discriminant
1137
+ ///
1138
+ /// Note that it is *undefined behavior* to [`transmute`] from [`Discriminant`] to a primitive!
1139
+ ///
1140
+ /// If an enum has only unit variants, then the numeric value of the discriminant can be accessed
1141
+ /// with an [`as`] cast:
1142
+ ///
1143
+ /// ```
1144
+ /// enum Enum {
1145
+ /// Foo,
1146
+ /// Bar,
1147
+ /// Baz,
1148
+ /// }
1149
+ ///
1150
+ /// assert_eq!(0, Enum::Foo as isize);
1151
+ /// assert_eq!(1, Enum::Bar as isize);
1152
+ /// assert_eq!(2, Enum::Baz as isize);
1153
+ /// ```
1154
+ ///
1155
+ /// If an enum has opted-in to having a [primitive representation] for its discriminant,
1156
+ /// then it's possible to use pointers to read the memory location storing the discriminant.
1157
+ /// That **cannot** be done for enums using the [default representation], however, as it's
1158
+ /// undefined what layout the discriminant has and where it's stored — it might not even be
1159
+ /// stored at all!
1160
+ ///
1161
+ /// [`as`]: ../../std/keyword.as.html
1162
+ /// [primitive representation]: ../../reference/type-layout.html#primitive-representations
1163
+ /// [default representation]: ../../reference/type-layout.html#the-default-representation
1164
+ /// ```
1165
+ /// #[repr(u8)]
1166
+ /// enum Enum {
1167
+ /// Unit,
1168
+ /// Tuple(bool),
1169
+ /// Struct { a: bool },
1170
+ /// }
1171
+ ///
1172
+ /// impl Enum {
1173
+ /// fn discriminant(&self) -> u8 {
1174
+ /// // SAFETY: Because `Self` is marked `repr(u8)`, its layout is a `repr(C)` `union`
1175
+ /// // between `repr(C)` structs, each of which has the `u8` discriminant as its first
1176
+ /// // field, so we can read the discriminant without offsetting the pointer.
1177
+ /// unsafe { *<*const _>::from(self).cast::<u8>() }
1178
+ /// }
1179
+ /// }
1180
+ ///
1181
+ /// let unit_like = Enum::Unit;
1182
+ /// let tuple_like = Enum::Tuple(true);
1183
+ /// let struct_like = Enum::Struct { a: false };
1184
+ /// assert_eq!(0, unit_like.discriminant());
1185
+ /// assert_eq!(1, tuple_like.discriminant());
1186
+ /// assert_eq!(2, struct_like.discriminant());
1187
+ ///
1188
+ /// // ⚠️ This is undefined behavior. Don't do this. ⚠️
1189
+ /// // assert_eq!(0, unsafe { std::mem::transmute::<_, u8>(std::mem::discriminant(&unit_like)) });
1190
+ /// ```
1132
1191
#[ stable( feature = "discriminant_value" , since = "1.21.0" ) ]
1133
1192
#[ rustc_const_unstable( feature = "const_discriminant" , issue = "69821" ) ]
1134
1193
#[ cfg_attr( not( test) , rustc_diagnostic_item = "mem_discriminant" ) ]
0 commit comments