181 lines
4.3 KiB
Rust
181 lines
4.3 KiB
Rust
//! Implements a trie on T9 numpads
|
|
//!
|
|
//! # T9:
|
|
//! 1: 2:abc 3:def
|
|
//! 4:ghi 5:jkl 6:mno
|
|
//! 7:pqrs 8:tuv 9:wxyz
|
|
|
|
use std::{
|
|
collections::VecDeque,
|
|
ops::{Index, IndexMut},
|
|
};
|
|
|
|
#[derive(Debug, Default)]
|
|
pub struct Trie9 {
|
|
pub link: Option<Box<[Trie9; 8]>>,
|
|
pub leaf: Vec<String>,
|
|
}
|
|
|
|
impl Trie9 {
|
|
pub fn new() -> Self {
|
|
Self::default()
|
|
}
|
|
|
|
pub fn insert(&mut self, string: &str) -> bool {
|
|
let Some(trie) = self.at_mut(string.chars()) else {
|
|
return false;
|
|
};
|
|
|
|
trie.leaf.push(string.into());
|
|
true
|
|
}
|
|
|
|
pub fn get(&self, index: T9) -> Option<&Trie9> {
|
|
self.link.as_ref()?.get(index as usize)
|
|
}
|
|
|
|
pub fn get_mut(&mut self, index: T9) -> Option<&mut Trie9> {
|
|
self.link.as_mut()?.get_mut(index as usize)
|
|
}
|
|
|
|
pub fn get_or_insert(&mut self, index: T9) -> &mut Trie9 {
|
|
self.link
|
|
.get_or_insert_default()
|
|
.get_mut(index as usize)
|
|
.expect("link exists at all T9 indices")
|
|
}
|
|
|
|
pub fn at<Iter, T>(&self, code: Iter) -> Option<&Self>
|
|
where
|
|
Iter: IntoIterator<Item = T>,
|
|
T: TryInto<T9>,
|
|
{
|
|
let mut code = code.into_iter();
|
|
match code.next() {
|
|
None => Some(self),
|
|
Some(link) => self.get(link.try_into().ok()?)?.at(code),
|
|
}
|
|
}
|
|
|
|
pub fn at_mut<Iter, T>(&mut self, code: Iter) -> Option<&mut Self>
|
|
where
|
|
Iter: IntoIterator<Item = T>,
|
|
T: TryInto<T9>,
|
|
{
|
|
let mut code = code.into_iter();
|
|
match code.next() {
|
|
None => Some(self),
|
|
Some(link) => self.get_or_insert(link.try_into().ok()?).at_mut(code),
|
|
}
|
|
}
|
|
|
|
pub fn iter<'t>(&'t self) -> Trie9Iter<'t> {
|
|
Trie9Iter::new(self)
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct Trie9Iter<'t9> {
|
|
queue: VecDeque<&'t9 Trie9>,
|
|
items: std::slice::Iter<'t9, String>,
|
|
}
|
|
|
|
impl<'t> Trie9Iter<'t> {
|
|
pub fn new(trie: &'t Trie9) -> Self {
|
|
Self { queue: VecDeque::from([trie]), items: Default::default() }
|
|
}
|
|
}
|
|
|
|
impl<'t> Iterator for Trie9Iter<'t> {
|
|
type Item = &'t str;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
let Self { queue, items } = self;
|
|
|
|
if let Some(item) = items.next() {
|
|
return Some(item.as_str());
|
|
}
|
|
|
|
let Trie9 { link, leaf } = queue.pop_front()?;
|
|
*items = leaf.iter();
|
|
queue.extend(link.iter().flat_map(|v| v.iter()));
|
|
|
|
self.next()
|
|
}
|
|
}
|
|
|
|
impl<'t> IntoIterator for &'t Trie9 {
|
|
type IntoIter = Trie9Iter<'t>;
|
|
type Item = &'t str;
|
|
|
|
fn into_iter(self) -> Self::IntoIter {
|
|
Self::IntoIter::new(self)
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
pub enum T9 {
|
|
T2,
|
|
T3,
|
|
T4,
|
|
T5,
|
|
T6,
|
|
T7,
|
|
T8,
|
|
T9,
|
|
}
|
|
|
|
impl From<T9> for u8 {
|
|
fn from(value: T9) -> Self {
|
|
value as u8 + 2
|
|
}
|
|
}
|
|
|
|
impl From<T9> for char {
|
|
fn from(value: T9) -> Self {
|
|
match value {
|
|
T9::T2 => '2',
|
|
T9::T3 => '3',
|
|
T9::T4 => '4',
|
|
T9::T5 => '5',
|
|
T9::T6 => '6',
|
|
T9::T7 => '7',
|
|
T9::T8 => '8',
|
|
T9::T9 => '9',
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<char> for T9 {
|
|
type Error = char;
|
|
fn try_from(value: char) -> Result<Self, Self::Error> {
|
|
Ok(match value {
|
|
'2' | 'A'..='C' | 'a'..='c' | 'À'..='Æ' | 'à'..='æ' | 'Ç' | 'ç' => Self::T2,
|
|
'3' | 'D'..='F' | 'd'..='f' | 'È'..='Ë' | 'è'..='ë' => Self::T3,
|
|
'4' | 'G'..='I' | 'g'..='i' | 'Ì'..='Ï' | 'ì'..='ï' => Self::T4,
|
|
'5' | 'J'..='L' | 'j'..='l' | '1' => Self::T5,
|
|
'6' | 'M'..='O' | 'm'..='o' | 'Ò'..='Ø' | 'ò'..='ø' | '0' => Self::T6,
|
|
'7' | 'P'..='S' | 'p'..='s' => Self::T7,
|
|
'8' | 'T'..='V' | 't'..='v' | 'Ù'..='Ü' | 'ù'..='ü' => Self::T8,
|
|
'9' | 'W'..='Z' | 'w'..='z' => Self::T9,
|
|
_ => Err(value)?,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl Index<T9> for Trie9 {
|
|
type Output = Trie9;
|
|
fn index(&self, index: T9) -> &Self::Output {
|
|
let Some(link) = self.get(index) else {
|
|
panic!("No Trie9 at index {index:?}");
|
|
};
|
|
link
|
|
}
|
|
}
|
|
|
|
impl IndexMut<T9> for Trie9 {
|
|
fn index_mut(&mut self, index: T9) -> &mut Self::Output {
|
|
self.get_or_insert(index)
|
|
}
|
|
}
|