Coverage Report

Created: 2026-04-29 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/idna_adapter-1.2.2/src/lib.rs
Line
Count
Source
1
// Copyright The rust-url developers.
2
//
3
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6
// option. This file may not be copied, modified, or distributed
7
// except according to those terms.
8
9
//! This crate abstracts over a Unicode back end for the [`idna`][1]
10
//! crate.
11
//!
12
//! To work around the lack of [`global-features`][2] in Cargo, this
13
//! crate allows the top level `Cargo.lock` to choose an alternative
14
//! Unicode back end for the `idna` crate by pinning a version of this
15
//! crate.
16
//!
17
//! See the [README of the latest version][3] for more details.
18
//!
19
//! [1]: https://docs.rs/crate/idna/latest
20
//! [2]: https://internals.rust-lang.org/t/pre-rfc-mutually-excusive-global-features/19618
21
//! [3]: https://docs.rs/crate/idna_adapter/latest
22
23
#![no_std]
24
25
use icu_normalizer::uts46::Uts46MapperBorrowed;
26
use icu_properties::props::GeneralCategory;
27
use icu_properties::CodePointMapDataBorrowed;
28
29
/// Turns a joining type into a mask for comparing with multiple type at once.
30
0
const fn joining_type_to_mask(jt: icu_properties::props::JoiningType) -> u32 {
31
0
    1u32 << jt.to_icu4c_value()
32
0
}
33
34
/// Mask for checking for both left and dual joining.
35
pub const LEFT_OR_DUAL_JOINING_MASK: JoiningTypeMask = JoiningTypeMask(
36
    joining_type_to_mask(icu_properties::props::JoiningType::LeftJoining)
37
        | joining_type_to_mask(icu_properties::props::JoiningType::DualJoining),
38
);
39
40
/// Mask for checking for both left and dual joining.
41
pub const RIGHT_OR_DUAL_JOINING_MASK: JoiningTypeMask = JoiningTypeMask(
42
    joining_type_to_mask(icu_properties::props::JoiningType::RightJoining)
43
        | joining_type_to_mask(icu_properties::props::JoiningType::DualJoining),
44
);
45
46
/// Turns a bidi class into a mask for comparing with multiple classes at once.
47
0
const fn bidi_class_to_mask(bc: icu_properties::props::BidiClass) -> u32 {
48
0
    1u32 << bc.to_icu4c_value()
49
0
}
50
51
/// Mask for checking if the domain is a bidi domain.
52
pub const RTL_MASK: BidiClassMask = BidiClassMask(
53
    bidi_class_to_mask(icu_properties::props::BidiClass::RightToLeft)
54
        | bidi_class_to_mask(icu_properties::props::BidiClass::ArabicLetter)
55
        | bidi_class_to_mask(icu_properties::props::BidiClass::ArabicNumber),
56
);
57
58
/// Mask for allowable bidi classes in the first character of a label
59
/// (either LTR or RTL) in a bidi domain.
60
pub const FIRST_BC_MASK: BidiClassMask = BidiClassMask(
61
    bidi_class_to_mask(icu_properties::props::BidiClass::LeftToRight)
62
        | bidi_class_to_mask(icu_properties::props::BidiClass::RightToLeft)
63
        | bidi_class_to_mask(icu_properties::props::BidiClass::ArabicLetter),
64
);
65
66
// Mask for allowable bidi classes of the last (non-Non-Spacing Mark)
67
// character in an LTR label in a bidi domain.
68
pub const LAST_LTR_MASK: BidiClassMask = BidiClassMask(
69
    bidi_class_to_mask(icu_properties::props::BidiClass::LeftToRight)
70
        | bidi_class_to_mask(icu_properties::props::BidiClass::EuropeanNumber),
71
);
72
73
// Mask for allowable bidi classes of the last (non-Non-Spacing Mark)
74
// character in an RTL label in a bidi domain.
75
pub const LAST_RTL_MASK: BidiClassMask = BidiClassMask(
76
    bidi_class_to_mask(icu_properties::props::BidiClass::RightToLeft)
77
        | bidi_class_to_mask(icu_properties::props::BidiClass::ArabicLetter)
78
        | bidi_class_to_mask(icu_properties::props::BidiClass::EuropeanNumber)
79
        | bidi_class_to_mask(icu_properties::props::BidiClass::ArabicNumber),
80
);
81
82
// Mask for allowable bidi classes of the middle characters in an LTR label in a bidi domain.
83
pub const MIDDLE_LTR_MASK: BidiClassMask = BidiClassMask(
84
    bidi_class_to_mask(icu_properties::props::BidiClass::LeftToRight)
85
        | bidi_class_to_mask(icu_properties::props::BidiClass::EuropeanNumber)
86
        | bidi_class_to_mask(icu_properties::props::BidiClass::EuropeanSeparator)
87
        | bidi_class_to_mask(icu_properties::props::BidiClass::CommonSeparator)
88
        | bidi_class_to_mask(icu_properties::props::BidiClass::EuropeanTerminator)
89
        | bidi_class_to_mask(icu_properties::props::BidiClass::OtherNeutral)
90
        | bidi_class_to_mask(icu_properties::props::BidiClass::BoundaryNeutral)
91
        | bidi_class_to_mask(icu_properties::props::BidiClass::NonspacingMark),
92
);
93
94
// Mask for allowable bidi classes of the middle characters in an RTL label in a bidi domain.
95
pub const MIDDLE_RTL_MASK: BidiClassMask = BidiClassMask(
96
    bidi_class_to_mask(icu_properties::props::BidiClass::RightToLeft)
97
        | bidi_class_to_mask(icu_properties::props::BidiClass::ArabicLetter)
98
        | bidi_class_to_mask(icu_properties::props::BidiClass::ArabicNumber)
99
        | bidi_class_to_mask(icu_properties::props::BidiClass::EuropeanNumber)
100
        | bidi_class_to_mask(icu_properties::props::BidiClass::EuropeanSeparator)
101
        | bidi_class_to_mask(icu_properties::props::BidiClass::CommonSeparator)
102
        | bidi_class_to_mask(icu_properties::props::BidiClass::EuropeanTerminator)
103
        | bidi_class_to_mask(icu_properties::props::BidiClass::OtherNeutral)
104
        | bidi_class_to_mask(icu_properties::props::BidiClass::BoundaryNeutral)
105
        | bidi_class_to_mask(icu_properties::props::BidiClass::NonspacingMark),
106
);
107
108
/// Turns a genecal category into a mask for comparing with multiple categories at once.
109
0
const fn general_category_to_mask(gc: GeneralCategory) -> u32 {
110
0
    1 << (gc as u32)
111
0
}
112
113
/// Mask for the disallowed general categories of the first character in a label.
114
const MARK_MASK: u32 = general_category_to_mask(GeneralCategory::NonspacingMark)
115
    | general_category_to_mask(GeneralCategory::SpacingMark)
