3
3
use std:: {
4
4
any:: Any ,
5
5
hash:: { Hash , Hasher } ,
6
+ marker:: PhantomData ,
6
7
} ;
7
8
8
9
pub trait DynEq : Any {
47
48
}
48
49
}
49
50
51
+ #[ doc( hidden) ]
52
+ /// A string slice, stuffed with a payload of data `16` bits long.
53
+ /// This means that the maximum length of the string is `2^(size-16)`,
54
+ /// where `size` is either 32 or 64 depending on your computer.
55
+ #[ derive( Clone , Copy ) ]
56
+ pub struct StuffedStr < ' a > {
57
+ ptr : * const u8 ,
58
+ marker : PhantomData < & ' a str > ,
59
+
60
+ /// lower 16 bits stores the data,
61
+ /// upper 48 or 16 bits stores the length of the string.
62
+ /// This layout optimizes for calling `.data()`
63
+ meta : usize ,
64
+ }
65
+
66
+ unsafe impl < ' a > Send for StuffedStr < ' a > { }
67
+ unsafe impl < ' a > Sync for StuffedStr < ' a > { }
68
+
69
+ impl < ' a > StuffedStr < ' a > {
70
+ const DATA_MASK : usize = !Self :: LEN_MASK ;
71
+ const LEN_MASK : usize = !0 << 16 ;
72
+
73
+ pub fn new ( str : & ' a str , data : u16 ) -> Self {
74
+ #[ cold]
75
+ #[ inline( never) ]
76
+ fn panic ( ) -> ! {
77
+ // needs a better message but its late
78
+ panic ! ( "string exceeds {} bytes" , StuffedStr :: LEN_MASK >> 16 ) ;
79
+ }
80
+
81
+ let ptr = str. as_ptr ( ) ;
82
+ // Make sure there's enough room to store the data.
83
+ if str. len ( ) . leading_zeros ( ) < 16 {
84
+ panic ( ) ;
85
+ }
86
+ let meta = data as usize | str. len ( ) << 16 ;
87
+ Self {
88
+ ptr,
89
+ marker : PhantomData ,
90
+ meta,
91
+ }
92
+ }
93
+
94
+ fn len ( & self ) -> usize {
95
+ self . meta >> 16
96
+ }
97
+ pub fn data ( & self ) -> u16 {
98
+ let data = self . meta & Self :: DATA_MASK ;
99
+ data as u16
100
+ }
101
+ pub fn as_str ( & self ) -> & ' a str {
102
+ // SAFETY: this instance was constructed from a string slice of length `len`, and lifetime `'a`.
103
+ // It is sound to convert it back to a slice.
104
+ unsafe {
105
+ let slice = std:: slice:: from_raw_parts ( self . ptr , self . len ( ) ) ;
106
+ std:: str:: from_utf8_unchecked ( slice)
107
+ }
108
+ }
109
+ }
110
+
50
111
/// Macro to define a new label trait
51
112
///
52
113
/// # Example
@@ -71,11 +132,7 @@ macro_rules! define_label {
71
132
) => {
72
133
$( #[ $id_attr] ) *
73
134
#[ derive( Clone , Copy ) ]
74
- pub struct $id_name {
75
- ty: :: core:: any:: TypeId ,
76
- data: u64 ,
77
- text: & ' static str
78
- }
135
+ pub struct $id_name( :: core:: any:: TypeId , $crate:: label:: StuffedStr <' static >) ;
79
136
80
137
impl :: core:: fmt:: Debug for $id_name {
81
138
fn fmt( & self , f: & mut :: core:: fmt:: Formatter ) -> :: core:: fmt:: Result {
@@ -90,14 +147,15 @@ macro_rules! define_label {
90
147
let ty = self . type_id( ) ;
91
148
let data = self . data( ) ;
92
149
let text = self . as_str( ) ;
93
- $id_name { ty, data, text }
150
+ let stuffed = $crate:: label:: StuffedStr :: new( text, data) ;
151
+ $id_name( ty, stuffed)
94
152
}
95
153
/// Returns the [`TypeId`] used to differentiate labels.
96
154
fn type_id( & self ) -> :: core:: any:: TypeId {
97
155
:: core:: any:: TypeId :: of:: <Self >( )
98
156
}
99
157
/// Returns a number used to distinguish different labels of the same type.
100
- fn data( & self ) -> u64 ;
158
+ fn data( & self ) -> u16 ;
101
159
/// Returns the representation of this label as a string literal.
102
160
///
103
161
/// In cases where you absolutely need a label to be determined at runtime,
@@ -110,13 +168,13 @@ macro_rules! define_label {
110
168
* self
111
169
}
112
170
fn type_id( & self ) -> :: core:: any:: TypeId {
113
- self . ty
171
+ self . 0
114
172
}
115
- fn data( & self ) -> u64 {
116
- self . data
173
+ fn data( & self ) -> u16 {
174
+ self . 1 . data( )
117
175
}
118
176
fn as_str( & self ) -> & ' static str {
119
- self . text
177
+ self . 1 . as_str ( )
120
178
}
121
179
}
122
180
0 commit comments