texcraft_stdext/
str.rs

1/// An owning iterator over the chars in a string.
2///
3/// This iterator is an alternative to the standard library's [Chars](std::str::Chars).
4/// This iterator has shared ownership of the string being iterated over and avoids lifetime issues.
5#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
6pub struct OwningChars {
7    // TODO: we don't need to serialize the full string, we just nneed to serialize
8    // everything after pos.
9    #[cfg_attr(
10        feature = "serde",
11        serde(
12            serialize_with = "crate::serde_tools::serialize_str",
13            deserialize_with = "crate::serde_tools::deserialize_rc_str"
14        )
15    )]
16    s: std::rc::Rc<str>,
17    pos: usize,
18}
19
20impl OwningChars {
21    pub fn new(s: std::rc::Rc<str>) -> OwningChars {
22        OwningChars { s, pos: 0 }
23    }
24
25    pub fn str(&self) -> &str {
26        &self.s
27    }
28
29    #[inline]
30    pub fn peek(&self) -> Option<char> {
31        self.s[self.pos..].chars().next()
32    }
33}
34
35impl std::iter::Iterator for OwningChars {
36    type Item = char;
37
38    #[inline]
39    fn next(&mut self) -> Option<Self::Item> {
40        let c_opt = self.s[self.pos..].chars().next();
41        if let Some(c) = c_opt {
42            self.pos += c.len_utf8();
43        }
44        c_opt
45    }
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51
52    #[test]
53    fn base_case() {
54        let s: std::rc::Rc<str> = "Tör".into();
55        let mut iter = OwningChars::new(s);
56        assert_eq!(Some('T'), iter.next());
57        assert_eq!(Some('ö'), iter.next());
58        assert_eq!(Some('r'), iter.next());
59        assert_eq!(None, iter.next());
60    }
61}