1 | //! [Confusable detection](https://www.unicode.org/reports/tr39/#Confusable_Detection) |
2 | |
3 | use core::iter; |
4 | |
5 | enum OnceOrMore<T, I> { |
6 | Once(iter::Once<T>), |
7 | More(I), |
8 | } |
9 | |
10 | impl<T, I> Iterator for OnceOrMore<T, I> |
11 | where |
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: impl Iterator ) => v.next(), |
20 | More(i: &mut I) => i.next(), |
21 | } |
22 | } |
23 | } |
24 | |
25 | type StaticSliceIterCloned = core::iter::Cloned<core::slice::Iter<'static, char>>; |
26 | |
27 | fn 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: &[char]) => OnceOrMore::More(l.iter().cloned()), |
32 | } |
33 | } |
34 | |
35 | /// Calculate skeleton for string, as defined by UTS 39 |
36 | pub fn skeleton(s: &str) -> impl Iterator<Item = char> + '_ { |
37 | use unicode_normalization::UnicodeNormalization; |
38 | s.chars().nfd().flat_map(char_prototype).nfd() |
39 | } |
40 | |