use crate::shape::*;
use alloc::vec::Vec;
pub fn is_tibetan(c: &u16) -> bool {
*c >= 0x0F00 && *c <= 0x0FFF
}
#[derive(Debug, Clone, PartialEq)]
enum MType {
Lh, Va, Vb, Vc,
U, WS, }
impl MType {
fn from_u16(c: &u16) -> MType {
match c {
0x0F40..=0x0F6C | 0x0F88..=0x0F8C => MType::Lh,
0x0F72 | 0x0F7A..=0x0F7D | 0x0F80 => MType::Va,
0x0F71 | 0x0F74 => MType::Vb,
0x0F73 | 0x0F75..=0x0F79 | 0x0F81 => MType::Vc,
&WHITESPACE => MType::WS,
_ => MType::U,
}
}
}
#[derive(Clone)]
struct Definition<'a> {
m_type: MType,
code: &'a u16,
}
impl<'a> Definition<'a> {
fn new(m_type: MType, code: &'a u16) -> Self {
Self { m_type, code }
}
fn build_from_unicodes(input: &[u16]) -> Vec<Definition> {
let mut clusters = Vec::new();
let mut idx: usize = 0;
while idx < input.len() {
let code = &input[idx];
clusters.push(Definition::new(MType::from_u16(code), code));
idx += 1;
}
clusters
}
}
struct Cluster<'a> {
pub defs: Vec<Definition<'a>>,
pub whitespace: Option<&'a u16>,
}
impl<'a> Cluster<'a> {
fn new(defs: Vec<Definition<'a>>, whitespace: Option<&'a u16>) -> Self {
Self { defs, whitespace }
}
fn build_clusters(defs: &'a [Definition<'a>]) -> Vec<Cluster<'a>> {
let mut clusters = Vec::new();
let mut def_idx = 0;
for idx in 0..defs.len() {
if defs[idx].m_type == MType::WS {
clusters.push(Cluster::new(defs[def_idx..idx].to_vec(), Some(defs[idx].code)));
def_idx = idx + 1;
}
}
if def_idx < defs.len() {
clusters.push(Cluster::new(defs[def_idx..].to_vec(), None));
}
clusters
}
fn get_sorted(&mut self) -> Vec<u16> {
let mut idx: usize = 0;
while idx < self.defs.len() {
match self.defs[idx].m_type {
MType::Va | MType::Vb | MType::Vc => {
let mut head_idx = idx;
while head_idx > 0 && self.defs[head_idx].m_type != MType::Lh {
head_idx -= 1;
}
let vowel_mark = self.defs.remove(idx);
self.defs.insert(head_idx, vowel_mark);
}
_ => {}
}
idx += 1;
}
let mut reordered = Vec::with_capacity(self.defs.len());
for def in &self.defs {
reordered.push(*def.code)
}
reordered
}
}
pub fn shape_tibetan(input: &mut [u16]) {
let mut res: Vec<u16> = Vec::with_capacity(input.len());
let defs = Definition::build_from_unicodes(input);
let mut clusters_sets = Cluster::build_clusters(&defs);
clusters_sets.iter_mut().for_each(|c| {
res.append(&mut c.get_sorted());
if let Some(ws) = c.whitespace {
res.push(*ws);
}
});
input.copy_from_slice(&res[..input.len()]);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn tibetan_test_above_base() {
let input = "བོད་རང་སྐྱོང་ལྗོངས།";
let expected: &[u16] = &[
3964, 3926, 3921, 3851, 3938, 3908, 3851, 3964, 3942, 3984, 4017, 3908, 3851, 3964,
3939, 3991, 3908, 3942, 3853,
];
let input_utf16_slice: Vec<u16> = input.encode_utf16().collect();
let input_utf16_ref: &[u16] = &input_utf16_slice;
let mut result = input_utf16_ref.to_vec();
shape_tibetan(&mut result);
assert_eq!(result, expected);
}
#[test]
fn tibetan_test_below_base() {
let input = "གུསར";
let expected: &[u16] = &[3956, 3906, 3942, 3938];
let input_utf16_slice: Vec<u16> = input.encode_utf16().collect();
let input_utf16_ref: &[u16] = &input_utf16_slice;
let mut result = input_utf16_ref.to_vec();
shape_tibetan(&mut result);
assert_eq!(result, expected);
}
#[test]
fn tibetan_test_compound_vowel() {
let input = "གཱིསར";
let expected: &[u16] = &[3955, 3906, 3942, 3938];
let input_utf16_slice: Vec<u16> = input.encode_utf16().collect();
let input_utf16_ref: &[u16] = &input_utf16_slice;
let mut result = input_utf16_ref.to_vec();
shape_tibetan(&mut result);
assert_eq!(result, expected);
}
}