116
    | general_category_to_mask(GeneralCategory::EnclosingMark);
117
118
/// Value for the Joining_Type Unicode property.
119
#[repr(transparent)]
120
#[derive(Clone, Copy)]
121
pub struct JoiningType(icu_properties::props::JoiningType);
122
123
impl JoiningType {
124
    /// Returns the corresponding `JoiningTypeMask`.
125
    #[inline(always)]
126
0
    pub fn to_mask(self) -> JoiningTypeMask {
127
0
        JoiningTypeMask(joining_type_to_mask(self.0))
128
0
    }
129
130
    // `true` iff this value is the Transparent value.
131
    #[inline(always)]
132
0
    pub fn is_transparent(self) -> bool {
133
0
        self.0 == icu_properties::props::JoiningType::Transparent
134
0
    }
135
}
136
137
/// A mask representing potentially multiple `JoiningType`
138
/// values.
139
#[repr(transparent)]
140
#[derive(Clone, Copy)]
141
pub struct JoiningTypeMask(u32);
142
143
impl JoiningTypeMask {
144
    /// `true` iff both masks have at `JoiningType` in common.
145
    #[inline(always)]
146
0
    pub fn intersects(self, other: JoiningTypeMask) -> bool {
147
0
        self.0 & other.0 != 0
148
0
    }
149
}
150
151
/// Value for the Bidi_Class Unicode property.
152
#[repr(transparent)]
153
#[derive(Clone, Copy)]
154
pub struct BidiClass(icu_properties::props::BidiClass);
155
156
impl BidiClass {
157
    /// Returns the corresponding `BidiClassMask`.
158
    #[inline(always)]
159
0
    pub fn to_mask(self) -> BidiClassMask {
160
0
        BidiClassMask(bidi_class_to_mask(self.0))
161
0
    }
162
163
    /// `true` iff this value is Left_To_Right
164
    #[inline(always)]
165
0
    pub fn is_ltr(self) -> bool {
166
0
        self.0 == icu_properties::props::BidiClass::LeftToRight
167
0
    }
168
169
    /// `true` iff this value is Nonspacing_Mark
170
    #[inline(always)]
171
0
    pub fn is_nonspacing_mark(self) -> bool {
172
0
        self.0 == icu_properties::props::BidiClass::NonspacingMark
173
0
    }
174
175
    /// `true` iff this value is European_Number
176
    #[inline(always)]
177
0
    pub fn is_european_number(self) -> bool {
178
0
        self.0 == icu_properties::props::BidiClass::EuropeanNumber
179
0
    }
180
181
    /// `true` iff this value is Arabic_Number
182
    #[inline(always)]
183
0
    pub fn is_arabic_number(self) -> bool {
184
0
        self.0 == icu_properties::props::BidiClass::ArabicNumber
185
0
    }
186
}
187
188
/// A mask representing potentially multiple `BidiClass`
189
/// values.
190
#[repr(transparent)]
191
#[derive(Clone, Copy)]
192
pub struct BidiClassMask(u32);
193
194
impl BidiClassMask {
195
    /// `true` iff both masks have at `BidiClass` in common.
196
    #[inline(always)]
197
0
    pub fn intersects(self, other: BidiClassMask) -> bool {
198
0
        self.0 & other.0 != 0
199
0
    }
200
}
201
202
/// An adapter between a Unicode back end an the `idna` crate.
203
pub struct Adapter {
204
    mapper: Uts46MapperBorrowed<'static>,
205
    general_category: CodePointMapDataBorrowed<'static, GeneralCategory>,
206
    bidi_class: CodePointMapDataBorrowed<'static, icu_properties::props::BidiClass>,
207
    joining_type: CodePointMapDataBorrowed<'static, icu_properties::props::JoiningType>,
208
}
209
210
#[cfg(feature = "compiled_data")]
211
impl Default for Adapter {
212
0
    fn default() -> Self {
213
0
        Self::new()
214
0
    }
215
}
216
217
impl Adapter {
218
    /// Constructor using data compiled into the binary.
219
    #[cfg(feature = "compiled_data")]
220
    #[inline(always)]
221
0
    pub const fn new() -> Self {
222
0
        Self {
223
0
            mapper: Uts46MapperBorrowed::new(),
224
0
            general_category: icu_properties::CodePointMapData::<GeneralCategory>::new(),
225
0
            bidi_class: icu_properties::CodePointMapData::<icu_properties::props::BidiClass>::new(),
226
0
            joining_type:
227
0
                icu_properties::CodePointMapData::<icu_properties::props::JoiningType>::new(),
228
0
        }
229
0
    }
230
231
    /// `true` iff the Canonical_Combining_Class of `c` is Virama.
232
    #[inline(always)]
233
0
    pub fn is_virama(&self, c: char) -> bool {
234
0
        self.mapper.is_virama(c)
235
0
    }
236
237
    /// `true` iff the General_Category of `c` is Mark, i.e. any of Nonspacing_Mark,
238
    /// Spacing_Mark, or Enclosing_Mark.
239
    #[inline(always)]
240
0
    pub fn is_mark(&self, c: char) -> bool {
241
0
        (general_category_to_mask(self.general_category.get(c)) & MARK_MASK) != 0
242
0
    }
243
244
    /// Returns the Bidi_Class of `c`.
245
    #[inline(always)]
246
0
    pub fn bidi_class(&self, c: char) -> BidiClass {
247
0
        BidiClass(self.bidi_class.get(c))
248
0
    }
249
250
    /// Returns the Joining_Type of `c`.
251
    #[inline(always)]
252
0
    pub fn joining_type(&self, c: char) -> JoiningType {
253
0
        JoiningType(self.joining_type.get(c))
254
0
    }
255
256
    /// See the [method of the same name in `icu_normalizer`][1] for the
257
    /// exact semantics.
258
    ///
259
    /// [1]: https://docs.rs/icu_normalizer/latest/icu_normalizer/uts46/struct.Uts46Mapper.html#method.map_normalize
260
    #[inline(always)]
261
0
    pub fn map_normalize<'delegate, I: Iterator<Item = char> + 'delegate>(
262
0
        &'delegate self,
263
0
        iter: I,
264
0
    ) -> impl Iterator<Item = char> + 'delegate {
265
0
        self.mapper.map_normalize(iter)
266
0
    }
Unexecuted instantiation: <idna_adapter::Adapter>::map_normalize::<utf8_iter::Utf8Chars>
Unexecuted instantiation: <idna_adapter::Adapter>::map_normalize::<_>
267
268
    /// See the [method of the same name in `icu_normalizer`][1] for the
269
    /// exact semantics.
270
    ///
271
    /// [1]: https://docs.rs/icu_normalizer/latest/icu_normalizer/uts46/struct.Uts46Mapper.html#method.normalize_validate
272
    #[inline(always)]
273
0
    pub fn normalize_validate<'delegate, I: Iterator<Item = char> + 'delegate>(
274
0
        &'delegate self,
275
0
        iter: I,
276
0
    ) -> impl Iterator<Item = char> + 'delegate {
277
0
        self.mapper.normalize_validate(iter)
278
0
    }
Unexecuted instantiation: <idna_adapter::Adapter>::normalize_validate::<core::iter::adapters::copied::Copied<core::slice::iter::Iter<char>>>
Unexecuted instantiation: <idna_adapter::Adapter>::normalize_validate::<_>
279
}