diff options
| author | Maybe Waffle <waffle.lapkin@gmail.com> | 2022-01-30 15:32:21 +0300 |
|---|---|---|
| committer | Maybe Waffle <waffle.lapkin@gmail.com> | 2022-01-30 15:32:21 +0300 |
| commit | 17cd2cd5927cf1075efbd0f4a859182eb102b920 (patch) | |
| tree | 0dd16de8c7d60190247c36e8149f18150fd88c76 | |
| parent | 2c97d1012e52c9a7ac217a15cce71473cc070e26 (diff) | |
| download | rust-17cd2cd5927cf1075efbd0f4a859182eb102b920.tar.gz rust-17cd2cd5927cf1075efbd0f4a859182eb102b920.zip | |
Fix an edge case in `chat::DecodeUtf16::size_hint`
There are cases, when data in the buf might or might not be an error.
| -rw-r--r-- | library/core/src/char/decode.rs | 30 | ||||
| -rw-r--r-- | library/core/tests/char.rs | 1 |
2 files changed, 20 insertions, 11 deletions
diff --git a/library/core/src/char/decode.rs b/library/core/src/char/decode.rs index 81d49ffe06e..8b9f979b573 100644 --- a/library/core/src/char/decode.rs +++ b/library/core/src/char/decode.rs @@ -121,23 +121,31 @@ impl<I: Iterator<Item = u16>> Iterator for DecodeUtf16<I> { fn size_hint(&self) -> (usize, Option<usize>) { let (low, high) = self.iter.size_hint(); - // If - // - `self.buf` contains a non surrogate (`u < 0xD800 || 0xDFFF < u`), or - // - `high == Some(0)` (and `self.buf` contains a leading surrogate since - // it can never contain a trailing surrogate) - // - // then buf contains an additional character or error that doesn't - // need a pair from `self.iter`, so it's +1 additional element. - let addition_from_buf = - self.buf.map_or(false, |u| u < 0xD800 || 0xDFFF < u || high == Some(0)) as usize; + let (low_buf, high_buf) = match self.buf { + // buf is empty, no additional elements from it. + None => (0, 0), + // `u` is a non surrogate, so it's always an additional character. + Some(u) if u < 0xD800 || 0xDFFF < u => (1, 1), + // `u` is a leading surrogate (it can never be a trailing surrogate and + // it's a surrogate due to the previous branch) and `self.iter` is empty. + // + // `u` can't be paired, since the `self.iter` is empty, + // so it will always become an additional element (error). + Some(_u) if high == Some(0) => (1, 1), + // `u` is a leading surrogate and `iter` may be non-empty. + // + // `u` can either pair with a trailing surrogate, in which case no additional elements + // are produced, or it can become an error, in which case it's an additional character (error). + Some(_u) => (0, 1), + }; // `self.iter` could contain entirely valid surrogates (2 elements per // char), or entirely non-surrogates (1 element per char). // // On odd lower bound, at least one element must stay unpaired // (with other elements from `self.iter`), so we round up. - let low = low.div_ceil(2) + addition_from_buf; - let high = high.and_then(|h| h.checked_add(addition_from_buf)); + let low = low.div_ceil(2) + low_buf; + let high = high.and_then(|h| h.checked_add(high_buf)); (low, high) } diff --git a/library/core/tests/char.rs b/library/core/tests/char.rs index 347ac04feb3..4c899b6eb43 100644 --- a/library/core/tests/char.rs +++ b/library/core/tests/char.rs @@ -329,6 +329,7 @@ fn test_decode_utf16_size_hint() { } check(&[0xD800, 0xD800, 0xDC00]); + check(&[0xD800, 0xD800, 0x0]); check(&[0xD800, 0x41, 0x42]); check(&[0xD800, 0]); check(&[0xD834, 0x006d]); |
