1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
use crate::feature_cell::FeatureCell;
use crate::Set;
use lazy_static::lazy_static;
use std::ops::Deref;

lazy_static! {
    pub(crate) static ref BANNED: FeatureCell<Banned> = FeatureCell::new(Banned(
        include_str!("banned_chars.txt")
            .lines()
            .filter(|s| s.starts_with("U+"))
            .map(|s| {
                u32::from_str_radix(&s[2..], 16)
                    .ok()
                    .and_then(char::from_u32)
                    .unwrap()
            })
            // If you care about width, you probably also care about height.
            .chain(if cfg!(feature = "width") {
                    ['\u{A9C1}', '\u{A9C2}'].as_slice().into_iter().copied()
                } else {
                    [].as_slice().into_iter().copied()
                })
            .collect()
    ));
}

/// Set of character to strip from input without replacement.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Banned(Set<char>);

impl Default for Banned {
    fn default() -> Self {
        BANNED.deref().deref().clone()
    }
}

impl Banned {
    /// Empty.
    pub fn new() -> Self {
        Self(Default::default())
    }

    /// Allows direct mutable access to the global default set of banned characters.
    ///
    /// # Safety
    ///
    /// You must manually avoid concurrent access/censoring.
    #[cfg(feature = "customize")]
    #[cfg_attr(doc, doc(cfg(feature = "customize")))]
    pub unsafe fn customize_default() -> &'static mut Self {
        BANNED.get_mut()
    }

    pub(crate) fn contains(&self, c: char) -> bool {
        self.0.contains(&c)
    }

    /// Adds a banned character.
    pub fn insert(&mut self, c: char) {
        self.0.insert(c);
    }

    /// Removes a banned character.
    pub fn remove(&mut self, c: char) {
        self.0.remove(&c);
    }
}