]> git.lizzy.rs Git - rust.git/commitdiff
Fix an edge case in `chat::DecodeUtf16::size_hint`
authorMaybe Waffle <waffle.lapkin@gmail.com>
Sun, 30 Jan 2022 12:32:21 +0000 (15:32 +0300)
committerMaybe Waffle <waffle.lapkin@gmail.com>
Sun, 30 Jan 2022 12:32:21 +0000 (15:32 +0300)
There are cases, when data in the buf might or might not be an error.

library/core/src/char/decode.rs
library/core/tests/char.rs

index 81d49ffe06e6d373bf2c5ac84c6a87d1d149c2cc..8b9f979b573f70830930452c21fc94a724fbc651 100644 (file)
@@ -121,23 +121,31 @@ fn next(&mut self) -> Option<Result<char, DecodeUtf16Error>> {
     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)
     }
index 347ac04feb31c009a9f3955d72e00c85ded76b14..4c899b6eb43d0c5b1e1934b16edffc825d3a8a82 100644 (file)
@@ -329,6 +329,7 @@ fn check(s: &[u16]) {
     }
 
     check(&[0xD800, 0xD800, 0xDC00]);
+    check(&[0xD800, 0xD800, 0x0]);
     check(&[0xD800, 0x41, 0x42]);
     check(&[0xD800, 0]);
     check(&[0xD834, 0x006d]);