6868
6969#![ recursion_limit = "128" ]
7070
71+ use proc_macro2:: Ident ;
7172use quote:: quote;
7273use std:: collections:: BTreeSet ;
7374use std:: fs:: File ;
@@ -185,8 +186,7 @@ impl AtomType {
185186 /// Write generated code to destination [`Vec<u8>`] and return it as [`String`]
186187 ///
187188 /// Used mostly for testing or displaying a value.
188- pub fn write_to_string ( & mut self , mut destination : Vec < u8 > ) -> io:: Result < String >
189- {
189+ pub fn write_to_string ( & mut self , mut destination : Vec < u8 > ) -> io:: Result < String > {
190190 destination. write_all (
191191 self . to_tokens ( )
192192 . to_string ( )
@@ -223,6 +223,30 @@ impl AtomType {
223223 let empty_string_index = atoms. iter ( ) . position ( |s| s. is_empty ( ) ) . unwrap ( ) as u32 ;
224224 let indices = 0 ..atoms. len ( ) as u32 ;
225225
226+ fn is_valid_ident ( name : & str ) -> bool {
227+ let begins_with_letter_or_underscore = name
228+ . chars ( )
229+ . next ( )
230+ . is_some_and ( |c| c. is_alphabetic ( ) || c == '_' ) ;
231+ let is_alphanumeric = name. chars ( ) . all ( |c| c. is_alphanumeric ( ) || c == '_' ) ;
232+
233+ begins_with_letter_or_underscore && is_alphanumeric
234+ }
235+
236+ let atoms_for_idents: Vec < & str > = atoms
237+ . iter ( )
238+ . copied ( )
239+ . filter ( |x| is_valid_ident ( x) )
240+ . collect ( ) ;
241+ let atom_idents: Vec < Ident > = atoms_for_idents. iter ( ) . map ( |atom| new_term ( atom) ) . collect ( ) ;
242+
243+ let istrs_for_idents: Vec < & str > = inline_strs
244+ . iter ( )
245+ . copied ( )
246+ . filter ( |x| is_valid_ident ( x) )
247+ . collect ( ) ;
248+ let istr_idents: Vec < Ident > = istrs_for_idents. iter ( ) . map ( |atom| new_term ( atom) ) . collect ( ) ;
249+
226250 let hashes: Vec < u32 > = atoms
227251 . iter ( )
228252 . map ( |string| {
@@ -249,8 +273,9 @@ impl AtomType {
249273 Some ( ref doc) => quote ! ( #[ doc = #doc] ) ,
250274 None => quote ! ( ) ,
251275 } ;
252- let new_term =
253- |string : & str | proc_macro2:: Ident :: new ( string, proc_macro2:: Span :: call_site ( ) ) ;
276+ fn new_term ( string : & str ) -> Ident {
277+ Ident :: new ( string, proc_macro2:: Span :: call_site ( ) )
278+ }
254279 let static_set_name = new_term ( & format ! ( "{}StaticSet" , type_name) ) ;
255280 let type_name = new_term ( type_name) ;
256281 let macro_name = new_term ( & * self . macro_name ) ;
@@ -264,6 +289,16 @@ impl AtomType {
264289 new_term ( & name)
265290 } ;
266291 let const_names: Vec < _ > = atoms. iter ( ) . copied ( ) . map ( new_const_name) . collect ( ) ;
292+ let ident_const_names: Vec < _ > = atoms_for_idents
293+ . iter ( )
294+ . copied ( )
295+ . map ( new_const_name)
296+ . collect ( ) ;
297+ let ident_inline_const_names: Vec < _ > = istrs_for_idents
298+ . iter ( )
299+ . copied ( )
300+ . map ( new_const_name)
301+ . collect ( ) ;
267302
268303 // Inline strings
269304 let ( inline_const_names, inline_values_and_lengths) : ( Vec < _ > , Vec < _ > ) = inline_strs
@@ -323,6 +358,12 @@ impl AtomType {
323358 #(
324359 ( #inline_strs) => { #module:: #inline_const_names } ;
325360 ) *
361+ #(
362+ ( #atom_idents) => { #module:: #ident_const_names } ;
363+ ) *
364+ #(
365+ ( #istr_idents) => { #module:: #ident_inline_const_names } ;
366+ ) *
326367 }
327368 }
328369 }
@@ -340,11 +381,13 @@ impl AtomType {
340381fn test_iteration_order ( ) {
341382 let x1 = crate :: AtomType :: new ( "foo::Atom" , "foo_atom!" )
342383 . atoms ( & [ "x" , "xlink" , "svg" , "test" ] )
343- . write_to_string ( Vec :: new ( ) ) . expect ( "write to string cache x1" ) ;
384+ . write_to_string ( Vec :: new ( ) )
385+ . expect ( "write to string cache x1" ) ;
344386
345387 let x2 = crate :: AtomType :: new ( "foo::Atom" , "foo_atom!" )
346388 . atoms ( & [ "x" , "xlink" , "svg" , "test" ] )
347- . write_to_string ( Vec :: new ( ) ) . expect ( "write to string cache x2" ) ;
389+ . write_to_string ( Vec :: new ( ) )
390+ . expect ( "write to string cache x2" ) ;
348391
349392 assert_eq ! ( x1, x2) ;
350393}
0 commit comments