diff options
author | Lukas Wirth <[email protected]> | 2020-11-26 22:08:02 +0000 |
---|---|---|
committer | Lukas Wirth <[email protected]> | 2020-11-27 11:03:58 +0000 |
commit | 347da74edabf329ce84ec81cf22bd65ef944199b (patch) | |
tree | 004c9e2a1f3d0e8c8f188fd8b469556658bb4536 /crates/syntax/src | |
parent | fc0354b2803bccfeb6e0c3335a5d4e52288c05b4 (diff) |
Avoid allocation in ast::String::value if the string needs no unescaping
Diffstat (limited to 'crates/syntax/src')
-rw-r--r-- | crates/syntax/src/ast/token_ext.rs | 27 |
1 files changed, 18 insertions, 9 deletions
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs index ac0326420..b985861f2 100644 --- a/crates/syntax/src/ast/token_ext.rs +++ b/crates/syntax/src/ast/token_ext.rs | |||
@@ -130,19 +130,28 @@ impl ast::String { | |||
130 | let text = self.text().as_str(); | 130 | let text = self.text().as_str(); |
131 | let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; | 131 | let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; |
132 | 132 | ||
133 | let mut buf = String::with_capacity(text.len()); | 133 | let mut buf = String::new(); |
134 | let mut text_iter = text.chars(); | ||
134 | let mut has_error = false; | 135 | let mut has_error = false; |
135 | unescape_literal(text, Mode::Str, &mut |_, unescaped_char| match unescaped_char { | 136 | unescape_literal(text, Mode::Str, &mut |char_range, unescaped_char| match ( |
136 | Ok(c) => buf.push(c), | 137 | unescaped_char, |
137 | Err(_) => has_error = true, | 138 | buf.capacity() == 0, |
139 | ) { | ||
140 | (Ok(c), false) => buf.push(c), | ||
141 | (Ok(c), true) if Some(c) == text_iter.next() => (), | ||
142 | (Ok(c), true) => { | ||
143 | buf.reserve_exact(text.len()); | ||
144 | buf.push_str(&text[..char_range.start]); | ||
145 | buf.push(c); | ||
146 | } | ||
147 | (Err(_), _) => has_error = true, | ||
138 | }); | 148 | }); |
139 | 149 | ||
140 | if has_error { | 150 | match (has_error, buf.capacity() == 0) { |
141 | return None; | 151 | (true, _) => None, |
152 | (false, true) => Some(Cow::Borrowed(text)), | ||
153 | (false, false) => Some(Cow::Owned(buf)), | ||
142 | } | 154 | } |
143 | // FIXME: don't actually allocate for borrowed case | ||
144 | let res = if buf == text { Cow::Borrowed(text) } else { Cow::Owned(buf) }; | ||
145 | Some(res) | ||
146 | } | 155 | } |
147 | 156 | ||
148 | pub fn quote_offsets(&self) -> Option<QuoteOffsets> { | 157 | pub fn quote_offsets(&self) -> Option<QuoteOffsets> { |