1use std::collections::HashMap;
2use std::sync::OnceLock;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum UnicodeScriptKind {
7 UnicodeSubscript,
8 UnicodeSuperscript,
9}
10
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct UnicodeScript {
13 pub replacement: String,
14 pub kind: UnicodeScriptKind,
15}
16
17fn unicode_scripts() -> &'static HashMap<String, UnicodeScript> {
18 static TABLE: OnceLock<HashMap<String, UnicodeScript>> = OnceLock::new();
19 TABLE.get_or_init(|| {
20 let mut map = HashMap::new();
21 fn sub(map: &mut HashMap<String, UnicodeScript>, c: &str, r: &str) {
22 map.insert(
23 c.to_string(),
24 UnicodeScript {
25 replacement: r.to_string(),
26 kind: UnicodeScriptKind::UnicodeSubscript,
27 },
28 );
29 }
30 fn sup(map: &mut HashMap<String, UnicodeScript>, c: &str, r: &str) {
31 map.insert(
32 c.to_string(),
33 UnicodeScript {
34 replacement: r.to_string(),
35 kind: UnicodeScriptKind::UnicodeSuperscript,
36 },
37 );
38 }
39 sub(&mut map, "₊", "+");
40 sub(&mut map, "₋", "-");
41 sub(&mut map, "₌", "=");
42 sub(&mut map, "₍", "(");
43 sub(&mut map, "₎", ")");
44 sub(&mut map, "₀", "0");
45 sub(&mut map, "₁", "1");
46 sub(&mut map, "₂", "2");
47 sub(&mut map, "₃", "3");
48 sub(&mut map, "₄", "4");
49 sub(&mut map, "₅", "5");
50 sub(&mut map, "₆", "6");
51 sub(&mut map, "₇", "7");
52 sub(&mut map, "₈", "8");
53 sub(&mut map, "₉", "9");
54 sub(&mut map, "ₐ", "a");
55 sub(&mut map, "ₑ", "e");
56 sub(&mut map, "ₕ", "h");
57 sub(&mut map, "ᵢ", "i");
58 sub(&mut map, "ⱼ", "j");
59 sub(&mut map, "ₖ", "k");
60 sub(&mut map, "ₗ", "l");
61 sub(&mut map, "ₘ", "m");
62 sub(&mut map, "ₙ", "n");
63 sub(&mut map, "ₒ", "o");
64 sub(&mut map, "ₚ", "p");
65 sub(&mut map, "ᵣ", "r");
66 sub(&mut map, "ₛ", "s");
67 sub(&mut map, "ₜ", "t");
68 sub(&mut map, "ᵤ", "u");
69 sub(&mut map, "ᵥ", "v");
70 sub(&mut map, "ₓ", "x");
71 sub(&mut map, "ᵦ", "β");
72 sub(&mut map, "ᵧ", "γ");
73 sub(&mut map, "ᵨ", "ρ");
74 sub(&mut map, "ᵩ", "ϕ");
75 sub(&mut map, "ᵪ", "χ");
76 sup(&mut map, "⁺", "+");
77 sup(&mut map, "⁻", "-");
78 sup(&mut map, "⁼", "=");
79 sup(&mut map, "⁽", "(");
80 sup(&mut map, "⁾", ")");
81 sup(&mut map, "⁰", "0");
82 sup(&mut map, "¹", "1");
83 sup(&mut map, "²", "2");
84 sup(&mut map, "³", "3");
85 sup(&mut map, "⁴", "4");
86 sup(&mut map, "⁵", "5");
87 sup(&mut map, "⁶", "6");
88 sup(&mut map, "⁷", "7");
89 sup(&mut map, "⁸", "8");
90 sup(&mut map, "⁹", "9");
91 sup(&mut map, "ᴬ", "A");
92 sup(&mut map, "ᴮ", "B");
93 sup(&mut map, "ᴰ", "D");
94 sup(&mut map, "ᴱ", "E");
95 sup(&mut map, "ᴳ", "G");
96 sup(&mut map, "ᴴ", "H");
97 sup(&mut map, "ᴵ", "I");
98 sup(&mut map, "ᴶ", "J");
99 sup(&mut map, "ᴷ", "K");
100 sup(&mut map, "ᴸ", "L");
101 sup(&mut map, "ᴹ", "M");
102 sup(&mut map, "ᴺ", "N");
103 sup(&mut map, "ᴼ", "O");
104 sup(&mut map, "ᴾ", "P");
105 sup(&mut map, "ᴿ", "R");
106 sup(&mut map, "ᵀ", "T");
107 sup(&mut map, "ᵁ", "U");
108 sup(&mut map, "ⱽ", "V");
109 sup(&mut map, "ᵂ", "W");
110 sup(&mut map, "ᵃ", "a");
111 sup(&mut map, "ᵇ", "b");
112 sup(&mut map, "ᶜ", "c");
113 sup(&mut map, "ᵈ", "d");
114 sup(&mut map, "ᵉ", "e");
115 sup(&mut map, "ᶠ", "f");
116 sup(&mut map, "ᵍ", "g");
117 sup(&mut map, "ʰ", "h");
118 sup(&mut map, "ⁱ", "i");
119 sup(&mut map, "ʲ", "j");
120 sup(&mut map, "ᵏ", "k");
121 sup(&mut map, "ˡ", "l");
122 sup(&mut map, "ᵐ", "m");
123 sup(&mut map, "ⁿ", "n");
124 sup(&mut map, "ᵒ", "o");
125 sup(&mut map, "ᵖ", "p");
126 sup(&mut map, "ʳ", "r");
127 sup(&mut map, "ˢ", "s");
128 sup(&mut map, "ᵗ", "t");
129 sup(&mut map, "ᵘ", "u");
130 sup(&mut map, "ᵛ", "v");
131 sup(&mut map, "ʷ", "w");
132 sup(&mut map, "ˣ", "x");
133 sup(&mut map, "ʸ", "y");
134 sup(&mut map, "ᶻ", "z");
135 sup(&mut map, "ᵝ", "β");
136 sup(&mut map, "ᵞ", "γ");
137 sup(&mut map, "ᵟ", "δ");
138 sup(&mut map, "ᵠ", "ϕ");
139 sup(&mut map, "ᵡ", "χ");
140 sup(&mut map, "ᶿ", "θ");
141 map
142 })
143}
144
145pub(crate) fn lookup_unicode_script(text: &str) -> Option<&'static UnicodeScript> {
146 unicode_scripts().get(text)
147}
148
149pub fn unicode_script_character(kind: UnicodeScriptKind, replacement: &str) -> Option<String> {
151 unicode_scripts()
152 .iter()
153 .find(|(_, script)| script.kind == kind && script.replacement == replacement)
154 .map(|(character, _)| character.clone())
155}
156
157pub fn supported_codepoint(code: u32) -> bool {
160 (0x0100..=0x024F).contains(&code) || (0x0300..=0x036F).contains(&code) || (0x0400..=0x04FF).contains(&code) || (0x0530..=0x058F).contains(&code) || (0x0900..=0x109F).contains(&code) || (0x10A0..=0x10FF).contains(&code) || (0x3000..=0x30FF).contains(&code) || (0x4E00..=0x9FAF).contains(&code) || (0xFF00..=0xFF60).contains(&code) || (0xAC00..=0xD7AF).contains(&code) }