/rust/registry/src/index.crates.io-1949cf8c6b5b557f/unicode-bidi-0.3.18/src/level.rs
Line | Count | Source |
1 | | // Copyright 2017 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 | | //! Bidi Embedding Level |
11 | | //! |
12 | | //! See [`Level`](struct.Level.html) for more details. |
13 | | //! |
14 | | //! <http://www.unicode.org/reports/tr9/#BD2> |
15 | | |
16 | | use alloc::{ |
17 | | string::{String, ToString}, |
18 | | vec::Vec, |
19 | | }; |
20 | | use core::slice; |
21 | | |
22 | | use super::char_data::BidiClass; |
23 | | |
24 | | /// Embedding Level |
25 | | /// |
26 | | /// Embedding Levels are numbers between 0 and 126 (inclusive), where even values denote a |
27 | | /// left-to-right (LTR) direction and odd values a right-to-left (RTL) direction. |
28 | | /// |
29 | | /// This struct maintains a *valid* status for level numbers, meaning that creating a new level, or |
30 | | /// mutating an existing level, with the value smaller than `0` (before conversion to `u8`) or |
31 | | /// larger than 125 results in an `Error`. |
32 | | /// |
33 | | /// <http://www.unicode.org/reports/tr9/#BD2> |
34 | | #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] |
35 | | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
36 | | #[repr(transparent)] |
37 | | pub struct Level(u8); |
38 | | |
39 | | pub const LTR_LEVEL: Level = Level(0); |
40 | | pub const RTL_LEVEL: Level = Level(1); |
41 | | |
42 | | const MAX_DEPTH: u8 = 125; |
43 | | /// During explicit level resolution, embedding level can go as high as `max_depth`. |
44 | | pub const MAX_EXPLICIT_DEPTH: u8 = MAX_DEPTH; |
45 | | /// During implicit level resolution, embedding level can go as high as `max_depth + 1`. |
46 | | pub const MAX_IMPLICIT_DEPTH: u8 = MAX_DEPTH + 1; |
47 | | |
48 | | /// Errors that can occur on Level creation or mutation |
49 | | #[derive(Debug, PartialEq)] |
50 | | pub enum Error { |
51 | | /// Out-of-range (invalid) embedding level number. |
52 | | OutOfRangeNumber, |
53 | | } |
54 | | |
55 | | impl Level { |
56 | | /// New LTR level with smallest number value (0). |
57 | | #[inline] |
58 | 0 | pub fn ltr() -> Level { |
59 | 0 | LTR_LEVEL |
60 | 0 | } Unexecuted instantiation: <unicode_bidi::level::Level>::ltr Unexecuted instantiation: <unicode_bidi::level::Level>::ltr |
61 | | |
62 | | /// New RTL level with smallest number value (1). |
63 | | #[inline] |
64 | 0 | pub fn rtl() -> Level { |
65 | 0 | RTL_LEVEL |
66 | 0 | } Unexecuted instantiation: <unicode_bidi::level::Level>::rtl Unexecuted instantiation: <unicode_bidi::level::Level>::rtl |
67 | | |
68 | | /// Maximum depth of the directional status stack during implicit resolutions. |
69 | 0 | pub fn max_implicit_depth() -> u8 { |
70 | 0 | MAX_IMPLICIT_DEPTH |
71 | 0 | } |
72 | | |
73 | | /// Maximum depth of the directional status stack during explicit resolutions. |
74 | 0 | pub fn max_explicit_depth() -> u8 { |
75 | 0 | MAX_EXPLICIT_DEPTH |
76 | 0 | } |
77 | | |
78 | | // == Inquiries == |
79 | | |
80 | | /// Create new level, fail if number is larger than `max_depth + 1`. |
81 | | #[inline] |
82 | 0 | pub fn new(number: u8) -> Result<Level, Error> { |
83 | 0 | if number <= MAX_IMPLICIT_DEPTH { |
84 | 0 | Ok(Level(number)) |
85 | | } else { |
86 | 0 | Err(Error::OutOfRangeNumber) |
87 | | } |
88 | 0 | } Unexecuted instantiation: <unicode_bidi::level::Level>::new Unexecuted instantiation: <unicode_bidi::level::Level>::new |
89 | | |
90 | | /// Create new level, fail if number is larger than `max_depth`. |
91 | | #[inline] |
92 | 0 | pub fn new_explicit(number: u8) -> Result<Level, Error> { |
93 | 0 | if number <= MAX_EXPLICIT_DEPTH { |
94 | 0 | Ok(Level(number)) |
95 | | } else { |
96 | 0 | Err(Error::OutOfRangeNumber) |
97 | | } |
98 | 0 | } Unexecuted instantiation: <unicode_bidi::level::Level>::new_explicit Unexecuted instantiation: <unicode_bidi::level::Level>::new_explicit |
99 | | |
100 | | // == Inquiries == |
101 | | |
102 | | /// The level number. |
103 | | #[inline] |
104 | 0 | pub fn number(&self) -> u8 { |
105 | 0 | self.0 |
106 | 0 | } Unexecuted instantiation: <unicode_bidi::level::Level>::number Unexecuted instantiation: <unicode_bidi::level::Level>::number |
107 | | |
108 | | /// If this level is left-to-right. |
109 | | #[inline] |
110 | 0 | pub fn is_ltr(&self) -> bool { |
111 | 0 | self.0 % 2 == 0 |
112 | 0 | } Unexecuted instantiation: <unicode_bidi::level::Level>::is_ltr Unexecuted instantiation: <unicode_bidi::level::Level>::is_ltr |
113 | | |
114 | | /// If this level is right-to-left. |
115 | | #[inline] |
116 | 0 | pub fn is_rtl(&self) -> bool { |
117 | 0 | self.0 % 2 == 1 |
118 | 0 | } Unexecuted instantiation: <unicode_bidi::level::Level>::is_rtl Unexecuted instantiation: <unicode_bidi::level::Level>::is_rtl |
119 | | |
120 | | // == Mutators == |
121 | | |
122 | | /// Raise level by `amount`, fail if number is larger than `max_depth + 1`. |
123 | | #[inline] |
124 | 0 | pub fn raise(&mut self, amount: u8) -> Result<(), Error> { |
125 | 0 | match self.0.checked_add(amount) { |
126 | 0 | Some(number) => { |
127 | 0 | if number <= MAX_IMPLICIT_DEPTH { |
128 | 0 | self.0 = number; |
129 | 0 | Ok(()) |
130 | | } else { |
131 | 0 | Err(Error::OutOfRangeNumber) |
132 | | } |
133 | | } |
134 | 0 | None => Err(Error::OutOfRangeNumber), |
135 | | } |
136 | 0 | } |
137 | | |
138 | | /// Raise level by `amount`, fail if number is larger than `max_depth`. |
139 | | #[inline] |
140 | 0 | pub fn raise_explicit(&mut self, amount: u8) -> Result<(), Error> { |
141 | 0 | match self.0.checked_add(amount) { |
142 | 0 | Some(number) => { |
143 | 0 | if number <= MAX_EXPLICIT_DEPTH { |
144 | 0 | self.0 = number; |
145 | 0 | Ok(()) |
146 | | } else { |
147 | 0 | Err(Error::OutOfRangeNumber) |
148 | | } |
149 | | } |
150 | 0 | None => Err(Error::OutOfRangeNumber), |
151 | | } |
152 | 0 | } |
153 | | |
154 | | /// Lower level by `amount`, fail if number goes below zero. |
155 | | #[inline] |
156 | 0 | pub fn lower(&mut self, amount: u8) -> Result<(), Error> { |
157 | 0 | match self.0.checked_sub(amount) { |
158 | 0 | Some(number) => { |
159 | 0 | self.0 = number; |
160 | 0 | Ok(()) |
161 | | } |
162 | 0 | None => Err(Error::OutOfRangeNumber), |
163 | | } |
164 | 0 | } |
165 | | |
166 | | // == Helpers == |
167 | | |
168 | | /// The next LTR (even) level greater than this, or fail if number is larger than `max_depth`. |
169 | | #[inline] |
170 | 0 | pub fn new_explicit_next_ltr(&self) -> Result<Level, Error> { |
171 | 0 | Level::new_explicit((self.0 + 2) & !1) |
172 | 0 | } Unexecuted instantiation: <unicode_bidi::level::Level>::new_explicit_next_ltr Unexecuted instantiation: <unicode_bidi::level::Level>::new_explicit_next_ltr |
173 | | |
174 | | /// The next RTL (odd) level greater than this, or fail if number is larger than `max_depth`. |
175 | | #[inline] |
176 | 0 | pub fn new_explicit_next_rtl(&self) -> Result<Level, Error> { |
177 | 0 | Level::new_explicit((self.0 + 1) | 1) |
178 | 0 | } Unexecuted instantiation: <unicode_bidi::level::Level>::new_explicit_next_rtl Unexecuted instantiation: <unicode_bidi::level::Level>::new_explicit_next_rtl |
179 | | |
180 | | /// The lowest RTL (odd) level greater than or equal to this, or fail if number is larger than |
181 | | /// `max_depth + 1`. |
182 | | #[inline] |
183 | 0 | pub fn new_lowest_ge_rtl(&self) -> Result<Level, Error> { |
184 | 0 | Level::new(self.0 | 1) |
185 | 0 | } |
186 | | |
187 | | /// Generate a character type based on a level (as specified in steps X10 and N2). |
188 | | #[inline] |
189 | 0 | pub fn bidi_class(&self) -> BidiClass { |
190 | 0 | if self.is_rtl() { |
191 | 0 | BidiClass::R |
192 | | } else { |
193 | 0 | BidiClass::L |
194 | | } |
195 | 0 | } Unexecuted instantiation: <unicode_bidi::level::Level>::bidi_class Unexecuted instantiation: <unicode_bidi::level::Level>::bidi_class |
196 | | |
197 | 0 | pub fn vec(v: &[u8]) -> Vec<Level> { |
198 | 0 | v.iter().map(|&x| x.into()).collect() |
199 | 0 | } |
200 | | |
201 | | /// Converts a byte slice to a slice of Levels |
202 | | /// |
203 | | /// Does _not_ check if each level is within bounds (`<=` [`MAX_IMPLICIT_DEPTH`]), |
204 | | /// which is not a requirement for safety but is a requirement for correctness of the algorithm. |
205 | 0 | pub fn from_slice_unchecked(v: &[u8]) -> &[Level] { |
206 | 0 | debug_assert_eq!(core::mem::size_of::<u8>(), core::mem::size_of::<Level>()); |
207 | | unsafe { |
208 | | // Safety: The two arrays are the same size and layout-compatible since |
209 | | // Level is `repr(transparent)` over `u8` |
210 | 0 | slice::from_raw_parts(v as *const [u8] as *const u8 as *const Level, v.len()) |
211 | | } |
212 | 0 | } |
213 | | } |
214 | | |
215 | | /// If levels has any RTL (odd) level |
216 | | /// |
217 | | /// This information is usually used to skip re-ordering of text when no RTL level is present |
218 | | #[inline] |
219 | 0 | pub fn has_rtl(levels: &[Level]) -> bool { |
220 | 0 | levels.iter().any(|&lvl| lvl.is_rtl()) |
221 | 0 | } |
222 | | |
223 | | impl From<Level> for u8 { |
224 | | /// Convert to the level number |
225 | | #[inline] |
226 | 0 | fn from(val: Level) -> Self { |
227 | 0 | val.number() |
228 | 0 | } |
229 | | } |
230 | | |
231 | | impl From<u8> for Level { |
232 | | /// Create level by number |
233 | | #[inline] |
234 | 0 | fn from(number: u8) -> Level { |
235 | 0 | Level::new(number).expect("Level number error") |
236 | 0 | } |
237 | | } |
238 | | |
239 | | /// Used for matching levels in conformance tests |
240 | | impl<'a> PartialEq<&'a str> for Level { |
241 | | #[inline] |
242 | 0 | fn eq(&self, s: &&'a str) -> bool { |
243 | 0 | *s == "x" || *s == self.0.to_string() |
244 | 0 | } |
245 | | } |
246 | | |
247 | | /// Used for matching levels in conformance tests |
248 | | impl PartialEq<String> for Level { |
249 | | #[inline] |
250 | 0 | fn eq(&self, s: &String) -> bool { |
251 | 0 | self == &s.as_str() |
252 | 0 | } |
253 | | } |
254 | | |
255 | | #[cfg(test)] |
256 | | mod tests { |
257 | | use super::*; |
258 | | |
259 | | #[test] |
260 | | fn test_new() { |
261 | | assert_eq!(Level::new(0), Ok(Level(0))); |
262 | | assert_eq!(Level::new(1), Ok(Level(1))); |
263 | | assert_eq!(Level::new(10), Ok(Level(10))); |
264 | | assert_eq!(Level::new(125), Ok(Level(125))); |
265 | | assert_eq!(Level::new(126), Ok(Level(126))); |
266 | | assert_eq!(Level::new(127), Err(Error::OutOfRangeNumber)); |
267 | | assert_eq!(Level::new(255), Err(Error::OutOfRangeNumber)); |
268 | | } |
269 | | |
270 | | #[test] |
271 | | fn test_new_explicit() { |
272 | | assert_eq!(Level::new_explicit(0), Ok(Level(0))); |
273 | | assert_eq!(Level::new_explicit(1), Ok(Level(1))); |
274 | | assert_eq!(Level::new_explicit(10), Ok(Level(10))); |
275 | | assert_eq!(Level::new_explicit(125), Ok(Level(125))); |
276 | | assert_eq!(Level::new_explicit(126), Err(Error::OutOfRangeNumber)); |
277 | | assert_eq!(Level::new_explicit(255), Err(Error::OutOfRangeNumber)); |
278 | | } |
279 | | |
280 | | #[test] |
281 | | fn test_is_ltr() { |
282 | | assert_eq!(Level(0).is_ltr(), true); |
283 | | assert_eq!(Level(1).is_ltr(), false); |
284 | | assert_eq!(Level(10).is_ltr(), true); |
285 | | assert_eq!(Level(11).is_ltr(), false); |
286 | | assert_eq!(Level(124).is_ltr(), true); |
287 | | assert_eq!(Level(125).is_ltr(), false); |
288 | | } |
289 | | |
290 | | #[test] |
291 | | fn test_is_rtl() { |
292 | | assert_eq!(Level(0).is_rtl(), false); |
293 | | assert_eq!(Level(1).is_rtl(), true); |
294 | | assert_eq!(Level(10).is_rtl(), false); |
295 | | assert_eq!(Level(11).is_rtl(), true); |
296 | | assert_eq!(Level(124).is_rtl(), false); |
297 | | assert_eq!(Level(125).is_rtl(), true); |
298 | | } |
299 | | |
300 | | #[test] |
301 | | fn test_raise() { |
302 | | let mut level = Level::ltr(); |
303 | | assert_eq!(level.number(), 0); |
304 | | assert!(level.raise(100).is_ok()); |
305 | | assert_eq!(level.number(), 100); |
306 | | assert!(level.raise(26).is_ok()); |
307 | | assert_eq!(level.number(), 126); |
308 | | assert!(level.raise(1).is_err()); // invalid! |
309 | | assert!(level.raise(250).is_err()); // overflow! |
310 | | assert_eq!(level.number(), 126); |
311 | | } |
312 | | |
313 | | #[test] |
314 | | fn test_raise_explicit() { |
315 | | let mut level = Level::ltr(); |
316 | | assert_eq!(level.number(), 0); |
317 | | assert!(level.raise_explicit(100).is_ok()); |
318 | | assert_eq!(level.number(), 100); |
319 | | assert!(level.raise_explicit(25).is_ok()); |
320 | | assert_eq!(level.number(), 125); |
321 | | assert!(level.raise_explicit(1).is_err()); // invalid! |
322 | | assert!(level.raise_explicit(250).is_err()); // overflow! |
323 | | assert_eq!(level.number(), 125); |
324 | | } |
325 | | |
326 | | #[test] |
327 | | fn test_lower() { |
328 | | let mut level = Level::rtl(); |
329 | | assert_eq!(level.number(), 1); |
330 | | assert!(level.lower(1).is_ok()); |
331 | | assert_eq!(level.number(), 0); |
332 | | assert!(level.lower(1).is_err()); // underflow! |
333 | | assert!(level.lower(250).is_err()); // underflow! |
334 | | assert_eq!(level.number(), 0); |
335 | | } |
336 | | |
337 | | #[test] |
338 | | fn test_has_rtl() { |
339 | | assert_eq!(has_rtl(&Level::vec(&[0, 0, 0])), false); |
340 | | assert_eq!(has_rtl(&Level::vec(&[0, 1, 0])), true); |
341 | | assert_eq!(has_rtl(&Level::vec(&[0, 2, 0])), false); |
342 | | assert_eq!(has_rtl(&Level::vec(&[0, 125, 0])), true); |
343 | | assert_eq!(has_rtl(&Level::vec(&[0, 126, 0])), false); |
344 | | } |
345 | | |
346 | | #[test] |
347 | | fn test_into() { |
348 | | let level = Level::rtl(); |
349 | | let number: u8 = level.into(); |
350 | | assert_eq!(1u8, number); |
351 | | } |
352 | | |
353 | | #[test] |
354 | | fn test_vec() { |
355 | | assert_eq!( |
356 | | Level::vec(&[0, 1, 125]), |
357 | | vec![Level(0), Level(1), Level(125)] |
358 | | ); |
359 | | } |
360 | | |
361 | | #[test] |
362 | | fn test_str_eq() { |
363 | | assert_eq!(Level::vec(&[0, 1, 4, 125]), vec!["0", "1", "x", "125"]); |
364 | | assert_ne!(Level::vec(&[0, 1, 4, 125]), vec!["0", "1", "5", "125"]); |
365 | | } |
366 | | |
367 | | #[test] |
368 | | fn test_string_eq() { |
369 | | assert_eq!( |
370 | | Level::vec(&[0, 1, 4, 125]), |
371 | | vec!["0".to_string(), "1".to_string(), "x".to_string(), "125".to_string()] |
372 | | ); |
373 | | } |
374 | | } |
375 | | |
376 | | #[cfg(all(feature = "serde", test))] |
377 | | mod serde_tests { |
378 | | use super::*; |
379 | | use serde_test::{assert_tokens, Token}; |
380 | | |
381 | | #[test] |
382 | | fn test_statics() { |
383 | | assert_tokens( |
384 | | &Level::ltr(), |
385 | | &[Token::NewtypeStruct { name: "Level" }, Token::U8(0)], |
386 | | ); |
387 | | assert_tokens( |
388 | | &Level::rtl(), |
389 | | &[Token::NewtypeStruct { name: "Level" }, Token::U8(1)], |
390 | | ); |
391 | | } |
392 | | |
393 | | #[test] |
394 | | fn test_new() { |
395 | | let level = Level::new(42).unwrap(); |
396 | | assert_tokens( |
397 | | &level, |
398 | | &[Token::NewtypeStruct { name: "Level" }, Token::U8(42)], |
399 | | ); |
400 | | } |
401 | | } |