zalgo_codec_common/zalgo_string/
iterators.rs

1use crate::{decode_byte_pair, ZalgoString};
2use core::iter::FusedIterator;
3
4/// An iterator over the decoded bytes of a [`ZalgoString`].
5///
6/// This struct is obtained by calling the [`decoded_bytes`](ZalgoString::decoded_bytes) method on a [`ZalgoString`].
7/// See its documentation for more.
8#[derive(Debug, Clone)]
9#[must_use = "iterators are lazy and do nothing unless consumed"]
10pub struct DecodedBytes<'a>(core::str::Bytes<'a>);
11
12impl<'a> DecodedBytes<'a> {
13    #[inline]
14    pub(crate) fn new(zs: &'a ZalgoString) -> Self {
15        Self(zs.as_combining_chars().bytes())
16    }
17}
18
19impl Iterator for DecodedBytes<'_> {
20    type Item = u8;
21    #[inline]
22    fn next(&mut self) -> Option<Self::Item> {
23        self.0
24            .next()
25            .zip(self.0.next())
26            .map(|(odd, even)| decode_byte_pair(odd, even))
27    }
28
29    #[inline]
30    fn size_hint(&self) -> (usize, Option<usize>) {
31        let left = self.0.size_hint().0 / 2;
32        (left, Some(left))
33    }
34
35    #[inline]
36    fn nth(&mut self, n: usize) -> Option<Self::Item> {
37        self.0
38            .nth(2 * n)
39            .zip(self.0.next())
40            .map(|(odd, even)| decode_byte_pair(odd, even))
41    }
42
43    #[inline]
44    fn last(mut self) -> Option<Self::Item> {
45        self.0
46            .len()
47            // Check if there are at least two bytes left
48            .checked_sub(2)
49            .and_then(|l| {
50                self.0
51                    // Get the next to last,
52                    .nth(l)
53                    // and the last
54                    .zip(self.0.next())
55                    // and decode them
56                    .map(|(odd, even)| decode_byte_pair(odd, even))
57            })
58    }
59
60    #[inline]
61    fn count(self) -> usize {
62        self.0.count() / 2
63    }
64}
65
66impl DoubleEndedIterator for DecodedBytes<'_> {
67    #[inline]
68    fn next_back(&mut self) -> Option<Self::Item> {
69        self.0
70            .next_back()
71            .zip(self.0.next_back())
72            .map(|(even, odd)| decode_byte_pair(odd, even))
73    }
74}
75
76impl FusedIterator for DecodedBytes<'_> {}
77impl ExactSizeIterator for DecodedBytes<'_> {}
78
79/// An iterator over the decoded characters of a [`ZalgoString`].
80///
81/// This struct is obtained by calling the [`decoded_chars`](ZalgoString::decoded_chars) method on a [`ZalgoString`].
82/// See it's documentation for more.
83#[derive(Debug, Clone)]
84#[must_use = "iterators are lazy and do nothing unless consumed"]
85pub struct DecodedChars<'a>(DecodedBytes<'a>);
86
87impl<'a> DecodedChars<'a> {
88    pub(crate) fn new(zs: &'a ZalgoString) -> Self {
89        Self(zs.decoded_bytes())
90    }
91}
92
93impl Iterator for DecodedChars<'_> {
94    type Item = char;
95    #[inline]
96    fn next(&mut self) -> Option<Self::Item> {
97        self.0.next().map(char::from)
98    }
99
100    #[inline]
101    fn size_hint(&self) -> (usize, Option<usize>) {
102        self.0.size_hint()
103    }
104
105    #[inline]
106    fn nth(&mut self, n: usize) -> Option<Self::Item> {
107        self.0.nth(n).map(char::from)
108    }
109
110    #[inline]
111    fn count(self) -> usize {
112        self.0.count()
113    }
114
115    #[inline]
116    fn last(self) -> Option<Self::Item> {
117        self.0.last().map(char::from)
118    }
119}
120
121impl DoubleEndedIterator for DecodedChars<'_> {
122    #[inline]
123    fn next_back(&mut self) -> Option<Self::Item> {
124        self.0.next_back().map(char::from)
125    }
126}
127
128impl FusedIterator for DecodedChars<'_> {}
129impl ExactSizeIterator for DecodedChars<'_> {}