1
1
use std:: {
2
- cell:: Cell ,
3
2
collections:: hash_map:: DefaultHasher ,
4
- hash:: Hasher ,
3
+ hash:: { Hash , Hasher } ,
5
4
iter, mem,
6
- num:: Wrapping ,
7
- sync:: atomic:: { AtomicUsize , Ordering } ,
8
5
} ;
9
6
10
- use proc_macro2:: TokenStream ;
7
+ use proc_macro2:: { Delimiter , Spacing , TokenStream , TokenTree } ;
11
8
use quote:: format_ident;
12
9
use syn:: {
13
10
parse:: { Parse , ParseStream } ,
@@ -120,7 +117,7 @@ impl Context {
120
117
markers. push ( marker_string) ;
121
118
122
119
Ok ( Self {
123
- builder : Builder :: new ( ) ,
120
+ builder : Builder :: new ( & span ) ,
124
121
args,
125
122
marker,
126
123
markers,
@@ -338,16 +335,16 @@ struct Builder {
338
335
}
339
336
340
337
impl Builder {
341
- fn new ( ) -> Self {
342
- Self { ident : format_ident ! ( "___Enum {}" , random ( ) ) , variants : Vec :: new ( ) }
338
+ fn new ( input : & TokenStream ) -> Self {
339
+ Self { ident : format_ident ! ( "__Enum {}" , hash ( input ) ) , variants : Vec :: new ( ) }
343
340
}
344
341
345
342
fn iter ( & self ) -> impl Iterator < Item = & Ident > + ' _ {
346
343
self . variants . iter ( )
347
344
}
348
345
349
346
fn next_expr ( & mut self , attrs : Vec < Attribute > , expr : Expr ) -> Expr {
350
- let variant = format_ident ! ( "___Variant {}" , self . variants. len( ) ) ;
347
+ let variant = format_ident ! ( "__Variant {}" , self . variants. len( ) ) ;
351
348
352
349
let path =
353
350
path ( iter:: once ( self . ident . clone ( ) . into ( ) ) . chain ( iter:: once ( variant. clone ( ) . into ( ) ) ) ) ;
@@ -373,37 +370,59 @@ impl Builder {
373
370
}
374
371
375
372
// =================================================================================================
376
- // RNG
377
-
378
- /// Pseudorandom number generator based on [xorshift*] .
379
- ///
380
- /// [xorshift*]: https://en.wikipedia.org/wiki/Xorshift#xorshift*
381
- fn random ( ) -> u64 {
382
- thread_local ! {
383
- static RNG : Cell < Wrapping < u64 >> = Cell :: new ( Wrapping ( prng_seed ( ) ) ) ;
384
- }
373
+ // Hash
374
+
375
+ /// Returns the hash value of the input AST .
376
+ fn hash ( tokens : & TokenStream ) -> u64 {
377
+ let tokens = TokenStreamHelper ( tokens ) ;
378
+ let mut hasher = DefaultHasher :: new ( ) ;
379
+ tokens . hash ( & mut hasher ) ;
380
+ hasher . finish ( )
381
+ }
385
382
386
- fn prng_seed ( ) -> u64 {
387
- static COUNTER : AtomicUsize = AtomicUsize :: new ( 0 ) ;
383
+ // Based on https://github.com/dtolnay/syn/blob/1.0.5/src/tt.rs
388
384
389
- // Any non-zero seed will do -- this uses the hash of a global counter.
390
- // Refs: https://github.com/rayon-rs/rayon/pull/571
391
- let mut seed = 0 ;
392
- while seed == 0 {
393
- let mut hasher = DefaultHasher :: new ( ) ;
394
- hasher. write_usize ( COUNTER . fetch_add ( 1 , Ordering :: Relaxed ) ) ;
395
- seed = hasher. finish ( ) ;
385
+ struct TokenTreeHelper < ' a > ( & ' a TokenTree ) ;
386
+
387
+ impl Hash for TokenTreeHelper < ' _ > {
388
+ fn hash < H : Hasher > ( & self , h : & mut H ) {
389
+ match self . 0 {
390
+ TokenTree :: Group ( g) => {
391
+ 0_u8 . hash ( h) ;
392
+ match g. delimiter ( ) {
393
+ Delimiter :: Parenthesis => 0_u8 . hash ( h) ,
394
+ Delimiter :: Brace => 1_u8 . hash ( h) ,
395
+ Delimiter :: Bracket => 2_u8 . hash ( h) ,
396
+ Delimiter :: None => 3_u8 . hash ( h) ,
397
+ }
398
+
399
+ for tt in g. stream ( ) {
400
+ TokenTreeHelper ( & tt) . hash ( h) ;
401
+ }
402
+ 0xff_u8 . hash ( h) ; // terminator w/ a variant we don't normally hash
403
+ }
404
+ TokenTree :: Punct ( op) => {
405
+ 1_u8 . hash ( h) ;
406
+ op. as_char ( ) . hash ( h) ;
407
+ match op. spacing ( ) {
408
+ Spacing :: Alone => 0_u8 . hash ( h) ,
409
+ Spacing :: Joint => 1_u8 . hash ( h) ,
410
+ }
411
+ }
412
+ TokenTree :: Literal ( lit) => ( 2_u8 , lit. to_string ( ) ) . hash ( h) ,
413
+ TokenTree :: Ident ( word) => ( 3_u8 , word) . hash ( h) ,
396
414
}
397
- seed
398
415
}
416
+ }
399
417
400
- RNG . with ( |rng| {
401
- let mut x = rng. get ( ) ;
402
- debug_assert_ne ! ( x. 0 , 0 ) ;
403
- x ^= x >> 12 ;
404
- x ^= x << 25 ;
405
- x ^= x >> 27 ;
406
- rng. set ( x) ;
407
- x. 0 . wrapping_mul ( 0x2545_f491_4f6c_dd1d )
408
- } )
418
+ struct TokenStreamHelper < ' a > ( & ' a TokenStream ) ;
419
+
420
+ impl Hash for TokenStreamHelper < ' _ > {
421
+ fn hash < H : Hasher > ( & self , state : & mut H ) {
422
+ let tokens = self . 0 . clone ( ) . into_iter ( ) . collect :: < Vec < _ > > ( ) ;
423
+ tokens. len ( ) . hash ( state) ;
424
+ for tt in tokens {
425
+ TokenTreeHelper ( & tt) . hash ( state) ;
426
+ }
427
+ }
409
428
}
0 commit comments