Skip to main content

obeli_sk_boa_string/
iter.rs

1use std::iter::FusedIterator;
2
3use crate::{CodePoint, JsStr};
4
5use super::JsStrVariant;
6
7#[derive(Debug, Clone)]
8enum IterInner<'a> {
9    U8(std::iter::Copied<std::slice::Iter<'a, u8>>),
10    U16(std::iter::Copied<std::slice::Iter<'a, u16>>),
11}
12
13/// Iterator over a [`JsStr`].
14#[derive(Debug, Clone)]
15pub struct Iter<'a> {
16    inner: IterInner<'a>,
17}
18
19impl<'a> Iter<'a> {
20    #[inline]
21    pub(crate) fn new(s: JsStr<'a>) -> Self {
22        let inner = match s.variant() {
23            JsStrVariant::Latin1(s) => IterInner::U8(s.iter().copied()),
24            JsStrVariant::Utf16(s) => IterInner::U16(s.iter().copied()),
25        };
26        Iter { inner }
27    }
28}
29
30impl Iterator for Iter<'_> {
31    type Item = u16;
32
33    #[inline]
34    fn next(&mut self) -> Option<Self::Item> {
35        match &mut self.inner {
36            IterInner::U8(iter) => iter.map(u16::from).next(),
37            IterInner::U16(iter) => iter.next(),
38        }
39    }
40}
41
42impl FusedIterator for Iter<'_> {}
43
44impl ExactSizeIterator for Iter<'_> {
45    #[inline]
46    fn len(&self) -> usize {
47        match &self.inner {
48            IterInner::U8(v) => v.len(),
49            IterInner::U16(v) => v.len(),
50        }
51    }
52}
53
54#[derive(Debug, Clone)]
55enum WindowsInner<'a> {
56    U8(std::slice::Windows<'a, u8>),
57    U16(std::slice::Windows<'a, u16>),
58}
59
60/// An iterator over overlapping subslices of length size.
61///
62/// This struct is created by the `windows` method.
63#[derive(Debug, Clone)]
64pub struct Windows<'a> {
65    inner: WindowsInner<'a>,
66}
67
68impl<'a> Windows<'a> {
69    #[inline]
70    pub(crate) fn new(string: JsStr<'a>, size: usize) -> Self {
71        let inner = match string.variant() {
72            JsStrVariant::Latin1(v) => WindowsInner::U8(v.windows(size)),
73            JsStrVariant::Utf16(v) => WindowsInner::U16(v.windows(size)),
74        };
75        Self { inner }
76    }
77}
78
79impl<'a> Iterator for Windows<'a> {
80    type Item = JsStr<'a>;
81
82    #[inline]
83    fn next(&mut self) -> Option<Self::Item> {
84        match &mut self.inner {
85            WindowsInner::U8(iter) => iter.next().map(JsStr::latin1),
86            WindowsInner::U16(iter) => iter.next().map(JsStr::utf16),
87        }
88    }
89}
90
91impl FusedIterator for Windows<'_> {}
92
93impl ExactSizeIterator for Windows<'_> {
94    #[inline]
95    fn len(&self) -> usize {
96        match &self.inner {
97            WindowsInner::U8(v) => v.len(),
98            WindowsInner::U16(v) => v.len(),
99        }
100    }
101}
102
103#[derive(Debug, Clone)]
104enum CodePointsIterInner<'a> {
105    Latin1(std::iter::Copied<std::slice::Iter<'a, u8>>),
106    Utf16(std::char::DecodeUtf16<std::iter::Copied<std::slice::Iter<'a, u16>>>),
107}
108
109#[derive(Debug, Clone)]
110pub struct CodePointsIter<'a> {
111    inner: CodePointsIterInner<'a>,
112}
113
114impl<'a> CodePointsIter<'a> {
115    #[inline]
116    pub(crate) fn new(s: JsStr<'a>) -> Self {
117        let inner = match s.variant() {
118            JsStrVariant::Latin1(s) => CodePointsIterInner::Latin1(s.iter().copied()),
119            JsStrVariant::Utf16(s) => {
120                CodePointsIterInner::Utf16(char::decode_utf16(s.iter().copied()))
121            }
122        };
123        CodePointsIter { inner }
124    }
125}
126
127impl Iterator for CodePointsIter<'_> {
128    type Item = CodePoint;
129
130    #[inline]
131    fn next(&mut self) -> Option<Self::Item> {
132        match &mut self.inner {
133            CodePointsIterInner::Latin1(iter) => {
134                iter.next().map(|b| CodePoint::Unicode(char::from(b)))
135            }
136            CodePointsIterInner::Utf16(iter) => iter.next().map(|res| match res {
137                Ok(c) => CodePoint::Unicode(c),
138                Err(e) => CodePoint::UnpairedSurrogate(e.unpaired_surrogate()),
139            }),
140        }
141    }
142}
143
144impl FusedIterator for CodePointsIter<'_> {}