diff --git a/Lib/test/test_json/test_unicode.py b/Lib/test/test_json/test_unicode.py index 8f78a633a..e9ec511c3 100644 --- a/Lib/test/test_json/test_unicode.py +++ b/Lib/test/test_json/test_unicode.py @@ -38,8 +38,6 @@ class TestUnicode: self.assertEqual(self.loads('"' + u + '"'), u) self.assertEqual(self.loads('"z\\ud834\\udd20x"'), u) - # just takes FOREVER (3min+), unskip when it doesn't - @unittest.skip("TODO: RUSTPYTHON time") def test_unicode_decode(self): for i in range(0, 0xd7ff): u = chr(i) diff --git a/extra_tests/snippets/json_snippet.py b/extra_tests/snippets/json_snippet.py index 60e1020ce..a91f3bd81 100644 --- a/extra_tests/snippets/json_snippet.py +++ b/extra_tests/snippets/json_snippet.py @@ -184,3 +184,5 @@ assert json_dump({'a': 'b'}) == json_dump(Dict({'a': 'b'})) i = 7**500 assert json.dumps(i) == str(i) + +assert json.decoder.scanstring('✨x"', 1) == ('x', 3) diff --git a/vm/src/stdlib/json/machinery.rs b/vm/src/stdlib/json/machinery.rs index fe0051a87..7c9ac3ac4 100644 --- a/vm/src/stdlib/json/machinery.rs +++ b/vm/src/stdlib/json/machinery.rs @@ -136,12 +136,12 @@ pub fn scanstring<'a>( chunks.push(chunk); }; let unterminated_err = || DecodeError::new("Unterminated string starting at", end - 1); - let mut chunk_start = end; let mut chars = s.char_indices().enumerate().skip(end).peekable(); - while let Some((char_i, (i, c))) = chars.next() { + let (_, (mut chunk_start, _)) = chars.peek().ok_or_else(unterminated_err)?; + while let Some((char_i, (byte_i, c))) = chars.next() { match c { '"' => { - push_chunk(StrOrChar::Str(&s[chunk_start..i])); + push_chunk(StrOrChar::Str(&s[chunk_start..byte_i])); let mut out = String::with_capacity(output_len); for x in chunks { match x { @@ -152,7 +152,7 @@ pub fn scanstring<'a>( return Ok((out, char_i + 1)); } '\\' => { - push_chunk(StrOrChar::Str(&s[chunk_start..i])); + push_chunk(StrOrChar::Str(&s[chunk_start..byte_i])); let (_, (_, c)) = chars.next().ok_or_else(unterminated_err)?; let esc = match c { '"' => "\"", @@ -166,7 +166,7 @@ pub fn scanstring<'a>( 'u' => { let surrogate_err = || DecodeError::new("unpaired surrogate", char_i); let mut uni = decode_unicode(&mut chars, char_i)?; - chunk_start = char_i + 6; + chunk_start = byte_i + 6; if (0xd800..=0xdbff).contains(&uni) { // uni is a surrogate -- try to find its pair if let Some(&(pos2, (_, '\\'))) = chars.peek() { @@ -202,7 +202,7 @@ pub fn scanstring<'a>( )) } }; - chunk_start = i + 2; + chunk_start = byte_i + 2; push_chunk(StrOrChar::Str(esc)); } '\x00'..='\x1f' if strict => {