| 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: &'static [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 | |