1use crate::unicode::std_case_mapping_iter::CaseMappingIter;
2use crate::unicode::ucd_generated_case_mapping::SORTED_TITLECASE_MAPPING;
3use core::iter::FusedIterator;
4
5#[allow(clippy::module_name_repetitions)]
26#[must_use]
27pub fn to_titlecase(c: char) -> [char; 3] {
28 let codepoint = c as u32;
29 if let Ok(index) = SORTED_TITLECASE_MAPPING.binary_search_by(|&(key, _)| key.cmp(&codepoint)) {
30 let chars = SORTED_TITLECASE_MAPPING[index].1;
31 [
32 char::from_u32(chars[0]).unwrap_or(c),
33 char::from_u32(chars[1]).unwrap_or('\0'),
34 char::from_u32(chars[2]).unwrap_or('\0'),
35 ]
36 } else {
37 [c, '\0', '\0']
38 }
39}
40
41#[allow(clippy::module_name_repetitions)]
45#[derive(Clone, Debug)]
46pub struct ToTitlecase(CaseMappingIter);
47
48impl Iterator for ToTitlecase {
49 type Item = char;
50 fn next(&mut self) -> Option<char> {
51 self.0.next()
52 }
53 fn size_hint(&self) -> (usize, Option<usize>) {
54 self.0.size_hint()
55 }
56}
57
58impl DoubleEndedIterator for ToTitlecase {
59 fn next_back(&mut self) -> Option<char> {
60 self.0.next_back()
61 }
62}
63
64impl FusedIterator for ToTitlecase {}
65
66impl ExactSizeIterator for ToTitlecase {}
67
68pub trait Titlecase {
69 fn to_titlecase(self) -> ToTitlecase;
70}
71
72impl Titlecase for char {
73 fn to_titlecase(self) -> ToTitlecase {
74 ToTitlecase(CaseMappingIter::new(to_titlecase(self)))
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use alloc::vec::Vec;
81
82 use crate::unicode::titlecase::Titlecase;
83
84 #[test]
85 fn test_char_to_titlecase() {
86 assert_eq!('ß'.to_titlecase().collect::<Vec<_>>(), ['S', 's']);
87 assert_eq!('DŽ'.to_titlecase().collect::<Vec<_>>(), ['Dž']);
88 assert_eq!('ffl'.to_titlecase().collect::<Vec<_>>(), ['F', 'f', 'l']);
89 assert_eq!('i'.to_titlecase().collect::<Vec<_>>(), ['I']);
90 assert_eq!('A'.to_titlecase().collect::<Vec<_>>(), ['A']);
91 }
92
93 #[test]
94 fn test_next_back() {
95 let mut iter = 'ffl'.to_titlecase();
96 assert_eq!(iter.next_back(), Some('l'));
97 assert_eq!(iter.next_back(), Some('f'));
98 assert_eq!(iter.next_back(), Some('F'));
99 assert_eq!(iter.next_back(), None);
100 }
101}