#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Token {
Char(char),
Compose,
}
pub trait Composer: std::fmt::Debug {
fn feed(&mut self, token: Token) -> ComposeState;
fn reset(&mut self);
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ComposeState {
Idle(Token),
Composing(String),
Finished(char),
Cancelled,
}
#[inline(always)]
fn token_key(token: &Token) -> u32 {
match token {
Token::Compose => 0,
Token::Char(c) => *c as u32,
}
}
#[derive(Debug, Clone)]
pub(crate) struct TrieNode {
children: Vec<(u32, u32)>, emit: Option<char>,
}
#[derive(Debug, Clone)]
pub struct ListComposer {
pub(crate) nodes: Vec<TrieNode>,
cur: u32,
pending: Vec<Token>,
}
impl Default for ListComposer {
fn default() -> Self {
Self::new()
}
}
impl ListComposer {
pub fn new() -> Self {
Self {
nodes: vec![TrieNode {
children: Vec::new(),
emit: None,
}],
cur: 0,
pending: Vec::new(),
}
}
#[inline]
pub fn pending(&self) -> &[Token] {
&self.pending
}
pub fn insert(&mut self, tokens: &[Token], out: char) {
let mut n = 0u32;
for t in tokens.iter() {
let key = token_key(t);
let children = &self.nodes[n as usize].children;
match children.binary_search_by_key(&key, |&(k, _)| k) {
Ok(pos) => {
n = children[pos].1;
}
Err(pos) => {
let new_idx = self.nodes.len() as u32;
self.nodes.push(TrieNode {
children: Vec::new(),
emit: None,
});
self.nodes[n as usize].children.insert(pos, (key, new_idx));
n = new_idx;
}
}
}
self.nodes[n as usize].emit = Some(out);
}
pub fn pending_string(&self) -> String {
if self.pending.is_empty() {
return String::new();
}
let mut s = String::with_capacity(self.pending.len());
let last = self.pending.len() - 1;
for token in &self.pending[..last] {
if let Token::Char(c) = token {
s.push(*c);
}
}
match self.pending[last] {
Token::Compose => s.push('·'),
Token::Char(c) => s.push(c),
}
s
}
}
impl Composer for ListComposer {
#[inline]
fn feed(&mut self, token: Token) -> ComposeState {
let key = token_key(&token);
let node = &self.nodes[self.cur as usize];
match node.children.binary_search_by_key(&key, |&(k, _)| k) {
Ok(pos) => {
let next = node.children[pos].1;
self.pending.push(token);
let next_node = &self.nodes[next as usize];
if let Some(out) = next_node.emit {
self.cur = 0;
self.pending.clear();
ComposeState::Finished(out)
} else {
self.cur = next;
ComposeState::Composing(self.pending_string())
}
}
Err(_) => {
if self.cur == 0 {
ComposeState::Idle(token)
} else {
self.cur = 0;
self.pending.clear();
ComposeState::Cancelled
}
}
}
}
fn reset(&mut self) {
self.cur = 0;
self.pending.clear();
}
}