#![no_std]
extern crate alloc;
mod bool_trie;
mod tables;
use tables::{conversions, general_category};
pub trait CharExt {
fn is_titlecase(self) -> bool;
fn to_titlecase(self) -> ToTitlecase;
}
impl CharExt for char {
#[inline]
fn is_titlecase(self) -> bool {
general_category::Lt(self)
}
#[inline]
fn to_titlecase(self) -> ToTitlecase {
ToTitlecase(CaseMappingIter::new(conversions::to_title(self)))
}
}
enum CaseMappingIter {
Three(char, char, char),
Two(char, char),
One(char),
Zero,
}
impl Iterator for CaseMappingIter {
type Item = char;
fn next(&mut self) -> Option<char> {
match *self {
CaseMappingIter::Three(a, b, c) => {
*self = CaseMappingIter::Two(b, c);
Some(a)
}
CaseMappingIter::Two(b, c) => {
*self = CaseMappingIter::One(c);
Some(b)
}
CaseMappingIter::One(c) => {
*self = CaseMappingIter::Zero;
Some(c)
}
CaseMappingIter::Zero => None,
}
}
}
impl CaseMappingIter {
fn new(chars: [char; 3]) -> CaseMappingIter {
if chars[2] == '\0' {
if chars[1] == '\0' {
CaseMappingIter::One(chars[0]) } else {
CaseMappingIter::Two(chars[0], chars[1])
}
} else {
CaseMappingIter::Three(chars[0], chars[1], chars[2])
}
}
}
pub struct ToTitlecase(CaseMappingIter);
impl Iterator for ToTitlecase {
type Item = char;
fn next(&mut self) -> Option<char> {
self.0.next()
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec::Vec;
#[test]
fn test_is_titlecase() {
assert!(!'A'.is_titlecase());
assert!('\u{1FFC}'.is_titlecase());
assert!('Dž'.is_titlecase());
}
#[test]
fn test_to_titlecase() {
fn title(c: char) -> Vec<char> {
c.to_titlecase().collect()
}
assert_eq!(title('a'), ['A']);
assert_eq!(title('ö'), ['Ö']);
assert_eq!(title('ß'), ['S', 's']); assert_eq!(title('ü'), ['Ü']);
assert_eq!(title('💩'), ['💩']);
assert_eq!(title('σ'), ['Σ']);
assert_eq!(title('τ'), ['Τ']);
assert_eq!(title('ι'), ['Ι']);
assert_eq!(title('γ'), ['Γ']);
assert_eq!(title('μ'), ['Μ']);
assert_eq!(title('α'), ['Α']);
assert_eq!(title('ς'), ['Σ']);
assert_eq!(title('DŽ'), ['Dž']);
assert_eq!(title('fi'), ['F', 'i']);
assert_eq!(title('ᾀ'), ['ᾈ']);
}
}