11use std:: {
2- cell:: Cell ,
32 collections:: hash_map:: DefaultHasher ,
4- hash:: Hasher ,
3+ hash:: { Hash , Hasher } ,
54 iter, mem,
6- num:: Wrapping ,
7- sync:: atomic:: { AtomicUsize , Ordering } ,
85} ;
96
10- use proc_macro2:: TokenStream ;
7+ use proc_macro2:: { Delimiter , Spacing , TokenStream , TokenTree } ;
118use quote:: format_ident;
129use syn:: {
1310 parse:: { Parse , ParseStream } ,
@@ -120,7 +117,7 @@ impl Context {
120117 markers. push ( marker_string) ;
121118
122119 Ok ( Self {
123- builder : Builder :: new ( ) ,
120+ builder : Builder :: new ( & span ) ,
124121 args,
125122 marker,
126123 markers,
@@ -338,16 +335,16 @@ struct Builder {
338335}
339336
340337impl 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 ( ) }
343340 }
344341
345342 fn iter ( & self ) -> impl Iterator < Item = & Ident > + ' _ {
346343 self . variants . iter ( )
347344 }
348345
349346 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( ) ) ;
351348
352349 let path =
353350 path ( iter:: once ( self . ident . clone ( ) . into ( ) ) . chain ( iter:: once ( variant. clone ( ) . into ( ) ) ) ) ;
@@ -373,37 +370,59 @@ impl Builder {
373370}
374371
375372// =================================================================================================
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+ }
385382
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
388384
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) ,
396414 }
397- seed
398415 }
416+ }
399417
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+ }
409428}
0 commit comments