Skip to content

Commit 17cd2cd

Browse files
committed
Fix an edge case in chat::DecodeUtf16::size_hint
There are cases, when data in the buf might or might not be an error.
1 parent 2c97d10 commit 17cd2cd

File tree

2 files changed

+20
-11
lines changed

2 files changed

+20
-11
lines changed

library/core/src/char/decode.rs

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -121,23 +121,31 @@ impl<I: Iterator<Item = u16>> Iterator for DecodeUtf16<I> {
121121
fn size_hint(&self) -> (usize, Option<usize>) {
122122
let (low, high) = self.iter.size_hint();
123123

124-
// If
125-
// - `self.buf` contains a non surrogate (`u < 0xD800 || 0xDFFF < u`), or
126-
// - `high == Some(0)` (and `self.buf` contains a leading surrogate since
127-
// it can never contain a trailing surrogate)
128-
//
129-
// then buf contains an additional character or error that doesn't
130-
// need a pair from `self.iter`, so it's +1 additional element.
131-
let addition_from_buf =
132-
self.buf.map_or(false, |u| u < 0xD800 || 0xDFFF < u || high == Some(0)) as usize;
124+
let (low_buf, high_buf) = match self.buf {
125+
// buf is empty, no additional elements from it.
126+
None => (0, 0),
127+
// `u` is a non surrogate, so it's always an additional character.
128+
Some(u) if u < 0xD800 || 0xDFFF < u => (1, 1),
129+
// `u` is a leading surrogate (it can never be a trailing surrogate and
130+
// it's a surrogate due to the previous branch) and `self.iter` is empty.
131+
//
132+
// `u` can't be paired, since the `self.iter` is empty,
133+
// so it will always become an additional element (error).
134+
Some(_u) if high == Some(0) => (1, 1),
135+
// `u` is a leading surrogate and `iter` may be non-empty.
136+
//
137+
// `u` can either pair with a trailing surrogate, in which case no additional elements
138+
// are produced, or it can become an error, in which case it's an additional character (error).
139+
Some(_u) => (0, 1),
140+
};
133141

134142
// `self.iter` could contain entirely valid surrogates (2 elements per
135143
// char), or entirely non-surrogates (1 element per char).
136144
//
137145
// On odd lower bound, at least one element must stay unpaired
138146
// (with other elements from `self.iter`), so we round up.
139-
let low = low.div_ceil(2) + addition_from_buf;
140-
let high = high.and_then(|h| h.checked_add(addition_from_buf));
147+
let low = low.div_ceil(2) + low_buf;
148+
let high = high.and_then(|h| h.checked_add(high_buf));
141149

142150
(low, high)
143151
}

library/core/tests/char.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@ fn test_decode_utf16_size_hint() {
329329
}
330330

331331
check(&[0xD800, 0xD800, 0xDC00]);
332+
check(&[0xD800, 0xD800, 0x0]);
332333
check(&[0xD800, 0x41, 0x42]);
333334
check(&[0xD800, 0]);
334335
check(&[0xD834, 0x006d]);

0 commit comments

Comments
 (0)