1 // Copyright 2015 The Servo Project Developers. See the
2 // COPYRIGHT file at the top-level directory of this distribution.
3 //
4 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7 // option. This file may not be copied, modified, or distributed
8 // except according to those terms.
9 
10 //! Accessor for `Bidi_Class` property from Unicode Character Database (UCD)
11 
12 mod tables;
13 
14 pub use self::tables::{BidiClass, UNICODE_VERSION};
15 
16 use std::cmp::Ordering::{Equal, Less, Greater};
17 use std::char;
18 
19 use self::tables::bidi_class_table;
20 use BidiClass::*;
21 
22 /// Find the `BidiClass` of a single char.
bidi_class(c: char) -> BidiClass23 pub fn bidi_class(c: char) -> BidiClass {
24     bsearch_range_value_table(c, bidi_class_table)
25 }
26 
is_rtl(bidi_class: BidiClass) -> bool27 pub fn is_rtl(bidi_class: BidiClass) -> bool {
28     match bidi_class {
29         RLE | RLO | RLI => true,
30         _ => false,
31     }
32 }
33 
bsearch_range_value_table(c: char, r: &'static [(char, char, BidiClass)]) -> BidiClass34 fn bsearch_range_value_table(c: char, r: &'static [(char, char, BidiClass)]) -> BidiClass {
35     match r.binary_search_by(|&(lo, hi, _)| if lo <= c && c <= hi {
36         Equal
37     } else if hi < c {
38         Less
39     } else {
40         Greater
41     }) {
42         Ok(idx) => {
43             let (_, _, cat) = r[idx];
44             cat
45         }
46         // UCD/extracted/DerivedBidiClass.txt: "All code points not explicitly listed
47         // for Bidi_Class have the value Left_To_Right (L)."
48         Err(_) => L,
49     }
50 }
51 
52 #[cfg(test)]
53 mod tests {
54     use super::*;
55 
56     #[test]
test_ascii()57     fn test_ascii() {
58         assert_eq!(bidi_class('\u{0000}'), BN);
59         assert_eq!(bidi_class('\u{0040}'), ON);
60         assert_eq!(bidi_class('\u{0041}'), L);
61         assert_eq!(bidi_class('\u{0062}'), L);
62         assert_eq!(bidi_class('\u{007F}'), BN);
63     }
64 
65     #[test]
test_bmp()66     fn test_bmp() {
67         // Hebrew
68         assert_eq!(bidi_class('\u{0590}'), R);
69         assert_eq!(bidi_class('\u{05D0}'), R);
70         assert_eq!(bidi_class('\u{05D1}'), R);
71         assert_eq!(bidi_class('\u{05FF}'), R);
72 
73         // Arabic
74         assert_eq!(bidi_class('\u{0600}'), AN);
75         assert_eq!(bidi_class('\u{0627}'), AL);
76         assert_eq!(bidi_class('\u{07BF}'), AL);
77 
78         // Default R + Arabic Extras
79         assert_eq!(bidi_class('\u{07C0}'), R);
80         assert_eq!(bidi_class('\u{085F}'), R);
81         assert_eq!(bidi_class('\u{0860}'), AL);
82         assert_eq!(bidi_class('\u{0870}'), R);
83         assert_eq!(bidi_class('\u{089F}'), R);
84         assert_eq!(bidi_class('\u{08A0}'), AL);
85         assert_eq!(bidi_class('\u{089F}'), R);
86         assert_eq!(bidi_class('\u{08FF}'), NSM);
87 
88         // Default ET
89         assert_eq!(bidi_class('\u{20A0}'), ET);
90         assert_eq!(bidi_class('\u{20CF}'), ET);
91 
92         // Arabic Presentation Forms
93         assert_eq!(bidi_class('\u{FB1D}'), R);
94         assert_eq!(bidi_class('\u{FB4F}'), R);
95         assert_eq!(bidi_class('\u{FB50}'), AL);
96         assert_eq!(bidi_class('\u{FDCF}'), AL);
97         assert_eq!(bidi_class('\u{FDF0}'), AL);
98         assert_eq!(bidi_class('\u{FDFF}'), AL);
99         assert_eq!(bidi_class('\u{FE70}'), AL);
100         assert_eq!(bidi_class('\u{FEFE}'), AL);
101         assert_eq!(bidi_class('\u{FEFF}'), BN);
102 
103         // noncharacters
104         assert_eq!(bidi_class('\u{FDD0}'), L);
105         assert_eq!(bidi_class('\u{FDD1}'), L);
106         assert_eq!(bidi_class('\u{FDEE}'), L);
107         assert_eq!(bidi_class('\u{FDEF}'), L);
108         assert_eq!(bidi_class('\u{FFFE}'), L);
109         assert_eq!(bidi_class('\u{FFFF}'), L);
110     }
111 
112     #[test]
test_smp()113     fn test_smp() {
114         // Default AL + R
115         assert_eq!(bidi_class('\u{10800}'), R);
116         assert_eq!(bidi_class('\u{10FFF}'), R);
117         assert_eq!(bidi_class('\u{1E800}'), R);
118         assert_eq!(bidi_class('\u{1EDFF}'), R);
119         assert_eq!(bidi_class('\u{1EE00}'), AL);
120         assert_eq!(bidi_class('\u{1EEFF}'), AL);
121         assert_eq!(bidi_class('\u{1EF00}'), R);
122         assert_eq!(bidi_class('\u{1EFFF}'), R);
123     }
124 
125     #[test]
test_unassigned_planes()126     fn test_unassigned_planes() {
127         assert_eq!(bidi_class('\u{30000}'), L);
128         assert_eq!(bidi_class('\u{40000}'), L);
129         assert_eq!(bidi_class('\u{50000}'), L);
130         assert_eq!(bidi_class('\u{60000}'), L);
131         assert_eq!(bidi_class('\u{70000}'), L);
132         assert_eq!(bidi_class('\u{80000}'), L);
133         assert_eq!(bidi_class('\u{90000}'), L);
134         assert_eq!(bidi_class('\u{a0000}'), L);
135     }
136 }
137