| 50 | /// is not the shortest possible UTF-8 sequence for that codepoint. |
| 51 | #[inline] |
| 52 | pub fn decode_utf8(src: &[u8]) -> Option<(char, usize)> { |
| 53 | let b0 = match src.get(0) { |
| 54 | None => return None, |
| 55 | Some(&b) if b <= 0x7F => return Some((b as char, 1)), |
| 56 | Some(&b) => b, |
| 57 | }; |
| 58 | match b0 { |
| 59 | 0b110_00000 ... 0b110_11111 => { |
| 60 | if src.len() < 2 { |
| 61 | return None; |
| 62 | } |
| 63 | let b1 = src[1]; |
| 64 | if 0b11_000000 & b1 != TAG_CONT { |
| 65 | return None; |
| 66 | } |
| 67 | let cp = ((b0 & !TAG_TWO) as u32) << 6 |
| 68 | | ((b1 & !TAG_CONT) as u32); |
| 69 | match cp { |
| 70 | 0x80 ... 0x7FF => char::from_u32(cp).map(|cp| (cp, 2)), |
| 71 | _ => None, |
| 72 | } |
| 73 | } |
| 74 | 0b1110_0000 ... 0b1110_1111 => { |
| 75 | if src.len() < 3 { |
| 76 | return None; |
| 77 | } |
| 78 | let (b1, b2) = (src[1], src[2]); |
| 79 | if 0b11_000000 & b1 != TAG_CONT { |
| 80 | return None; |
| 81 | } |
| 82 | if 0b11_000000 & b2 != TAG_CONT { |
| 83 | return None; |
| 84 | } |
| 85 | let cp = ((b0 & !TAG_THREE) as u32) << 12 |
| 86 | | ((b1 & !TAG_CONT) as u32) << 6 |
| 87 | | ((b2 & !TAG_CONT) as u32); |
| 88 | match cp { |
| 89 | // char::from_u32 will disallow surrogate codepoints. |
| 90 | 0x800 ... 0xFFFF => char::from_u32(cp).map(|cp| (cp, 3)), |
| 91 | _ => None, |
| 92 | } |
| 93 | } |
| 94 | 0b11110_000 ... 0b11110_111 => { |
| 95 | if src.len() < 4 { |
| 96 | return None; |
| 97 | } |
| 98 | let (b1, b2, b3) = (src[1], src[2], src[3]); |
| 99 | if 0b11_000000 & b1 != TAG_CONT { |
| 100 | return None; |
| 101 | } |
| 102 | if 0b11_000000 & b2 != TAG_CONT { |
| 103 | return None; |
| 104 | } |
| 105 | if 0b11_000000 & b3 != TAG_CONT { |
| 106 | return None; |
| 107 | } |
| 108 | let cp = ((b0 & !TAG_FOUR) as u32) << 18 |
| 109 | | ((b1 & !TAG_CONT) as u32) << 12 |