diff options
Diffstat (limited to 'src/libcore')
| -rw-r--r-- | src/libcore/char.rs | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/src/libcore/char.rs b/src/libcore/char.rs index d80b456181a..0e7f04c7758 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -676,3 +676,50 @@ impl Iterator for EncodeUtf16 { self.as_slice().iter().size_hint() } } + + +/// An iterator over an iterator of bytes of the characters the bytes represent +/// as UTF-8 +#[unstable(feature = "decode_utf8", issue = "33906")] +#[derive(Clone, Debug)] +pub struct DecodeUtf8<I: Iterator<Item = u8>>(::iter::Peekable<I>); + +/// Decodes an `Iterator` of bytes as UTF-8. +#[unstable(feature = "decode_utf8", issue = "33906")] +#[inline] +pub fn decode_utf8<I: IntoIterator<Item = u8>>(i: I) -> DecodeUtf8<I::IntoIter> { + DecodeUtf8(i.into_iter().peekable()) +} + +/// `<DecodeUtf8 as Iterator>::next` returns this for an invalid input sequence. +#[unstable(feature = "decode_utf8", issue = "33906")] +#[derive(PartialEq, Debug)] +pub struct InvalidSequence(()); + +#[unstable(feature = "decode_utf8", issue = "33906")] +impl<I: Iterator<Item = u8>> Iterator for DecodeUtf8<I> { + type Item = Result<char, InvalidSequence>; + #[inline] + fn next(&mut self) -> Option<Result<char, InvalidSequence>> { + self.0.next().map(|b| { + if b & 0x80 == 0 { Ok(b as char) } else { + let l = (!b).leading_zeros() as usize; // number of bytes in UTF-8 representation + if l < 2 || l > 6 { return Err(InvalidSequence(())) }; + let mut x = (b as u32) & (0x7F >> l); + for _ in 0..l-1 { + match self.0.peek() { + Some(&b) if b & 0xC0 == 0x80 => { + self.0.next(); + x = (x << 6) | (b as u32) & 0x3F; + }, + _ => return Err(InvalidSequence(())), + } + } + match from_u32(x) { + Some(x) if l == x.len_utf8() => Ok(x), + _ => Err(InvalidSequence(())), + } + } + }) + } +} |
