@@ -132,17 +132,11 @@ impl server::TokenStream for RustAnalyzer {
132
132
}
133
133
134
134
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 ( ) ) ) ;
144
138
145
- let literal = tt:: Literal { text, id : literal. span } ;
139
+ let literal = tt:: Literal { text, id : literal. 0 . span } ;
146
140
let leaf = tt:: Leaf :: from ( literal) ;
147
141
let tree = TokenTree :: from ( leaf) ;
148
142
Self :: TokenStream :: from_iter ( vec ! [ tree] )
@@ -416,6 +410,53 @@ impl server::Server for RustAnalyzer {
416
410
}
417
411
}
418
412
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
+
419
460
#[ cfg( test) ]
420
461
mod tests {
421
462
use super :: * ;
0 commit comments