@@ -132,17 +132,11 @@ impl server::TokenStream for RustAnalyzer {
132132 }
133133
134134 bridge:: TokenTree :: Literal ( literal) => {
135- // FIXME: remove unnecessary clones here
136- let symbol = ThreadLocalSymbolInterner :: get_cloned ( & literal. symbol ) ;
137-
138- let text: tt:: SmolStr = if let Some ( suffix) = literal. suffix {
139- let suffix = ThreadLocalSymbolInterner :: get_cloned ( & suffix) ;
140- format ! ( "{symbol}{suffix}" ) . into ( )
141- } else {
142- symbol
143- } ;
135+ let literal = LiteralFormatter ( literal) ;
136+ let text = literal
137+ . with_stringify_parts ( |parts| tt:: SmolStr :: from_iter ( parts. iter ( ) . copied ( ) ) ) ;
144138
145- let literal = tt:: Literal { text, id : literal. span } ;
139+ let literal = tt:: Literal { text, id : literal. 0 . span } ;
146140 let leaf = tt:: Leaf :: from ( literal) ;
147141 let tree = TokenTree :: from ( leaf) ;
148142 Self :: TokenStream :: from_iter ( vec ! [ tree] )
@@ -416,6 +410,53 @@ impl server::Server for RustAnalyzer {
416410 }
417411}
418412
413+ struct LiteralFormatter ( bridge:: Literal < tt:: TokenId , Symbol > ) ;
414+
415+ impl LiteralFormatter {
416+ /// Invokes the callback with a `&[&str]` consisting of each part of the
417+ /// literal's representation. This is done to allow the `ToString` and
418+ /// `Display` implementations to borrow references to symbol values, and
419+ /// both be optimized to reduce overhead.
420+ fn with_stringify_parts < R > ( & self , f : impl FnOnce ( & [ & str ] ) -> R ) -> R {
421+ /// Returns a string containing exactly `num` '#' characters.
422+ /// Uses a 256-character source string literal which is always safe to
423+ /// index with a `u8` index.
424+ fn get_hashes_str ( num : u8 ) -> & ' static str {
425+ const HASHES : & str = "\
426+ ################################################################\
427+ ################################################################\
428+ ################################################################\
429+ ################################################################\
430+ ";
431+ const _: ( ) = assert ! ( HASHES . len( ) == 256 ) ;
432+ & HASHES [ ..num as usize ]
433+ }
434+
435+ self . with_symbol_and_suffix ( |symbol, suffix| match self . 0 . kind {
436+ bridge:: LitKind :: Byte => f ( & [ "b'" , symbol, "'" , suffix] ) ,
437+ bridge:: LitKind :: Char => f ( & [ "'" , symbol, "'" , suffix] ) ,
438+ bridge:: LitKind :: Str => f ( & [ "\" " , symbol, "\" " , suffix] ) ,
439+ bridge:: LitKind :: StrRaw ( n) => {
440+ let hashes = get_hashes_str ( n) ;
441+ f ( & [ "r" , hashes, "\" " , symbol, "\" " , hashes, suffix] )
442+ }
443+ bridge:: LitKind :: ByteStr => f ( & [ "b\" " , symbol, "\" " , suffix] ) ,
444+ bridge:: LitKind :: ByteStrRaw ( n) => {
445+ let hashes = get_hashes_str ( n) ;
446+ f ( & [ "br" , hashes, "\" " , symbol, "\" " , hashes, suffix] )
447+ }
448+ _ => f ( & [ symbol, suffix] ) ,
449+ } )
450+ }
451+
452+ fn with_symbol_and_suffix < R > ( & self , f : impl FnOnce ( & str , & str ) -> R ) -> R {
453+ ThreadLocalSymbolInterner :: with ( & self . 0 . symbol , |symbol| match self . 0 . suffix . as_ref ( ) {
454+ Some ( suffix) => ThreadLocalSymbolInterner :: with ( suffix, |suffix| f ( symbol, suffix) ) ,
455+ None => f ( symbol, "" ) ,
456+ } )
457+ }
458+ }
459+
419460#[ cfg( test) ]
420461mod tests {
421462 use super :: * ;
0 commit comments