Skip to content

Commit f162434

Browse files
author
victor
committed
Fix: Correct offset for Unicode escape errors
This change corrects an error where the offset for a Unicode escape error was incorrectly adjusted. Previously, the offset was manually incremented by 2, causing errors for invalid escape sequences like `\uD83D` to report an incorrect position. The `handle_unicode_escape_from_slice` function already handles the offset correctly, so the manual adjustment was redundant and wrong. This fix removes the unnecessary offset adjustment, ensuring that error positions are now reported accurately.
1 parent ceb3c8b commit f162434

5 files changed

Lines changed: 56 additions & 3 deletions

File tree

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
/target
2-
/todo
2+
/todo
3+
/src/stream.rs

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file.
33
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
44
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
55

6+
## [0.1.3] - 2025-09-26
7+
8+
### Fixed
9+
10+
- **Corrected offset for Unicode escape errors.** Previously, an incorrect manual adjustment of `+2` was applied to the error offset, causing invalid escape sequences like `\uD83D` to report the wrong position. This change removes the redundant adjustment, ensuring error positions are now reported accurately.
11+
612
## [0.1.2] - 2025-09-25
713

814
### Added

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ keywords = [
1919
exclude = [
2020
"/.github",
2121
"/benches",
22+
"/src/stream.rs",
2223
]
2324

2425
[dependencies]

src/explicit.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -419,9 +419,9 @@ impl<'a> Iterator for Unescape<'a> {
419419
// that it can advance.
420420
match crate::Unescape::handle_unicode_escape_from_slice(&mut remainder) {
421421
Ok(c) => c,
422-
Err(mut e) => {
422+
Err(e) => {
423+
// FIX: handle_unicode_escape_from_slice already handles this for us.
423424
// Adjust offset: error is relative to `\u`, but we need it relative to chunk start.
424-
e.offset += 2; // for `\u`
425425
return Some(Err(e));
426426
}
427427
}
@@ -533,6 +533,12 @@ impl<'a> Unescape<'a> {
533533
lossy: true,
534534
}
535535
}
536+
537+
// TODO: Doc
538+
#[inline]
539+
pub(crate) const fn remnant(&self) -> &[u8] {
540+
self.bytes
541+
}
536542
}
537543

538544
impl fmt::Debug for Unescape<'_> {

src/lib.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ use core::{
8585
use memchr::memchr;
8686

8787
pub mod explicit;
88+
pub mod stream;
8889

8990
// =============================================================================
9091
// Escape Implementation
@@ -555,6 +556,7 @@ impl<'a> Unescape<'a> {
555556
}
556557
}
557558

559+
// FIXME: Replace iter with slice and match on b with a table
558560
/// Helper: parse exactly 4 hex digits from `it`. Returns Ok(u16) or an error.
559561
#[inline(always)]
560562
fn parse_hex4(iter: &mut slice::Iter<'a, u8>, base_offset: u8) -> Result<u16, UnescapeError> {
@@ -1788,6 +1790,13 @@ mod tests {
17881790
let got = escape_str(input).collect::<String>();
17891791
assert_eq!(got, want);
17901792

1793+
// Test PartialEq too
1794+
assert_eq!(escape_str(input), want);
1795+
1796+
// FIXME: Once logic is unified, remove this.
1797+
let got = explicit::escape_str(input).collect::<String>();
1798+
assert_eq!(got, want);
1799+
17911800
// Test PartialEq too
17921801
assert_eq!(escape_str(input), want)
17931802
}
@@ -1880,6 +1889,16 @@ mod tests {
18801889

18811890
// Help display
18821891
assert_display(unescape(input).display_utf8(), Ok(want));
1892+
1893+
// FIXME: Once logic is unified, remove this.
1894+
let got = explicit::unescape(input).decode_utf8().unwrap();
1895+
assert_eq!(got, want);
1896+
1897+
// Test PartialEq too
1898+
assert_eq!(explicit::unescape(input), want);
1899+
1900+
// Help display
1901+
assert_display(explicit::unescape(input).display_utf8(), Ok(want));
18831902
}
18841903

18851904
#[test]
@@ -1914,6 +1933,17 @@ mod tests {
19141933
})) => {}
19151934
_ => panic!("expected invalid escape"),
19161935
}
1936+
1937+
// FIXME: Once logic is unified, remove this.
1938+
let mut u = explicit::unescape(s);
1939+
1940+
match u.next() {
1941+
Some(Err(UnescapeError {
1942+
kind: UnescapeErrorKind::InvalidEscape(InvalidEscapeError { found: b'x' }),
1943+
offset: 1,
1944+
})) => {}
1945+
_ => panic!("expected invalid escape"),
1946+
}
19171947
}
19181948

19191949
#[test]
@@ -1941,6 +1971,15 @@ mod tests {
19411971
}
19421972
}
19431973
assert!(found);
1974+
1975+
// FIXME: Once logic is unified, remove this.
1976+
assert_eq!(
1977+
explicit::unescape(input).next(),
1978+
Some(Err(UnescapeError {
1979+
kind: UnescapeErrorKind::UnexpectedEof,
1980+
offset: 4,
1981+
}))
1982+
);
19441983
}
19451984

19461985
// ===================== Chunk_Eq ===================== //

0 commit comments

Comments
 (0)