Coverage Report

Created: 2025-10-13 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}