1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT 2 // file at the top-level directory of this distribution and at 3 // http://rust-lang.org/COPYRIGHT. 4 // 5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or 6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license 7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your 8 // option. This file may not be copied, modified, or distributed 9 // except according to those terms. 10 11 use crate::decompose::Decompositions; 12 use core::{ 13 fmt::{self, Write}, 14 iter::FusedIterator, 15 }; 16 use tinyvec::TinyVec; 17 18 #[derive(Clone)] 19 enum RecompositionState { 20 Composing, 21 Purging(usize), 22 Finished(usize), 23 } 24 25 /// External iterator for a string recomposition's characters. 26 #[derive(Clone)] 27 pub struct Recompositions<I> { 28 iter: Decompositions<I>, 29 state: RecompositionState, 30 buffer: TinyVec<[char; 4]>, 31 composee: Option<char>, 32 last_ccc: Option<u8>, 33 } 34 35 impl<I: Iterator<Item = char>> Recompositions<I> { 36 /// Create a new recomposition iterator for canonical compositions (NFC) 37 /// 38 /// Note that this iterator can also be obtained by directly calling [`.nfc()`](crate::UnicodeNormalization::nfc) 39 /// on the iterator. 40 #[inline] new_canonical(iter: I) -> Self41 pub fn new_canonical(iter: I) -> Self { 42 Recompositions { 43 iter: Decompositions::new_canonical(iter), 44 state: self::RecompositionState::Composing, 45 buffer: TinyVec::new(), 46 composee: None, 47 last_ccc: None, 48 } 49 } 50 51 /// Create a new recomposition iterator for compatability compositions (NFkC) 52 /// 53 /// Note that this iterator can also be obtained by directly calling [`.nfkc()`](crate::UnicodeNormalization::nfkc) 54 /// on the iterator. 55 #[inline] new_compatible(iter: I) -> Self56 pub fn new_compatible(iter: I) -> Self { 57 Recompositions { 58 iter: Decompositions::new_compatible(iter), 59 state: self::RecompositionState::Composing, 60 buffer: TinyVec::new(), 61 composee: None, 62 last_ccc: None, 63 } 64 } 65 } 66 67 impl<I: Iterator<Item = char>> Iterator for Recompositions<I> { 68 type Item = char; 69 70 #[inline] next(&mut self) -> Option<char>71 fn next(&mut self) -> Option<char> { 72 use self::RecompositionState::*; 73 74 loop { 75 match self.state { 76 Composing => { 77 for ch in self.iter.by_ref() { 78 let ch_class = super::char::canonical_combining_class(ch); 79 let k = match self.composee { 80 None => { 81 if ch_class != 0 { 82 return Some(ch); 83 } 84 self.composee = Some(ch); 85 continue; 86 } 87 Some(k) => k, 88 }; 89 match self.last_ccc { 90 None => match super::char::compose(k, ch) { 91 Some(r) => { 92 self.composee = Some(r); 93 continue; 94 } 95 None => { 96 if ch_class == 0 { 97 self.composee = Some(ch); 98 return Some(k); 99 } 100 self.buffer.push(ch); 101 self.last_ccc = Some(ch_class); 102 } 103 }, 104 Some(l_class) => { 105 if l_class >= ch_class { 106 // `ch` is blocked from `composee` 107 if ch_class == 0 { 108 self.composee = Some(ch); 109 self.last_ccc = None; 110 self.state = Purging(0); 111 return Some(k); 112 } 113 self.buffer.push(ch); 114 self.last_ccc = Some(ch_class); 115 continue; 116 } 117 match super::char::compose(k, ch) { 118 Some(r) => { 119 self.composee = Some(r); 120 continue; 121 } 122 None => { 123 self.buffer.push(ch); 124 self.last_ccc = Some(ch_class); 125 } 126 } 127 } 128 } 129 } 130 self.state = Finished(0); 131 if self.composee.is_some() { 132 return self.composee.take(); 133 } 134 } 135 Purging(next) => match self.buffer.get(next).cloned() { 136 None => { 137 self.buffer.clear(); 138 self.state = Composing; 139 } 140 s => { 141 self.state = Purging(next + 1); 142 return s; 143 } 144 }, 145 Finished(next) => match self.buffer.get(next).cloned() { 146 None => { 147 self.buffer.clear(); 148 return self.composee.take(); 149 } 150 s => { 151 self.state = Finished(next + 1); 152 return s; 153 } 154 }, 155 } 156 } 157 } 158 } 159 160 impl<I: Iterator<Item = char> + FusedIterator> FusedIterator for Recompositions<I> {} 161 162 impl<I: Iterator<Item = char> + Clone> fmt::Display for Recompositions<I> { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result163 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 164 for c in self.clone() { 165 f.write_char(c)?; 166 } 167 Ok(()) 168 } 169 } 170