23
23
//! ```
24
24
25
25
use proc_macro2:: { Span , TokenStream } ;
26
- use quote:: quote;
26
+ use quote:: { quote, ToTokens } ;
27
27
use std:: collections:: HashMap ;
28
+ use std:: hash:: { Hash , Hasher } ;
28
29
use syn:: parse:: { Parse , ParseStream , Result } ;
29
30
use syn:: { braced, punctuated:: Punctuated , Ident , LitStr , Token } ;
30
31
@@ -100,6 +101,46 @@ impl Errors {
100
101
}
101
102
}
102
103
104
+ struct PrefillStream {
105
+ prefill : [ Vec < String > ; 256 ] ,
106
+ }
107
+
108
+ impl PrefillStream {
109
+ fn new ( ) -> Self {
110
+ const EMPTY_VEC : Vec < String > = Vec :: new ( ) ;
111
+ PrefillStream { prefill : [ EMPTY_VEC ; 256 ] }
112
+ }
113
+
114
+ fn add_symbol ( & mut self , symbol : String ) -> u32 {
115
+ // Warning: hasher has to be kept in sync with rustc_span::symbols to ensure that all
116
+ // pre-filled symbols are assigned the correct shard.
117
+ let mut state = rustc_hash:: FxHasher :: default ( ) ;
118
+ symbol. hash ( & mut state) ;
119
+ let hash = state. finish ( ) ;
120
+
121
+ let shard = ( hash & 0xff ) as usize ;
122
+ let index = self . prefill [ shard] . len ( ) ;
123
+
124
+ self . prefill [ shard] . push ( symbol) ;
125
+
126
+ ( index << 8 ) as u32 | shard as u32
127
+ }
128
+ }
129
+
130
+ impl ToTokens for PrefillStream {
131
+ fn to_tokens ( & self , tokens : & mut TokenStream ) {
132
+ for shard in & self . prefill {
133
+ let mut shard_stream = quote ! { } ;
134
+ for symbol in shard {
135
+ shard_stream. extend ( quote ! { #symbol, } ) ;
136
+ }
137
+ tokens. extend ( quote ! {
138
+ & [ #shard_stream] ,
139
+ } ) ;
140
+ }
141
+ }
142
+ }
143
+
103
144
pub fn symbols ( input : TokenStream ) -> TokenStream {
104
145
let ( mut output, errors) = symbols_with_errors ( input) ;
105
146
@@ -126,8 +167,8 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
126
167
127
168
let mut keyword_stream = quote ! { } ;
128
169
let mut symbols_stream = quote ! { } ;
129
- let mut prefill_stream = quote ! { } ;
130
- let mut counter = 0u32 ;
170
+ let mut digit_stream = quote ! { } ;
171
+ let mut prefill_stream = PrefillStream :: new ( ) ;
131
172
let mut keys =
132
173
HashMap :: < String , Span > :: with_capacity ( input. keywords . len ( ) + input. symbols . len ( ) + 10 ) ;
133
174
let mut prev_key: Option < ( Span , String ) > = None ;
@@ -157,13 +198,10 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
157
198
let value = & keyword. value ;
158
199
let value_string = value. value ( ) ;
159
200
check_dup ( keyword. name . span ( ) , & value_string, & mut errors) ;
160
- prefill_stream. extend ( quote ! {
161
- #value,
162
- } ) ;
201
+ let sym = prefill_stream. add_symbol ( value_string) ;
163
202
keyword_stream. extend ( quote ! {
164
- pub const #name: Symbol = Symbol :: new( #counter ) ;
203
+ pub const #name: Symbol = Symbol :: new( #sym ) ;
165
204
} ) ;
166
- counter += 1 ;
167
205
}
168
206
169
207
// Generate the listed symbols.
@@ -176,30 +214,21 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
176
214
check_dup ( symbol. name . span ( ) , & value, & mut errors) ;
177
215
check_order ( symbol. name . span ( ) , & name. to_string ( ) , & mut errors) ;
178
216
179
- prefill_stream. extend ( quote ! {
180
- #value,
181
- } ) ;
217
+ let sym = prefill_stream. add_symbol ( value) ;
182
218
symbols_stream. extend ( quote ! {
183
- pub const #name: Symbol = Symbol :: new( #counter ) ;
219
+ pub const #name: Symbol = Symbol :: new( #sym ) ;
184
220
} ) ;
185
- counter += 1 ;
186
221
}
187
222
188
223
// Generate symbols for the strings "0", "1", ..., "9".
189
- let digits_base = counter;
190
- counter += 10 ;
191
224
for n in 0 ..10 {
192
225
let n = n. to_string ( ) ;
193
226
check_dup ( Span :: call_site ( ) , & n, & mut errors) ;
194
- prefill_stream. extend ( quote ! {
195
- #n,
196
- } ) ;
227
+ let sym = prefill_stream. add_symbol ( n) ;
228
+ digit_stream. extend ( quote ! { Symbol :: new( #sym) , } ) ;
197
229
}
198
- let _ = counter; // for future use
199
230
200
231
let output = quote ! {
201
- const SYMBOL_DIGITS_BASE : u32 = #digits_base;
202
-
203
232
#[ doc( hidden) ]
204
233
#[ allow( non_upper_case_globals) ]
205
234
mod kw_generated {
@@ -214,6 +243,8 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
214
243
#symbols_stream
215
244
}
216
245
246
+ const SYMBOL_DIGITS : [ Symbol ; 10 ] = [ #digit_stream] ;
247
+
217
248
impl Interner {
218
249
pub ( crate ) fn fresh( ) -> Self {
219
250
Interner :: prefill( & [
0 commit comments