@@ -209,17 +209,19 @@ impl ast::String {
209209 let text = & text[ self . text_range_between_quotes ( ) ? - self . syntax ( ) . text_range ( ) . start ( ) ] ;
210210
211211 let mut buf = String :: new ( ) ;
212- let mut text_iter = text . chars ( ) ;
212+ let mut prev_end = 0 ;
213213 let mut has_error = false ;
214214 unescape_literal ( text, Mode :: Str , & mut |char_range, unescaped_char| match (
215215 unescaped_char,
216216 buf. capacity ( ) == 0 ,
217217 ) {
218218 ( Ok ( c) , false ) => buf. push ( c) ,
219- ( Ok ( c) , true ) if char_range. len ( ) == 1 && Some ( c) == text_iter. next ( ) => ( ) ,
219+ ( Ok ( _) , true ) if char_range. len ( ) == 1 && char_range. start == prev_end => {
220+ prev_end = char_range. end
221+ }
220222 ( Ok ( c) , true ) => {
221223 buf. reserve_exact ( text. len ( ) ) ;
222- buf. push_str ( & text[ ..char_range . start ] ) ;
224+ buf. push_str ( & text[ ..prev_end ] ) ;
223225 buf. push ( c) ;
224226 }
225227 ( Err ( _) , _) => has_error = true ,
@@ -252,17 +254,19 @@ impl ast::ByteString {
252254 let text = & text[ self . text_range_between_quotes ( ) ? - self . syntax ( ) . text_range ( ) . start ( ) ] ;
253255
254256 let mut buf: Vec < u8 > = Vec :: new ( ) ;
255- let mut text_iter = text . chars ( ) ;
257+ let mut prev_end = 0 ;
256258 let mut has_error = false ;
257259 unescape_literal ( text, Mode :: ByteStr , & mut |char_range, unescaped_char| match (
258260 unescaped_char,
259261 buf. capacity ( ) == 0 ,
260262 ) {
261263 ( Ok ( c) , false ) => buf. push ( c as u8 ) ,
262- ( Ok ( c) , true ) if char_range. len ( ) == 1 && Some ( c) == text_iter. next ( ) => ( ) ,
264+ ( Ok ( _) , true ) if char_range. len ( ) == 1 && char_range. start == prev_end => {
265+ prev_end = char_range. end
266+ }
263267 ( Ok ( c) , true ) => {
264268 buf. reserve_exact ( text. len ( ) ) ;
265- buf. extend_from_slice ( text[ ..char_range . start ] . as_bytes ( ) ) ;
269+ buf. extend_from_slice ( text[ ..prev_end ] . as_bytes ( ) ) ;
266270 buf. push ( c as u8 ) ;
267271 }
268272 ( Err ( _) , _) => has_error = true ,
@@ -445,6 +449,36 @@ mod tests {
445449 check_string_value ( r"\foobar" , None ) ;
446450 check_string_value ( r"\nfoobar" , "\n foobar" ) ;
447451 check_string_value ( r"C:\\Windows\\System32\\" , "C:\\ Windows\\ System32\\ " ) ;
452+ check_string_value ( r"\x61bcde" , "abcde" ) ;
453+ check_string_value (
454+ r"a\
455+ bcde" , "abcde" ,
456+ ) ;
457+ }
458+
459+ fn check_byte_string_value < ' a , const N : usize > (
460+ lit : & str ,
461+ expected : impl Into < Option < & ' a [ u8 ; N ] > > ,
462+ ) {
463+ assert_eq ! (
464+ ast:: ByteString { syntax: make:: tokens:: literal( & format!( "b\" {}\" " , lit) ) }
465+ . value( )
466+ . as_deref( ) ,
467+ expected. into( ) . map( |value| & value[ ..] )
468+ ) ;
469+ }
470+
471+ #[ test]
472+ fn test_byte_string_escape ( ) {
473+ check_byte_string_value ( r"foobar" , b"foobar" ) ;
474+ check_byte_string_value ( r"\foobar" , None :: < & [ u8 ; 0 ] > ) ;
475+ check_byte_string_value ( r"\nfoobar" , b"\n foobar" ) ;
476+ check_byte_string_value ( r"C:\\Windows\\System32\\" , b"C:\\ Windows\\ System32\\ " ) ;
477+ check_byte_string_value ( r"\x61bcde" , b"abcde" ) ;
478+ check_byte_string_value (
479+ r"a\
480+ bcde" , b"abcde" ,
481+ ) ;
448482 }
449483
450484 #[ test]
0 commit comments