1mod bool_trie;
2mod tables;
3
4use tables::{conversions, general_category};
5
6pub trait CharExt {
7 fn is_titlecase(self) -> bool;
12
13 fn to_titlecase(self) -> ToTitlecase;
32}
33
34impl CharExt for char {
35 #[inline]
36 fn is_titlecase(self) -> bool {
37 general_category::Lt(self)
38 }
39
40 #[inline]
41 fn to_titlecase(self) -> ToTitlecase {
42 ToTitlecase(CaseMappingIter::new(conversions::to_title(self)))
43 }
44}
45
46enum CaseMappingIter {
47 Three(char, char, char),
48 Two(char, char),
49 One(char),
50 Zero,
51}
52
53impl Iterator for CaseMappingIter {
54 type Item = char;
55 fn next(&mut self) -> Option<char> {
56 match *self {
57 CaseMappingIter::Three(a, b, c) => {
58 *self = CaseMappingIter::Two(b, c);
59 Some(a)
60 }
61 CaseMappingIter::Two(b, c) => {
62 *self = CaseMappingIter::One(c);
63 Some(b)
64 }
65 CaseMappingIter::One(c) => {
66 *self = CaseMappingIter::Zero;
67 Some(c)
68 }
69 CaseMappingIter::Zero => None,
70 }
71 }
72}
73
74impl CaseMappingIter {
75 fn new(chars: [char; 3]) -> CaseMappingIter {
76 if chars[2] == '\0' {
77 if chars[1] == '\0' {
78 CaseMappingIter::One(chars[0]) } else {
80 CaseMappingIter::Two(chars[0], chars[1])
81 }
82 } else {
83 CaseMappingIter::Three(chars[0], chars[1], chars[2])
84 }
85 }
86}
87
88pub struct ToTitlecase(CaseMappingIter);
89
90impl Iterator for ToTitlecase {
91 type Item = char;
92 fn next(&mut self) -> Option<char> {
93 self.0.next()
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100
101 #[test]
102 fn test_is_titlecase() {
103 assert!(!'A'.is_titlecase());
104 assert!('\u{1FFC}'.is_titlecase());
105 assert!('Dž'.is_titlecase());
106 }
107
108 #[test]
109 fn test_to_titlecase() {
110 fn title(c: char) -> Vec<char> {
111 c.to_titlecase().collect()
112 }
113 assert_eq!(title('a'), ['A']);
114 assert_eq!(title('ö'), ['Ö']);
115 assert_eq!(title('ß'), ['S', 's']); assert_eq!(title('ü'), ['Ü']);
117 assert_eq!(title('💩'), ['💩']);
118
119 assert_eq!(title('σ'), ['Σ']);
120 assert_eq!(title('τ'), ['Τ']);
121 assert_eq!(title('ι'), ['Ι']);
122 assert_eq!(title('γ'), ['Γ']);
123 assert_eq!(title('μ'), ['Μ']);
124 assert_eq!(title('α'), ['Α']);
125 assert_eq!(title('ς'), ['Σ']);
126 assert_eq!(title('DŽ'), ['Dž']);
127 assert_eq!(title('fi'), ['F', 'i']);
128 assert_eq!(title('ᾀ'), ['ᾈ']);
129 }
130}