Skip to content

Commit 9cf99a9

Browse files
Stringify literals create client-side properly
1 parent 36d825f commit 9cf99a9

File tree

2 files changed

+51
-11
lines changed

2 files changed

+51
-11
lines changed

crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -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)]
420461
mod tests {
421462
use super::*;

crates/proc-macro-srv/src/tests/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ fn test_fn_like_mk_literals() {
7777
LITERAL b"byte_string" 4294967295
7878
LITERAL 'c' 4294967295
7979
LITERAL "string" 4294967295
80-
LITERAL "maybe \"raw\"?" 4294967295
8180
LITERAL 3.14f64 4294967295
8281
LITERAL 3.14 4294967295
8382
LITERAL 123i64 4294967295

0 commit comments

Comments
 (0)