1/*!
2
3This library implements
4[Unicode Bidi Mirroring](https://unicode.org/reports/tr44/#BidiMirroring.txt) property detection.
5
6```rust
7use unicode_bidi_mirroring::*;
8
9assert_eq!(get_mirrored('A'), None);
10assert_eq!(get_mirrored('\u{2039}'), Some('\u{203A}'));
11assert_eq!(get_mirrored('\u{203A}'), Some('\u{2039}'));
12
13assert_eq!(is_mirroring('A'), false);
14assert_eq!(is_mirroring('\u{29C4}'), true);
15assert_eq!(is_mirroring('\u{22FF}'), true);
16```
17
18*/
19
20#![doc(html_root_url = "https://docs.rs/unicode-bidi-mirroring/0.1.0")]
21#![no_std]
22#![forbid(unsafe_code)]
23
24/// The Unicode version.
25pub const UNICODE_VERSION: (u8, u8, u8) = (13, 0, 0);
26
27const PAIRS: &[(char, char)] = &[
28 ('\u{0028}', '\u{0029}'),
29 ('\u{003C}', '\u{003E}'),
30 ('\u{005B}', '\u{005D}'),
31 ('\u{007B}', '\u{007D}'),
32 ('\u{00AB}', '\u{00BB}'),
33 ('\u{0F3A}', '\u{0F3B}'),
34 ('\u{0F3C}', '\u{0F3D}'),
35 ('\u{169B}', '\u{169C}'),
36 ('\u{2039}', '\u{203A}'),
37 ('\u{2045}', '\u{2046}'),
38 ('\u{207D}', '\u{207E}'),
39 ('\u{208D}', '\u{208E}'),
40 ('\u{2208}', '\u{220B}'),
41 ('\u{2209}', '\u{220C}'),
42 ('\u{220A}', '\u{220D}'),
43 ('\u{2215}', '\u{29F5}'),
44 ('\u{221F}', '\u{2BFE}'),
45 ('\u{2220}', '\u{29A3}'),
46 ('\u{2221}', '\u{299B}'),
47 ('\u{2222}', '\u{29A0}'),
48 ('\u{2224}', '\u{2AEE}'),
49 ('\u{223C}', '\u{223D}'),
50 ('\u{2243}', '\u{22CD}'),
51 ('\u{2245}', '\u{224C}'),
52 ('\u{2252}', '\u{2253}'),
53 ('\u{2254}', '\u{2255}'),
54 ('\u{2264}', '\u{2265}'),
55 ('\u{2266}', '\u{2267}'),
56 ('\u{2268}', '\u{2269}'),
57 ('\u{226A}', '\u{226B}'),
58 ('\u{226E}', '\u{226F}'),
59 ('\u{2270}', '\u{2271}'),
60 ('\u{2272}', '\u{2273}'),
61 ('\u{2274}', '\u{2275}'),
62 ('\u{2276}', '\u{2277}'),
63 ('\u{2278}', '\u{2279}'),
64 ('\u{227A}', '\u{227B}'),
65 ('\u{227C}', '\u{227D}'),
66 ('\u{227E}', '\u{227F}'),
67 ('\u{2280}', '\u{2281}'),
68 ('\u{2282}', '\u{2283}'),
69 ('\u{2284}', '\u{2285}'),
70 ('\u{2286}', '\u{2287}'),
71 ('\u{2288}', '\u{2289}'),
72 ('\u{228A}', '\u{228B}'),
73 ('\u{228F}', '\u{2290}'),
74 ('\u{2291}', '\u{2292}'),
75 ('\u{2298}', '\u{29B8}'),
76 ('\u{22A2}', '\u{22A3}'),
77 ('\u{22A6}', '\u{2ADE}'),
78 ('\u{22A8}', '\u{2AE4}'),
79 ('\u{22A9}', '\u{2AE3}'),
80 ('\u{22AB}', '\u{2AE5}'),
81 ('\u{22B0}', '\u{22B1}'),
82 ('\u{22B2}', '\u{22B3}'),
83 ('\u{22B4}', '\u{22B5}'),
84 ('\u{22B6}', '\u{22B7}'),
85 ('\u{22B8}', '\u{27DC}'),
86 ('\u{22C9}', '\u{22CA}'),
87 ('\u{22CB}', '\u{22CC}'),
88 ('\u{22D0}', '\u{22D1}'),
89 ('\u{22D6}', '\u{22D7}'),
90 ('\u{22D8}', '\u{22D9}'),
91 ('\u{22DA}', '\u{22DB}'),
92 ('\u{22DC}', '\u{22DD}'),
93 ('\u{22DE}', '\u{22DF}'),
94 ('\u{22E0}', '\u{22E1}'),
95 ('\u{22E2}', '\u{22E3}'),
96 ('\u{22E4}', '\u{22E5}'),
97 ('\u{22E6}', '\u{22E7}'),
98 ('\u{22E8}', '\u{22E9}'),
99 ('\u{22EA}', '\u{22EB}'),
100 ('\u{22EC}', '\u{22ED}'),
101 ('\u{22F0}', '\u{22F1}'),
102 ('\u{22F2}', '\u{22FA}'),
103 ('\u{22F3}', '\u{22FB}'),
104 ('\u{22F4}', '\u{22FC}'),
105 ('\u{22F6}', '\u{22FD}'),
106 ('\u{22F7}', '\u{22FE}'),
107 ('\u{2308}', '\u{2309}'),
108 ('\u{230A}', '\u{230B}'),
109 ('\u{2329}', '\u{232A}'),
110 ('\u{2768}', '\u{2769}'),
111 ('\u{276A}', '\u{276B}'),
112 ('\u{276C}', '\u{276D}'),
113 ('\u{276E}', '\u{276F}'),
114 ('\u{2770}', '\u{2771}'),
115 ('\u{2772}', '\u{2773}'),
116 ('\u{2774}', '\u{2775}'),
117 ('\u{27C3}', '\u{27C4}'),
118 ('\u{27C5}', '\u{27C6}'),
119 ('\u{27C8}', '\u{27C9}'),
120 ('\u{27CB}', '\u{27CD}'),
121 ('\u{27D5}', '\u{27D6}'),
122 ('\u{27DD}', '\u{27DE}'),
123 ('\u{27E2}', '\u{27E3}'),
124 ('\u{27E4}', '\u{27E5}'),
125 ('\u{27E6}', '\u{27E7}'),
126 ('\u{27E8}', '\u{27E9}'),
127 ('\u{27EA}', '\u{27EB}'),
128 ('\u{27EC}', '\u{27ED}'),
129 ('\u{27EE}', '\u{27EF}'),
130 ('\u{2983}', '\u{2984}'),
131 ('\u{2985}', '\u{2986}'),
132 ('\u{2987}', '\u{2988}'),
133 ('\u{2989}', '\u{298A}'),
134 ('\u{298B}', '\u{298C}'),
135 ('\u{298D}', '\u{2990}'),
136 ('\u{298E}', '\u{298F}'),
137 ('\u{2991}', '\u{2992}'),
138 ('\u{2993}', '\u{2994}'),
139 ('\u{2995}', '\u{2996}'),
140 ('\u{2997}', '\u{2998}'),
141 ('\u{29A4}', '\u{29A5}'),
142 ('\u{29A8}', '\u{29A9}'),
143 ('\u{29AA}', '\u{29AB}'),
144 ('\u{29AC}', '\u{29AD}'),
145 ('\u{29AE}', '\u{29AF}'),
146 ('\u{29C0}', '\u{29C1}'),
147 ('\u{29C4}', '\u{29C5}'),
148 ('\u{29CF}', '\u{29D0}'),
149 ('\u{29D1}', '\u{29D2}'),
150 ('\u{29D4}', '\u{29D5}'),
151 ('\u{29D8}', '\u{29D9}'),
152 ('\u{29DA}', '\u{29DB}'),
153 ('\u{29E8}', '\u{29E9}'),
154 ('\u{29F8}', '\u{29F9}'),
155 ('\u{29FC}', '\u{29FD}'),
156 ('\u{2A2B}', '\u{2A2C}'),
157 ('\u{2A2D}', '\u{2A2E}'),
158 ('\u{2A34}', '\u{2A35}'),
159 ('\u{2A3C}', '\u{2A3D}'),
160 ('\u{2A64}', '\u{2A65}'),
161 ('\u{2A79}', '\u{2A7A}'),
162 ('\u{2A7B}', '\u{2A7C}'),
163 ('\u{2A7D}', '\u{2A7E}'),
164 ('\u{2A7F}', '\u{2A80}'),
165 ('\u{2A81}', '\u{2A82}'),
166 ('\u{2A83}', '\u{2A84}'),
167 ('\u{2A85}', '\u{2A86}'),
168 ('\u{2A87}', '\u{2A88}'),
169 ('\u{2A89}', '\u{2A8A}'),
170 ('\u{2A8B}', '\u{2A8C}'),
171 ('\u{2A8D}', '\u{2A8E}'),
172 ('\u{2A8F}', '\u{2A90}'),
173 ('\u{2A91}', '\u{2A92}'),
174 ('\u{2A93}', '\u{2A94}'),
175 ('\u{2A95}', '\u{2A96}'),
176 ('\u{2A97}', '\u{2A98}'),
177 ('\u{2A99}', '\u{2A9A}'),
178 ('\u{2A9B}', '\u{2A9C}'),
179 ('\u{2A9D}', '\u{2A9E}'),
180 ('\u{2A9F}', '\u{2AA0}'),
181 ('\u{2AA1}', '\u{2AA2}'),
182 ('\u{2AA6}', '\u{2AA7}'),
183 ('\u{2AA8}', '\u{2AA9}'),
184 ('\u{2AAA}', '\u{2AAB}'),
185 ('\u{2AAC}', '\u{2AAD}'),
186 ('\u{2AAF}', '\u{2AB0}'),
187 ('\u{2AB1}', '\u{2AB2}'),
188 ('\u{2AB3}', '\u{2AB4}'),
189 ('\u{2AB5}', '\u{2AB6}'),
190 ('\u{2AB7}', '\u{2AB8}'),
191 ('\u{2AB9}', '\u{2ABA}'),
192 ('\u{2ABB}', '\u{2ABC}'),
193 ('\u{2ABD}', '\u{2ABE}'),
194 ('\u{2ABF}', '\u{2AC0}'),
195 ('\u{2AC1}', '\u{2AC2}'),
196 ('\u{2AC3}', '\u{2AC4}'),
197 ('\u{2AC5}', '\u{2AC6}'),
198 ('\u{2AC7}', '\u{2AC8}'),
199 ('\u{2AC9}', '\u{2ACA}'),
200 ('\u{2ACB}', '\u{2ACC}'),
201 ('\u{2ACD}', '\u{2ACE}'),
202 ('\u{2ACF}', '\u{2AD0}'),
203 ('\u{2AD1}', '\u{2AD2}'),
204 ('\u{2AD3}', '\u{2AD4}'),
205 ('\u{2AD5}', '\u{2AD6}'),
206 ('\u{2AEC}', '\u{2AED}'),
207 ('\u{2AF7}', '\u{2AF8}'),
208 ('\u{2AF9}', '\u{2AFA}'),
209 ('\u{2E02}', '\u{2E03}'),
210 ('\u{2E04}', '\u{2E05}'),
211 ('\u{2E09}', '\u{2E0A}'),
212 ('\u{2E0C}', '\u{2E0D}'),
213 ('\u{2E1C}', '\u{2E1D}'),
214 ('\u{2E20}', '\u{2E21}'),
215 ('\u{2E22}', '\u{2E23}'),
216 ('\u{2E24}', '\u{2E25}'),
217 ('\u{2E26}', '\u{2E27}'),
218 ('\u{2E28}', '\u{2E29}'),
219 ('\u{3008}', '\u{3009}'),
220 ('\u{300A}', '\u{300B}'),
221 ('\u{300C}', '\u{300D}'),
222 ('\u{300E}', '\u{300F}'),
223 ('\u{3010}', '\u{3011}'),
224 ('\u{3014}', '\u{3015}'),
225 ('\u{3016}', '\u{3017}'),
226 ('\u{3018}', '\u{3019}'),
227 ('\u{301A}', '\u{301B}'),
228 ('\u{FE59}', '\u{FE5A}'),
229 ('\u{FE5B}', '\u{FE5C}'),
230 ('\u{FE5D}', '\u{FE5E}'),
231 ('\u{FE64}', '\u{FE65}'),
232 ('\u{FF08}', '\u{FF09}'),
233 ('\u{FF1C}', '\u{FF1E}'),
234 ('\u{FF3B}', '\u{FF3D}'),
235 ('\u{FF5B}', '\u{FF5D}'),
236 ('\u{FF5F}', '\u{FF60}'),
237 ('\u{FF62}', '\u{FF63}'),
238];
239
240const OTHER: &[char] = &[
241 '\u{2140}',
242 '\u{2201}',
243 '\u{2202}',
244 '\u{2203}',
245 '\u{2204}',
246 '\u{2211}',
247 '\u{2216}',
248 '\u{221A}',
249 '\u{221B}',
250 '\u{221C}',
251 '\u{221D}',
252 '\u{2226}',
253 '\u{222B}',
254 '\u{222C}',
255 '\u{222D}',
256 '\u{222E}',
257 '\u{222F}',
258 '\u{2230}',
259 '\u{2231}',
260 '\u{2232}',
261 '\u{2233}',
262 '\u{2239}',
263 '\u{223B}',
264 '\u{223E}',
265 '\u{223F}',
266 '\u{2240}',
267 '\u{2241}',
268 '\u{2242}',
269 '\u{2244}',
270 '\u{2246}',
271 '\u{2247}',
272 '\u{2248}',
273 '\u{2249}',
274 '\u{224A}',
275 '\u{224B}',
276 '\u{225F}',
277 '\u{2260}',
278 '\u{2262}',
279 '\u{228C}',
280 '\u{22A7}',
281 '\u{22AA}',
282 '\u{22AC}',
283 '\u{22AD}',
284 '\u{22AE}',
285 '\u{22AF}',
286 '\u{22BE}',
287 '\u{22BF}',
288 '\u{22F5}',
289 '\u{22F8}',
290 '\u{22F9}',
291 '\u{22FF}',
292 '\u{2320}',
293 '\u{2321}',
294 '\u{27C0}',
295 '\u{27CC}',
296 '\u{27D3}',
297 '\u{27D4}',
298 '\u{299C}',
299 '\u{299D}',
300 '\u{299E}',
301 '\u{299F}',
302 '\u{29A2}',
303 '\u{29A6}',
304 '\u{29A7}',
305 '\u{29C2}',
306 '\u{29C3}',
307 '\u{29C9}',
308 '\u{29CE}',
309 '\u{29DC}',
310 '\u{29E1}',
311 '\u{29E3}',
312 '\u{29E4}',
313 '\u{29E5}',
314 '\u{29F4}',
315 '\u{29F6}',
316 '\u{29F7}',
317 '\u{2A0A}',
318 '\u{2A0B}',
319 '\u{2A0C}',
320 '\u{2A0D}',
321 '\u{2A0E}',
322 '\u{2A0F}',
323 '\u{2A10}',
324 '\u{2A11}',
325 '\u{2A12}',
326 '\u{2A13}',
327 '\u{2A14}',
328 '\u{2A15}',
329 '\u{2A16}',
330 '\u{2A17}',
331 '\u{2A18}',
332 '\u{2A19}',
333 '\u{2A1A}',
334 '\u{2A1B}',
335 '\u{2A1C}',
336 '\u{2A1E}',
337 '\u{2A1F}',
338 '\u{2A20}',
339 '\u{2A21}',
340 '\u{2A24}',
341 '\u{2A26}',
342 '\u{2A29}',
343 '\u{2A3E}',
344 '\u{2A57}',
345 '\u{2A58}',
346 '\u{2A6A}',
347 '\u{2A6B}',
348 '\u{2A6C}',
349 '\u{2A6D}',
350 '\u{2A6F}',
351 '\u{2A70}',
352 '\u{2A73}',
353 '\u{2A74}',
354 '\u{2AA3}',
355 '\u{2ADC}',
356 '\u{2AE2}',
357 '\u{2AE6}',
358 '\u{2AF3}',
359 '\u{2AFB}',
360 '\u{2AFD}',
361 '\u{1D6DB}',
362 '\u{1D715}',
363 '\u{1D74F}',
364 '\u{1D789}',
365 '\u{1D7C3}',
366];
367
368/// Returns a bidi mirrored character.
369///
370/// Based on <https://www.unicode.org/Public/UNIDATA/BidiMirroring.txt>.
371pub fn get_mirrored(c: char) -> Option<char> {
372 if let Ok(idx: usize) = PAIRS.binary_search_by(|v: &(char, char)| v.0.cmp(&c)) {
373 return Some(PAIRS[idx].1);
374 }
375
376 if let Ok(idx: usize) = PAIRS.binary_search_by(|v: &(char, char)| v.1.cmp(&c)) {
377 return Some(PAIRS[idx].0);
378 }
379
380 None
381}
382
383/// Checks that character is bidi mirrored.
384///
385/// Based on <https://www.unicode.org/Public/UNIDATA/BidiMirroring.txt>.
386pub fn is_mirroring(c: char) -> bool {
387 PAIRS.binary_search_by(|v: &(char, char)| v.0.cmp(&c)).is_ok() ||
388 PAIRS.binary_search_by(|v: &(char, char)| v.1.cmp(&c)).is_ok() ||
389 OTHER.binary_search_by(|v: &char| v.cmp(&c)).is_ok()
390}
391