unicode_security/
confusable_detection.rs

1//! [Confusable detection](https://www.unicode.org/reports/tr39/#Confusable_Detection)
2
3use core::iter;
4
5enum OnceOrMore<T, I> {
6    Once(iter::Once<T>),
7    More(I),
8}
9
10impl<T, I> Iterator for OnceOrMore<T, I>
11where
12    I: Iterator<Item = T>,
13{
14    type Item = T;
15
16    fn next(&mut self) -> Option<T> {
17        use OnceOrMore::*;
18        match self {
19            Once(v) => v.next(),
20            More(i) => i.next(),
21        }
22    }
23}
24
25type StaticSliceIterCloned = core::iter::Cloned<core::slice::Iter<'static, char>>;
26
27fn char_prototype(c: char) -> OnceOrMore<char, StaticSliceIterCloned> {
28    use crate::tables::confusable_detection::char_confusable_prototype;
29    match char_confusable_prototype(c) {
30        None => OnceOrMore::Once(iter::once(c)),
31        Some(l) => OnceOrMore::More(l.iter().cloned()),
32    }
33}
34
35/// Calculate skeleton for string, as defined by UTS 39
36pub fn skeleton(s: &str) -> impl Iterator<Item = char> + '_ {
37    use unicode_normalization::UnicodeNormalization;
38    s.chars().nfd().flat_map(char_prototype).nfd()
39}