Coverage Report

Created: 2025-07-11 06:39

/rust/registry/src/index.crates.io-6f17d22bba15001f/icu_properties-1.5.1/src/bidi.rs
Line
Count
Source (jump to first uncovered line)
1
// This file is part of ICU4X. For terms of use, please see the file
2
// called LICENSE at the top level of the ICU4X source tree
3
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5
//! This module exposes tooling for running the [unicode bidi algorithm](https://unicode.org/reports/tr9/) using ICU4X data.
6
//!
7
//! `BidiClassAdapter` enables ICU4X to provide data to [`unicode-bidi`], an external crate implementing UAX #9.
8
//!
9
//! ✨ *Enabled with the `bidi` Cargo feature.*
10
//!
11
//! # Examples
12
//!
13
//!```
14
//! use icu::properties::bidi::BidiClassAdapter;
15
//! use icu::properties::maps;
16
//! use unicode_bidi::BidiInfo;
17
//! // This example text is defined using `concat!` because some browsers
18
//! // and text editors have trouble displaying bidi strings.
19
//! let text =  concat!["א", // RTL#1
20
//!                     "ב", // RTL#2
21
//!                     "ג", // RTL#3
22
//!                     "a", // LTR#1
23
//!                     "b", // LTR#2
24
//!                     "c", // LTR#3
25
//!                     ]; //
26
//!
27
//!
28
//! let adapter = BidiClassAdapter::new(maps::bidi_class());
29
//! // Resolve embedding levels within the text.  Pass `None` to detect the
30
//! // paragraph level automatically.
31
//!
32
//! let bidi_info = BidiInfo::new_with_data_source(&adapter, text, None);
33
//!
34
//! // This paragraph has embedding level 1 because its first strong character is RTL.
35
//! assert_eq!(bidi_info.paragraphs.len(), 1);
36
//! let para = &bidi_info.paragraphs[0];
37
//! assert_eq!(para.level.number(), 1);
38
//! assert!(para.level.is_rtl());
39
//!
40
//! // Re-ordering is done after wrapping each paragraph into a sequence of
41
//! // lines. For this example, I'll just use a single line that spans the
42
//! // entire paragraph.
43
//! let line = para.range.clone();
44
//!
45
//! let display = bidi_info.reorder_line(para, line);
46
//! assert_eq!(display, concat!["a", // LTR#1
47
//!                             "b", // LTR#2
48
//!                             "c", // LTR#3
49
//!                             "ג", // RTL#3
50
//!                             "ב", // RTL#2
51
//!                             "א", // RTL#1
52
//!                             ]);
53
//! ```
54
55
use crate::maps::CodePointMapDataBorrowed;
56
use crate::props::BidiClass;
57
use unicode_bidi::data_source::BidiDataSource;
58
use unicode_bidi::BidiClass as DataSourceBidiClass;
59
60
/// An adapter to convert from icu4x `BidiClass` to `unicode_bidi::BidiClass`.
61
///
62
/// ✨ *Enabled with the `bidi` Cargo feature.*
63
///
64
/// # Example
65
///
66
/// ```
67
/// use icu::collections::codepointtrie::CodePointTrie;
68
/// use icu::properties::bidi::BidiClassAdapter;
69
/// use icu::properties::{maps, BidiClass};
70
/// use unicode_bidi::BidiClass as DataSourceBidiClass;
71
/// use unicode_bidi::BidiDataSource;
72
///
73
/// let adapter = BidiClassAdapter::new(maps::bidi_class());
74
/// assert_eq!(adapter.bidi_class('a'), DataSourceBidiClass::L);
75
/// assert_eq!(adapter.bidi_class('ع'), DataSourceBidiClass::AL);
76
/// ```
77
#[derive(Debug)]
78
pub struct BidiClassAdapter<'a> {
79
    data: CodePointMapDataBorrowed<'a, BidiClass>,
80
}
81
82
impl<'a> BidiClassAdapter<'a> {
83
    /// Creates new instance of `BidiClassAdapter`.
84
0
    pub const fn new(data: CodePointMapDataBorrowed<'a, BidiClass>) -> BidiClassAdapter<'a> {
85
0
        BidiClassAdapter { data }
86
0
    }
87
}
88
89
impl<'a> BidiDataSource for BidiClassAdapter<'a> {
90
    /// Returns a [`DataSourceBidiClass`] given a unicode character.
91
    ///
92
    /// # Example
93
    ///
94
    /// ```
95
    /// use icu::collections::codepointtrie::CodePointTrie;
96
    /// use icu::properties::bidi::BidiClassAdapter;
97
    /// use icu::properties::{maps, BidiClass};
98
    /// use unicode_bidi::BidiClass as DataSourceBidiClass;
99
    /// use unicode_bidi::BidiDataSource;
100
    ///
101
    /// let adapter = BidiClassAdapter::new(maps::bidi_class());
102
    /// assert_eq!(adapter.bidi_class('a'), DataSourceBidiClass::L);
103
    /// ```
104
    ///
105
    /// [`CodePointTrie`]: icu::collections::codepointtrie::CodePointTrie
106
0
    fn bidi_class(&self, c: char) -> DataSourceBidiClass {
107
0
        let bidi_class = self.data.get(c);
108
0
        match bidi_class {
109
0
            BidiClass::LeftToRight => DataSourceBidiClass::L,
110
0
            BidiClass::RightToLeft => DataSourceBidiClass::R,
111
0
            BidiClass::EuropeanNumber => DataSourceBidiClass::EN,
112
0
            BidiClass::EuropeanSeparator => DataSourceBidiClass::ES,
113
0
            BidiClass::EuropeanTerminator => DataSourceBidiClass::ET,
114
0
            BidiClass::ArabicNumber => DataSourceBidiClass::AN,
115
0
            BidiClass::CommonSeparator => DataSourceBidiClass::CS,
116
0
            BidiClass::ParagraphSeparator => DataSourceBidiClass::B,
117
0
            BidiClass::SegmentSeparator => DataSourceBidiClass::S,
118
0
            BidiClass::WhiteSpace => DataSourceBidiClass::WS,
119
0
            BidiClass::OtherNeutral => DataSourceBidiClass::ON,
120
0
            BidiClass::LeftToRightEmbedding => DataSourceBidiClass::LRE,
121
0
            BidiClass::LeftToRightOverride => DataSourceBidiClass::LRO,
122
0
            BidiClass::ArabicLetter => DataSourceBidiClass::AL,
123
0
            BidiClass::RightToLeftEmbedding => DataSourceBidiClass::RLE,
124
0
            BidiClass::RightToLeftOverride => DataSourceBidiClass::RLO,
125
0
            BidiClass::PopDirectionalFormat => DataSourceBidiClass::PDF,
126
0
            BidiClass::NonspacingMark => DataSourceBidiClass::NSM,
127
0
            BidiClass::BoundaryNeutral => DataSourceBidiClass::BN,
128
0
            BidiClass::FirstStrongIsolate => DataSourceBidiClass::FSI,
129
0
            BidiClass::LeftToRightIsolate => DataSourceBidiClass::LRI,
130
0
            BidiClass::RightToLeftIsolate => DataSourceBidiClass::RLI,
131
0
            BidiClass::PopDirectionalIsolate => DataSourceBidiClass::PDI,
132
            _ =>
133
            // This must not happen.
134
            {
135
0
                DataSourceBidiClass::ON
136
            }
137
        }
138
0
    }
139
}