1#[cfg(not(feature = "ferrocene_subset"))]
4use crate::error::Error;
5#[cfg(not(feature = "ferrocene_subset"))]
6use crate::fmt;
7#[cfg(not(feature = "ferrocene_subset"))]
8use crate::iter::FusedIterator;
9
10#[stable(feature = "decode_utf16", since = "1.9.0")]
17#[cfg_attr(not(feature = "ferrocene_subset"), derive(Clone, Debug))]
18pub struct DecodeUtf16<I>
19where
20 I: Iterator<Item = u16>,
21{
22 iter: I,
23 buf: Option<u16>,
24}
25
26#[stable(feature = "decode_utf16", since = "1.9.0")]
30#[cfg_attr(not(feature = "ferrocene_subset"), derive(Debug, Clone, Eq, PartialEq))]
31pub struct DecodeUtf16Error {
32 code: u16,
33}
34
35#[inline]
38pub(super) fn decode_utf16<I: IntoIterator<Item = u16>>(iter: I) -> DecodeUtf16<I::IntoIter> {
39 DecodeUtf16 { iter: iter.into_iter(), buf: None }
40}
41
42#[stable(feature = "decode_utf16", since = "1.9.0")]
43impl<I: Iterator<Item = u16>> Iterator for DecodeUtf16<I> {
44 type Item = Result<char, DecodeUtf16Error>;
45
46 fn next(&mut self) -> Option<Result<char, DecodeUtf16Error>> {
47 let u = match self.buf.take() {
48 Some(buf) => buf,
49 None => self.iter.next()?,
50 };
51
52 if !u.is_utf16_surrogate() {
53 Some(Ok(unsafe { char::from_u32_unchecked(u as u32) }))
55 } else if u >= 0xDC00 {
56 Some(Err(DecodeUtf16Error { code: u }))
58 } else {
59 let u2 = match self.iter.next() {
60 Some(u2) => u2,
61 None => return Some(Err(DecodeUtf16Error { code: u })),
63 };
64 if u2 < 0xDC00 || u2 > 0xDFFF {
65 self.buf = Some(u2);
68 return Some(Err(DecodeUtf16Error { code: u }));
69 }
70
71 let c = (((u & 0x3ff) as u32) << 10 | (u2 & 0x3ff) as u32) + 0x1_0000;
73 Some(Ok(unsafe { char::from_u32_unchecked(c) }))
75 }
76 }
77
78 #[inline]
79 fn size_hint(&self) -> (usize, Option<usize>) {
80 let (low, high) = self.iter.size_hint();
81
82 let (low_buf, high_buf) = match self.buf {
83 None => (0, 0),
85 Some(u) if !u.is_utf16_surrogate() => (1, 1),
87 Some(_u) if high == Some(0) => (1, 1),
93 Some(_u) => (0, 1),
98 };
99
100 let low = low.div_ceil(2) + low_buf;
106 let high = high.and_then(|h| h.checked_add(high_buf));
107
108 (low, high)
109 }
110}
111
112#[cfg(not(feature = "ferrocene_subset"))]
113#[stable(feature = "decode_utf16_fused_iterator", since = "1.75.0")]
114impl<I: Iterator<Item = u16> + FusedIterator> FusedIterator for DecodeUtf16<I> {}
115
116impl DecodeUtf16Error {
117 #[must_use]
119 #[stable(feature = "decode_utf16", since = "1.9.0")]
120 pub fn unpaired_surrogate(&self) -> u16 {
121 self.code
122 }
123}
124
125#[cfg(not(feature = "ferrocene_subset"))]
126#[stable(feature = "decode_utf16", since = "1.9.0")]
127impl fmt::Display for DecodeUtf16Error {
128 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129 write!(f, "unpaired surrogate found: {:x}", self.code)
130 }
131}
132
133#[cfg(not(feature = "ferrocene_subset"))]
134#[stable(feature = "decode_utf16", since = "1.9.0")]
135impl Error for DecodeUtf16Error {}