@@ -130,19 +130,28 @@ impl ast::String {
130130 let text = self . text ( ) . as_str ( ) ;
131131 let text = & text[ self . text_range_between_quotes ( ) ? - self . syntax ( ) . text_range ( ) . start ( ) ] ;
132132
133- let mut buf = String :: with_capacity ( text. len ( ) ) ;
133+ let mut buf = String :: new ( ) ;
134+ let mut text_iter = text. chars ( ) ;
134135 let mut has_error = false ;
135- unescape_literal ( text, Mode :: Str , & mut |_, unescaped_char| match unescaped_char {
136- Ok ( c) => buf. push ( c) ,
137- Err ( _) => has_error = true ,
136+ unescape_literal ( text, Mode :: Str , & mut |char_range, unescaped_char| match (
137+ unescaped_char,
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 ,
138148 } ) ;
139149
140- if has_error {
141- return None ;
150+ match ( has_error, buf. capacity ( ) == 0 ) {
151+ ( true , _) => None ,
152+ ( false , true ) => Some ( Cow :: Borrowed ( text) ) ,
153+ ( false , false ) => Some ( Cow :: Owned ( buf) ) ,
142154 }
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)
146155 }
147156
148157 pub fn quote_offsets ( & self ) -> Option < QuoteOffsets > {
0 commit comments