Skip to content

Commit 9548730

Browse files
authored
Auto merge of #36823 - durka:discriminant_value, r=nagisa
add wrapper for discriminant_value, take 2 [This is #34785 reopened, since @bors apparently gave up on that thread.] add wrapper for discriminant_value intrinsic Implementation of [RFC 1696](https://github.com/rust-lang/rfcs/blob/master/text/1696-discriminant.md). Wraps the `discriminant_value` intrinsic under the name `std::mem::discriminant`. In order to avoid prematurely leaking information about the implementation of enums, the return value is an opaque type, generic over the enum type, which implements Copy, Clone, PartialEq, Eq, Hash, and Debug (notably not PartialOrd). There is currently no way to get the value out excepting printing the debug representation. The wrapper is safe and can be stabilized soon as per discussion in #24263. cc @aturon r? @nagisa
2 parents 1d64acd + a84b550 commit 9548730

File tree

2 files changed

+110
-0
lines changed

2 files changed

+110
-0
lines changed

src/libcore/mem.rs

+82
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@
1515
1616
#![stable(feature = "rust1", since = "1.0.0")]
1717

18+
use clone;
19+
use cmp;
20+
use fmt;
21+
use hash;
1822
use intrinsics;
23+
use marker::{Copy, PhantomData, Sized};
1924
use ptr;
2025

2126
#[stable(feature = "rust1", since = "1.0.0")]
@@ -647,3 +652,80 @@ pub fn drop<T>(_x: T) { }
647652
pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
648653
ptr::read(src as *const T as *const U)
649654
}
655+
656+
/// Opaque type representing the discriminant of an enum.
657+
///
658+
/// See the `discriminant` function in this module for more information.
659+
#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")]
660+
pub struct Discriminant<T>(u64, PhantomData<*const T>);
661+
662+
// N.B. These trait implementations cannot be derived because we don't want any bounds on T.
663+
664+
#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")]
665+
impl<T> Copy for Discriminant<T> {}
666+
667+
#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")]
668+
impl<T> clone::Clone for Discriminant<T> {
669+
fn clone(&self) -> Self {
670+
*self
671+
}
672+
}
673+
674+
#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")]
675+
impl<T> cmp::PartialEq for Discriminant<T> {
676+
fn eq(&self, rhs: &Self) -> bool {
677+
self.0 == rhs.0
678+
}
679+
}
680+
681+
#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")]
682+
impl<T> cmp::Eq for Discriminant<T> {}
683+
684+
#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")]
685+
impl<T> hash::Hash for Discriminant<T> {
686+
fn hash<H: hash::Hasher>(&self, state: &mut H) {
687+
self.0.hash(state);
688+
}
689+
}
690+
691+
#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")]
692+
impl<T> fmt::Debug for Discriminant<T> {
693+
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
694+
fmt.debug_tuple("Discriminant")
695+
.field(&self.0)
696+
.finish()
697+
}
698+
}
699+
700+
/// Returns a value uniquely identifying the enum variant in `v`.
701+
///
702+
/// If `T` is not an enum, calling this function will not result in undefined behavior, but the
703+
/// return value is unspecified.
704+
///
705+
/// # Stability
706+
///
707+
/// The discriminant of an enum variant may change if the enum definition changes. A discriminant
708+
/// of some variant will not change between compilations with the same compiler.
709+
///
710+
/// # Examples
711+
///
712+
/// This can be used to compare enums that carry data, while disregarding
713+
/// the actual data:
714+
///
715+
/// ```
716+
/// #![feature(discriminant_value)]
717+
/// use std::mem;
718+
///
719+
/// enum Foo { A(&'static str), B(i32), C(i32) }
720+
///
721+
/// assert!(mem::discriminant(&Foo::A("bar")) == mem::discriminant(&Foo::A("baz")));
722+
/// assert!(mem::discriminant(&Foo::B(1)) == mem::discriminant(&Foo::B(2)));
723+
/// assert!(mem::discriminant(&Foo::B(3)) != mem::discriminant(&Foo::C(3)));
724+
/// ```
725+
#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")]
726+
pub fn discriminant<T>(v: &T) -> Discriminant<T> {
727+
unsafe {
728+
Discriminant(intrinsics::discriminant_value(v), PhantomData)
729+
}
730+
}
731+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(discriminant_value)]
12+
13+
use std::mem;
14+
15+
enum ADT {
16+
First(u32, u32),
17+
Second(u64)
18+
}
19+
20+
pub fn main() {
21+
assert!(mem::discriminant(&ADT::First(0,0)) == mem::discriminant(&ADT::First(1,1)));
22+
assert!(mem::discriminant(&ADT::Second(5)) == mem::discriminant(&ADT::Second(6)));
23+
assert!(mem::discriminant(&ADT::First(2,2)) != mem::discriminant(&ADT::Second(2)));
24+
25+
let _ = mem::discriminant(&10);
26+
let _ = mem::discriminant(&"test");
27+
}
28+

0 commit comments

Comments
 (0)