(bytes: &mut I)
| 31 | /// `bytes` must produce a valid UTF-8-like (UTF-8 or WTF-8) string |
| 32 | #[inline] |
| 33 | pub unsafe fn next_code_point<'a, I: Iterator<Item = &'a u8>>(bytes: &mut I) -> Option<u32> { |
| 34 | // Decode UTF-8 |
| 35 | let x = *bytes.next()?; |
| 36 | if x < 128 { |
| 37 | return Some(x as u32); |
| 38 | } |
| 39 | |
| 40 | // Multibyte case follows |
| 41 | // Decode from a byte combination out of: [[[x y] z] w] |
| 42 | // NOTE: Performance is sensitive to the exact formulation here |
| 43 | let init = utf8_first_byte(x, 2); |
| 44 | // SAFETY: `bytes` produces an UTF-8-like string, |
| 45 | // so the iterator must produce a value here. |
| 46 | let y = unsafe { *bytes.next().unwrap_unchecked() }; |
| 47 | let mut ch = utf8_acc_cont_byte(init, y); |
| 48 | if x >= 0xE0 { |
| 49 | // [[x y z] w] case |
| 50 | // 5th bit in 0xE0 .. 0xEF is always clear, so `init` is still valid |
| 51 | // SAFETY: `bytes` produces an UTF-8-like string, |
| 52 | // so the iterator must produce a value here. |
| 53 | let z = unsafe { *bytes.next().unwrap_unchecked() }; |
| 54 | let y_z = utf8_acc_cont_byte((y & CONT_MASK) as u32, z); |
| 55 | ch = init << 12 | y_z; |
| 56 | if x >= 0xF0 { |
| 57 | // [x y z w] case |
| 58 | // use only the lower 3 bits of `init` |
| 59 | // SAFETY: `bytes` produces an UTF-8-like string, |
| 60 | // so the iterator must produce a value here. |
| 61 | let w = unsafe { *bytes.next().unwrap_unchecked() }; |
| 62 | ch = (init & 7) << 18 | utf8_acc_cont_byte(y_z, w); |
| 63 | } |
| 64 | } |
| 65 | |
| 66 | Some(ch) |
| 67 | } |
| 68 | |
| 69 | /// Reads the last code point out of a byte iterator (assuming a |
| 70 | /// UTF-8-like encoding). |
no test coverage detected