basic_text_internals/
categorize.rs

1//! On output, several disallowed scalar values are rejected, to catch
2//! applications attempting to use them.
3
4use crate::unicode::SUB;
5use crate::{check_basic_text_char, BasicTextError};
6use std::cell::RefCell;
7use std::rc::Rc;
8
9pub struct Categorize<Iter: Iterator<Item = char>> {
10    iter: Iter,
11
12    // Because we wrap this iterator in the NFC etc. iterator chain, it has
13    // to yield `char`s, and can't directly return errors. We indicate errors
14    // by returning the special `SUB` value, which we intercept on the other
15    // side to report the error stored in this error field.
16    error: Rc<RefCell<Option<BasicTextError>>>,
17}
18
19impl<Iter: Iterator<Item = char>> Categorize<Iter> {
20    #[inline]
21    pub fn new(iter: Iter, error: Rc<RefCell<Option<BasicTextError>>>) -> Self {
22        Self { iter, error }
23    }
24
25    #[cold]
26    fn record_error(&mut self, error: BasicTextError) -> char {
27        *self.error.borrow_mut() = Some(error);
28        SUB
29    }
30}
31
32impl<Iter: Iterator<Item = char>> Iterator for Categorize<Iter> {
33    type Item = char;
34
35    #[inline]
36    fn next(&mut self) -> Option<Self::Item> {
37        let c = self.iter.next()?;
38        Some(match check_basic_text_char(c) {
39            Ok(()) => c,
40            Err(e) => self.record_error(e),
41        })
42    }
43}