basic_text_internals/
isolate_unassigned.rs

1use crate::text_utils::is_private_use_area;
2use crate::unicode::CGJ;
3use std::iter::Fuse;
4use unicode_normalization::char::is_public_assigned;
5
6/// An iterator which inserts CGJ around unassigned scalar values.
7pub struct IsolateUnassigned<I: Iterator<Item = char>> {
8    iter: Fuse<I>,
9    need_cgj: bool,
10    have_cgj: bool,
11    deferred: Option<char>,
12}
13
14impl<I: Iterator<Item = char>> IsolateUnassigned<I> {
15    #[inline]
16    pub fn new(iter: I) -> Self {
17        Self {
18            iter: Iterator::fuse(iter),
19            need_cgj: false,
20            have_cgj: false,
21            deferred: None,
22        }
23    }
24}
25
26impl<I: Iterator<Item = char>> Iterator for IsolateUnassigned<I> {
27    type Item = char;
28
29    #[inline]
30    fn next(&mut self) -> Option<char> {
31        if let Some(deferred) = self.deferred.take() {
32            return Some(deferred);
33        }
34
35        let c = self.iter.next();
36
37        match c {
38            Some(c) => {
39                let assigned = is_public_assigned(c) || is_private_use_area(c);
40                let have_cgj = c == CGJ;
41                Some(
42                    if (self.need_cgj && !have_cgj) || (!assigned && !self.have_cgj) {
43                        self.need_cgj = !assigned;
44                        self.have_cgj = false;
45                        self.deferred = Some(c);
46                        CGJ
47                    } else {
48                        self.need_cgj = false;
49                        self.have_cgj = have_cgj;
50                        c
51                    },
52                )
53            }
54            None => {
55                if self.need_cgj {
56                    self.need_cgj = false;
57                    Some(CGJ)
58                } else {
59                    None
60                }
61            }
62        }
63    }
64}