@@ -56,6 +56,13 @@ pub trait LabelDowncast<Id> {
56
56
fn downcast_from ( data : u64 ) -> Option < Self :: Output > ;
57
57
}
58
58
59
+ #[ doc( hidden) ]
60
+ pub struct VTable {
61
+ // FIXME: When const TypeId stabilizes, inline the type instead of using a fn pointer for indirection.
62
+ pub ty : fn ( ) -> :: std:: any:: TypeId ,
63
+ pub fmt : fn ( u64 , & mut :: std:: fmt:: Formatter ) -> :: std:: fmt:: Result ,
64
+ }
65
+
59
66
/// Macro to define a new label trait
60
67
///
61
68
/// # Example
@@ -81,25 +88,30 @@ macro_rules! define_label {
81
88
$( #[ $id_attr] ) *
82
89
#[ derive( Clone , Copy ) ]
83
90
pub struct $id_name {
84
- ty: :: std:: any:: TypeId ,
85
91
data: u64 ,
86
- f : fn ( u64 , & mut :: std :: fmt :: Formatter ) -> :: std :: fmt :: Result ,
92
+ vtable : & ' static $crate :: label :: VTable ,
87
93
}
88
94
89
95
impl :: std:: fmt:: Debug for $id_name {
90
96
fn fmt( & self , f: & mut :: std:: fmt:: Formatter ) -> :: std:: fmt:: Result {
91
97
let data = self . data( ) ;
92
- ( self . f ) ( data, f)
98
+ ( self . vtable . fmt ) ( data, f)
93
99
}
94
100
}
95
101
96
102
$( #[ $label_attr] ) *
97
103
pub trait $label_name: ' static {
104
+ /// Essentially acts like a dynamic dispatch virtual table,
105
+ /// but specialized for labels.
106
+ const VTABLE : $crate:: label:: VTable = $crate:: label:: VTable {
107
+ ty: || :: std:: any:: TypeId :: of:: <Self >( ) ,
108
+ fmt: Self :: fmt,
109
+ } ;
98
110
/// Converts this type into an opaque, strongly-typed label.
99
111
#[ inline]
100
112
fn as_label( & self ) -> $id_name {
101
113
let data = self . data( ) ;
102
- $id_name { data, ty : :: std :: any :: TypeId :: of :: < Self > ( ) , f : Self :: fmt }
114
+ $id_name { data, vtable : & Self :: VTABLE }
103
115
}
104
116
/// Returns a number used to distinguish different labels of the same type.
105
117
fn data( & self ) -> u64 ;
@@ -129,23 +141,30 @@ macro_rules! define_label {
129
141
impl PartialEq for $id_name {
130
142
#[ inline]
131
143
fn eq( & self , rhs: & Self ) -> bool {
132
- self . ty == rhs. ty && self . data ( ) == rhs. data ( )
144
+ self . data ( ) == rhs. data ( ) && self . type_id ( ) == rhs. type_id ( )
133
145
}
134
146
}
135
147
impl Eq for $id_name { }
136
148
137
149
138
150
impl std:: hash:: Hash for $id_name {
139
151
fn hash<H : std:: hash:: Hasher >( & self , state: & mut H ) {
140
- self . ty . hash( state) ;
152
+ self . type_id ( ) . hash( state) ;
141
153
self . data( ) . hash( state) ;
142
154
}
143
155
}
144
156
145
157
impl $id_name {
158
+ /// Returns the [`TypeId`] of the label from which this ID was constructed.
159
+ ///
160
+ /// [`TypeId`]: ::std::any::TypeId
161
+ #[ inline]
162
+ pub fn type_id( self ) -> :: std:: any:: TypeId {
163
+ ( self . vtable. ty) ( )
164
+ }
146
165
/// Returns true if this label was constructed from an instance of type `L`.
147
166
pub fn is<L : $label_name>( self ) -> bool {
148
- self . ty == :: std:: any:: TypeId :: of:: <L >( )
167
+ self . type_id ( ) == :: std:: any:: TypeId :: of:: <L >( )
149
168
}
150
169
/// Attempts to downcast this label to type `L`.
151
170
///
0 commit comments