1type ToneTable = [[&'static str; 6]; 3];
5
6pub static A_LO: ToneTable = [
7 ["a", "à", "á", "ả", "ã", "ạ"],
8 ["â", "ầ", "ấ", "ẩ", "ẫ", "ậ"],
9 ["ă", "ằ", "ắ", "ẳ", "ẵ", "ặ"],
10];
11pub static A_UP: ToneTable = [
12 ["A", "À", "Á", "Ả", "Ã", "Ạ"],
13 ["Â", "Ầ", "Ấ", "Ẩ", "Ẫ", "Ậ"],
14 ["Ă", "Ằ", "Ắ", "Ẳ", "Ẵ", "Ặ"],
15];
16pub static E_LO: ToneTable = [
17 ["e", "è", "é", "ẻ", "ẽ", "ẹ"],
18 ["ê", "ề", "ế", "ể", "ễ", "ệ"],
19 ["e", "è", "é", "ẻ", "ẽ", "ẹ"],
20];
21pub static E_UP: ToneTable = [
22 ["E", "È", "É", "Ẻ", "Ẽ", "Ẹ"],
23 ["Ê", "Ề", "Ế", "Ể", "Ễ", "Ệ"],
24 ["E", "È", "É", "Ẻ", "Ẽ", "Ẹ"],
25];
26pub static I_LO: ToneTable = [
27 ["i", "ì", "í", "ỉ", "ĩ", "ị"],
28 ["i", "ì", "í", "ỉ", "ĩ", "ị"],
29 ["i", "ì", "í", "ỉ", "ĩ", "ị"],
30];
31pub static I_UP: ToneTable = [
32 ["I", "Ì", "Í", "Ỉ", "Ĩ", "Ị"],
33 ["I", "Ì", "Í", "Ỉ", "Ĩ", "Ị"],
34 ["I", "Ì", "Í", "Ỉ", "Ĩ", "Ị"],
35];
36pub static O_LO: ToneTable = [
37 ["o", "ò", "ó", "ỏ", "õ", "ọ"],
38 ["ô", "ồ", "ố", "ổ", "ỗ", "ộ"],
39 ["ơ", "ờ", "ớ", "ở", "ỡ", "ợ"],
40];
41pub static O_UP: ToneTable = [
42 ["O", "Ò", "Ó", "Ỏ", "Õ", "Ọ"],
43 ["Ô", "Ồ", "Ố", "Ổ", "Ỗ", "Ộ"],
44 ["Ơ", "Ờ", "Ớ", "Ở", "Ỡ", "Ợ"],
45];
46pub static U_LO: ToneTable = [
47 ["u", "ù", "ú", "ủ", "ũ", "ụ"],
48 ["u", "ù", "ú", "ủ", "ũ", "ụ"],
49 ["ư", "ừ", "ứ", "ử", "ữ", "ự"],
50];
51pub static U_UP: ToneTable = [
52 ["U", "Ù", "Ú", "Ủ", "Ũ", "Ụ"],
53 ["U", "Ù", "Ú", "Ủ", "Ũ", "Ụ"],
54 ["Ư", "Ừ", "Ứ", "Ử", "Ữ", "Ự"],
55];
56pub static Y_LO: ToneTable = [
57 ["y", "ỳ", "ý", "ỷ", "ỹ", "ỵ"],
58 ["y", "ỳ", "ý", "ỷ", "ỹ", "ỵ"],
59 ["y", "ỳ", "ý", "ỷ", "ỹ", "ỵ"],
60];
61pub static Y_UP: ToneTable = [
62 ["Y", "Ỳ", "Ý", "Ỷ", "Ỹ", "Ỵ"],
63 ["Y", "Ỳ", "Ý", "Ỷ", "Ỹ", "Ỵ"],
64 ["Y", "Ỳ", "Ý", "Ỷ", "Ỹ", "Ỵ"],
65];
66
67pub fn vowel_utf8(base: char, variant: u8, tone: u8, upper: bool) -> &'static str {
68 let v = (variant as usize).min(2);
69 let t = (tone as usize).min(5);
70 let table: &ToneTable = match base.to_ascii_lowercase() {
71 'a' => if upper { &A_UP } else { &A_LO },
72 'e' => if upper { &E_UP } else { &E_LO },
73 'i' => if upper { &I_UP } else { &I_LO },
74 'o' => if upper { &O_UP } else { &O_LO },
75 'u' => if upper { &U_UP } else { &U_LO },
76 'y' => if upper { &Y_UP } else { &Y_LO },
77 _ => return if upper { &A_UP } else { &A_LO }[0][0], };
79 table[v][t]
80}
81
82pub fn is_vowel(c: char) -> bool {
83 matches!(c.to_ascii_lowercase(), 'a' | 'e' | 'i' | 'o' | 'u' | 'y')
84}
85
86pub const D_STROKE_LO: &str = "\u{0111}"; pub const D_STROKE_UP: &str = "\u{0110}"; #[cfg(test)]
90mod tests {
91 use super::*;
92
93 #[test]
94 fn basic_vowels() {
95 assert_eq!(vowel_utf8('a', 0, 2, false), "á");
96 assert_eq!(vowel_utf8('a', 0, 1, false), "à");
97 assert_eq!(vowel_utf8('a', 1, 2, false), "ấ");
98 assert_eq!(vowel_utf8('a', 2, 2, false), "ắ");
99 assert_eq!(vowel_utf8('o', 2, 1, false), "ờ");
100 assert_eq!(vowel_utf8('u', 2, 2, false), "ứ");
101 assert_eq!(vowel_utf8('e', 1, 2, false), "ế");
102 }
103
104 #[test]
105 fn uppercase_vowels() {
106 assert_eq!(vowel_utf8('a', 0, 2, true), "Á");
107 assert_eq!(vowel_utf8('A', 1, 0, true), "Â");
108 assert_eq!(vowel_utf8('o', 2, 1, true), "Ờ");
109 }
110}