@@ -5,6 +5,8 @@ use std::{
5
5
hash:: { Hash , Hasher } ,
6
6
} ;
7
7
8
+ use crate :: Interner ;
9
+
8
10
pub trait DynEq : Any {
9
11
fn as_any ( & self ) -> & dyn Any ;
10
12
47
49
}
48
50
}
49
51
52
+ #[ doc( hidden) ]
53
+ pub struct VTable {
54
+ // FIXME: When const TypeId stabilizes, inline the type instead of using a fn pointer for indirection.
55
+ pub ty : fn ( ) -> :: std:: any:: TypeId ,
56
+ pub fmt : fn ( u64 , & mut :: std:: fmt:: Formatter ) -> :: std:: fmt:: Result ,
57
+ }
58
+
59
+ impl PartialEq for VTable {
60
+ #[ inline]
61
+ fn eq ( & self , other : & Self ) -> bool {
62
+ ( self . ty ) ( ) == ( other. ty ) ( )
63
+ }
64
+ }
65
+ impl Eq for VTable { }
66
+
67
+ impl Hash for VTable {
68
+ fn hash < H : Hasher > ( & self , state : & mut H ) {
69
+ ( self . ty ) ( ) . hash ( state) ;
70
+ }
71
+ }
72
+
73
+ #[ doc( hidden) ]
74
+ pub static STR_INTERN : Interner < & str > = Interner :: new ( ) ;
75
+
50
76
/// Macro to define a new label trait
51
77
///
52
78
/// # Example
@@ -71,48 +97,83 @@ macro_rules! define_label {
71
97
) => {
72
98
$( #[ $id_attr] ) *
73
99
#[ derive( Clone , Copy , PartialEq , Eq , Hash ) ]
74
- pub struct $id_name( :: core:: any:: TypeId , & ' static str ) ;
100
+ pub struct $id_name {
101
+ data: u64 ,
102
+ vtable: & ' static $crate:: label:: VTable ,
103
+ }
75
104
76
- impl :: core :: fmt:: Debug for $id_name {
77
- fn fmt( & self , f: & mut :: core :: fmt:: Formatter ) -> :: core :: fmt:: Result {
78
- write! ( f , "{}" , self . 1 )
105
+ impl :: std :: fmt:: Debug for $id_name {
106
+ fn fmt( & self , f: & mut :: std :: fmt:: Formatter ) -> :: std :: fmt:: Result {
107
+ ( self . vtable . fmt ) ( self . data , f )
79
108
}
80
109
}
81
110
82
111
$( #[ $label_attr] ) *
83
112
pub trait $label_name: ' static {
84
113
/// Converts this type into an opaque, strongly-typed label.
114
+ #[ inline]
85
115
fn as_label( & self ) -> $id_name {
86
- let id = self . type_id( ) ;
87
- let label = self . as_str( ) ;
88
- $id_name( id, label)
89
- }
90
- /// Returns the [`TypeId`] used to differentiate labels.
91
- fn type_id( & self ) -> :: core:: any:: TypeId {
92
- :: core:: any:: TypeId :: of:: <Self >( )
116
+ // This is just machinery that lets us store the TypeId and formatter fn in the same static reference.
117
+ struct VTables <L : ?:: std:: marker:: Sized >( L ) ;
118
+ impl <L : $label_name + ?:: std:: marker:: Sized > VTables <L > {
119
+ const VTABLE : $crate:: label:: VTable = $crate:: label:: VTable {
120
+ ty: || :: std:: any:: TypeId :: of:: <L >( ) ,
121
+ fmt: <L as $label_name>:: fmt,
122
+ } ;
123
+ }
124
+
125
+ let data = self . data( ) ;
126
+ $id_name { data, vtable: & VTables :: <Self >:: VTABLE }
93
127
}
94
- /// Returns the representation of this label as a string literal.
128
+ /// Returns a number used to distinguish different labels of the same type.
129
+ fn data( & self ) -> u64 ;
130
+ /// Writes debug info for a label of the current type.
131
+ /// * `data`: the result of calling [`data()`](#method.data) on an instance of this type.
95
132
///
96
- /// In cases where you absolutely need a label to be determined at runtime,
97
- /// you can use [`Box::leak`] to get a `'static` reference .
98
- fn as_str ( & self ) -> & ' static str ;
133
+ /// You should not call this method directly, as it may panic for some types;
134
+ /// use [`as_label`](#method.as_label) instead .
135
+ fn fmt ( data : u64 , f : & mut :: std :: fmt :: Formatter ) -> :: std :: fmt :: Result ;
99
136
}
100
137
101
138
impl $label_name for $id_name {
139
+ #[ inline]
102
140
fn as_label( & self ) -> Self {
103
141
* self
104
142
}
105
- fn type_id( & self ) -> :: core:: any:: TypeId {
106
- self . 0
143
+ #[ inline]
144
+ fn data( & self ) -> u64 {
145
+ self . data
107
146
}
108
- fn as_str( & self ) -> & ' static str {
109
- self . 1
147
+ #[ track_caller]
148
+ fn fmt( data: u64 , f: & mut :: std:: fmt:: Formatter ) -> std:: fmt:: Result {
149
+ let label = stringify!( $label_name) ;
150
+ :: std:: unimplemented!( "do not call `{label}::fmt` directly -- use the result of `as_label()` for formatting instead" )
151
+ }
152
+ }
153
+
154
+ impl $id_name {
155
+ /// Returns the [`TypeId`] of the label from which this ID was constructed.
156
+ ///
157
+ /// [`TypeId`]: ::std::any::TypeId
158
+ #[ inline]
159
+ pub fn type_id( self ) -> :: std:: any:: TypeId {
160
+ ( self . vtable. ty) ( )
161
+ }
162
+ /// Returns true if this label was constructed from an instance of type `L`.
163
+ pub fn is<L : $label_name>( self ) -> bool {
164
+ self . type_id( ) == :: std:: any:: TypeId :: of:: <L >( )
110
165
}
111
166
}
112
167
113
168
impl $label_name for & ' static str {
114
- fn as_str( & self ) -> Self {
115
- self
169
+ fn data( & self ) -> u64 {
170
+ $crate:: label:: STR_INTERN . intern( self ) as u64
171
+ }
172
+ fn fmt( idx: u64 , f: & mut std:: fmt:: Formatter ) -> std:: fmt:: Result {
173
+ let s = $crate:: label:: STR_INTERN
174
+ . get( idx as usize )
175
+ . ok_or( :: std:: fmt:: Error ) ?;
176
+ write!( f, "{s}" )
116
177
}
117
178
}
118
179
} ;
0 commit comments