corvus_json_schema 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Cargo.lock +2 -12
- data/README.md +10 -1
- data/THIRD-PARTY-NOTICES.txt +95 -0
- data/VERSIONHISTORY.md +24 -0
- data/ext/corvus_json_schema/Cargo.toml +2 -2
- data/ext/corvus_json_schema/clippy.toml +3 -4
- data/ext/corvus_json_schema/src/lib.rs +42 -19
- data/ext/corvus_json_schema/vendor/corvus-json-schema/Cargo.toml +9 -4
- data/ext/corvus_json_schema/vendor/corvus-json-schema/README.md +87 -4
- data/ext/corvus_json_schema/vendor/corvus-json-schema/THIRD-PARTY-NOTICES.txt +93 -0
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/compiler.rs +88 -96
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/document.rs +2 -2
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/ecmaregex/charset.rs +271 -0
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/ecmaregex/compile.rs +941 -0
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/ecmaregex/dfa.rs +366 -0
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/ecmaregex/fold.rs +138 -0
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/ecmaregex/mod.rs +329 -0
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/ecmaregex/parse.rs +1128 -0
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/ecmaregex/re2.rs +129 -0
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/ecmaregex/tables_gen.rs +6685 -0
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/ecmaregex/tests.rs +1672 -0
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/ecmaregex/ucd.rs +309 -0
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/ecmaregex/units.rs +165 -0
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/ecmaregex/vm.rs +981 -0
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/eval/plan/fused.rs +13 -9
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/eval/plan.rs +12 -11
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/eval.rs +105 -73
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/formats.rs +95 -1
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/lib.rs +165 -30
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/loader.rs +19 -21
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/numbers.rs +1 -1
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/options.rs +199 -4
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/pattern.rs +758 -79
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/uri.rs +4 -4
- data/lib/corvus_json_schema/version.rb +1 -1
- data/lib/corvus_json_schema.rb +13 -3
- metadata +16 -2
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
//! The Unicode Character Database properties the engine reads, for one fixed version of Unicode (the `ucd` package
|
|
2
|
+
//! of the Go module).
|
|
3
|
+
//!
|
|
4
|
+
//! Nothing in the engine takes Unicode properties from the Rust standard library or from the `regex` crate, because
|
|
5
|
+
//! those follow the toolchain and the version of the dependency. With its own tables the crate gives the same
|
|
6
|
+
//! answers whatever builds it, and the answers change only when the tables are generated again. [`VERSION`] names
|
|
7
|
+
//! the version of Unicode they hold.
|
|
8
|
+
//!
|
|
9
|
+
//! The tables are in `tables_gen.rs`, which `tools/gen-ucd-tables.ps1` writes from the tables of the Go module, so
|
|
10
|
+
//! the ports hold the same data. Each is a sorted list of inclusive ranges, the code points up to U+FFFF as 16-bit
|
|
11
|
+
//! bounds and the rest as 32-bit bounds. A value that follows from other values (a General_Category group such as
|
|
12
|
+
//! L, the Assigned property, the Unknown script) has no table of its own and is built when it is first asked for.
|
|
13
|
+
|
|
14
|
+
use std::sync::LazyLock;
|
|
15
|
+
|
|
16
|
+
use super::Rune;
|
|
17
|
+
use super::tables_gen as tables;
|
|
18
|
+
|
|
19
|
+
#[cfg(test)]
|
|
20
|
+
pub(crate) use super::tables_gen::VERSION;
|
|
21
|
+
|
|
22
|
+
/// The last Unicode code point.
|
|
23
|
+
pub(crate) const MAX_RUNE: Rune = 0x10FFFF;
|
|
24
|
+
|
|
25
|
+
/// An immutable set of code points. `r16` holds the ranges that end at or below U+FFFF and `r32` the ranges that
|
|
26
|
+
/// start above it, each as inclusive pairs in ascending order. No two ranges of one list overlap or touch.
|
|
27
|
+
pub(crate) struct Table {
|
|
28
|
+
pub(super) r16: &'static [u16],
|
|
29
|
+
pub(super) r32: &'static [u32],
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
impl Table {
|
|
33
|
+
/// Whether the table holds the code point.
|
|
34
|
+
pub(crate) fn contains(&self, r: Rune) -> bool {
|
|
35
|
+
if (r as u32) <= 0xFFFF {
|
|
36
|
+
let (ranges, c) = (self.r16, r as u16);
|
|
37
|
+
let (mut lo, mut hi) = (0, ranges.len() / 2);
|
|
38
|
+
while lo < hi {
|
|
39
|
+
let mid = (lo + hi) >> 1;
|
|
40
|
+
if c > ranges[2 * mid + 1] {
|
|
41
|
+
lo = mid + 1;
|
|
42
|
+
} else if c < ranges[2 * mid] {
|
|
43
|
+
hi = mid;
|
|
44
|
+
} else {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
let (ranges, c) = (self.r32, r as u32);
|
|
51
|
+
let (mut lo, mut hi) = (0, ranges.len() / 2);
|
|
52
|
+
while lo < hi {
|
|
53
|
+
let mid = (lo + hi) >> 1;
|
|
54
|
+
if c > ranges[2 * mid + 1] {
|
|
55
|
+
lo = mid + 1;
|
|
56
|
+
} else if c < ranges[2 * mid] {
|
|
57
|
+
hi = mid;
|
|
58
|
+
} else {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
false
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/// Appends the ranges of the table to `dst` as inclusive pairs in ascending order. The pairs neither overlap
|
|
66
|
+
/// nor touch.
|
|
67
|
+
pub(crate) fn append_ranges(&self, dst: &mut Vec<Rune>) {
|
|
68
|
+
dst.reserve(self.r16.len() + self.r32.len());
|
|
69
|
+
dst.extend(self.r16.iter().map(|&c| c as Rune));
|
|
70
|
+
let mut high = self.r32;
|
|
71
|
+
// A range that crosses U+FFFF is stored in two parts.
|
|
72
|
+
if !self.r16.is_empty() && !high.is_empty() && self.r16[self.r16.len() - 1] == 0xFFFF && high[0] == 0x10000 {
|
|
73
|
+
let last = dst.len() - 1;
|
|
74
|
+
dst[last] = high[1] as Rune;
|
|
75
|
+
high = &high[2..];
|
|
76
|
+
}
|
|
77
|
+
dst.extend(high.iter().map(|&c| c as Rune));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/// The ranges of the table as inclusive pairs.
|
|
81
|
+
pub(crate) fn ranges(&self) -> Vec<Rune> {
|
|
82
|
+
let mut pairs = Vec::new();
|
|
83
|
+
self.append_ranges(&mut pairs);
|
|
84
|
+
pairs
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/// A table that is built, not generated: the ranges of a value that follows from other values.
|
|
89
|
+
pub(crate) struct Built(Vec<Rune>);
|
|
90
|
+
|
|
91
|
+
/// The ranges of a property: of a generated table, or of one that was built.
|
|
92
|
+
pub(crate) enum Ranges {
|
|
93
|
+
Table(&'static Table),
|
|
94
|
+
Built(&'static Built),
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
impl Ranges {
|
|
98
|
+
/// The ranges as inclusive pairs in ascending order.
|
|
99
|
+
pub(crate) fn pairs(&self) -> Vec<Rune> {
|
|
100
|
+
match self {
|
|
101
|
+
Ranges::Table(t) => t.ranges(),
|
|
102
|
+
Ranges::Built(b) => b.0.clone(),
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/// The table of the code points that any of the tables holds.
|
|
108
|
+
fn union(tables: &[&Table]) -> Built {
|
|
109
|
+
let mut all = Vec::new();
|
|
110
|
+
for t in tables {
|
|
111
|
+
t.append_ranges(&mut all);
|
|
112
|
+
}
|
|
113
|
+
let mut order: Vec<usize> = (0..all.len() / 2).collect();
|
|
114
|
+
order.sort_by_key(|&i| all[2 * i]);
|
|
115
|
+
let mut merged: Vec<Rune> = Vec::with_capacity(all.len());
|
|
116
|
+
for i in order {
|
|
117
|
+
let (lo, hi) = (all[2 * i], all[2 * i + 1]);
|
|
118
|
+
if let Some(last) = merged.last_mut()
|
|
119
|
+
&& lo <= *last + 1
|
|
120
|
+
{
|
|
121
|
+
if hi > *last {
|
|
122
|
+
*last = hi;
|
|
123
|
+
}
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
merged.push(lo);
|
|
127
|
+
merged.push(hi);
|
|
128
|
+
}
|
|
129
|
+
Built(merged)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/// The table of the code points that the table does not hold.
|
|
133
|
+
fn complement(t: &Table) -> Built {
|
|
134
|
+
let pairs = t.ranges();
|
|
135
|
+
let mut inverse = Vec::with_capacity(pairs.len() + 2);
|
|
136
|
+
let mut next: Rune = 0;
|
|
137
|
+
for &[lo, hi] in pairs.as_chunks::<2>().0 {
|
|
138
|
+
if lo > next {
|
|
139
|
+
inverse.push(next);
|
|
140
|
+
inverse.push(lo - 1);
|
|
141
|
+
}
|
|
142
|
+
next = hi + 1;
|
|
143
|
+
}
|
|
144
|
+
if next <= MAX_RUNE {
|
|
145
|
+
inverse.push(next);
|
|
146
|
+
inverse.push(MAX_RUNE);
|
|
147
|
+
}
|
|
148
|
+
Built(inverse)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// The General_Category values that are groups of other values, the Assigned property and the Unknown script. Each
|
|
152
|
+
// is built on first use and kept. The generator of the Go tables checks each definition against their source.
|
|
153
|
+
static LETTER: LazyLock<Built> =
|
|
154
|
+
LazyLock::new(|| union(&[&tables::GC_LU, &tables::GC_LL, &tables::GC_LT, &tables::GC_LM, &tables::GC_LO]));
|
|
155
|
+
static CASED_LETTER: LazyLock<Built> = LazyLock::new(|| union(&[&tables::GC_LU, &tables::GC_LL, &tables::GC_LT]));
|
|
156
|
+
static MARK: LazyLock<Built> = LazyLock::new(|| union(&[&tables::GC_MN, &tables::GC_MC, &tables::GC_ME]));
|
|
157
|
+
static NUMBER: LazyLock<Built> = LazyLock::new(|| union(&[&tables::GC_ND, &tables::GC_NL, &tables::GC_NO]));
|
|
158
|
+
static PUNCTUATION: LazyLock<Built> = LazyLock::new(|| {
|
|
159
|
+
union(&[
|
|
160
|
+
&tables::GC_PC,
|
|
161
|
+
&tables::GC_PD,
|
|
162
|
+
&tables::GC_PS,
|
|
163
|
+
&tables::GC_PE,
|
|
164
|
+
&tables::GC_PI,
|
|
165
|
+
&tables::GC_PF,
|
|
166
|
+
&tables::GC_PO,
|
|
167
|
+
])
|
|
168
|
+
});
|
|
169
|
+
static SYMBOL: LazyLock<Built> =
|
|
170
|
+
LazyLock::new(|| union(&[&tables::GC_SM, &tables::GC_SC, &tables::GC_SK, &tables::GC_SO]));
|
|
171
|
+
static SEPARATOR: LazyLock<Built> = LazyLock::new(|| union(&[&tables::GC_ZS, &tables::GC_ZL, &tables::GC_ZP]));
|
|
172
|
+
static OTHER: LazyLock<Built> =
|
|
173
|
+
LazyLock::new(|| union(&[&tables::GC_CC, &tables::GC_CF, &tables::GC_CS, &tables::GC_CO, &tables::GC_CN]));
|
|
174
|
+
/// The code points that have a General_Category other than Cn.
|
|
175
|
+
static ASSIGNED: LazyLock<Built> = LazyLock::new(|| complement(&tables::GC_CN));
|
|
176
|
+
/// The code points that belong to no script. They are the unassigned, private use and surrogate code points.
|
|
177
|
+
static UNKNOWN_SCRIPT: LazyLock<Built> = LazyLock::new(|| union(&[&tables::GC_CN, &tables::GC_CO, &tables::GC_CS]));
|
|
178
|
+
|
|
179
|
+
/// The table of the Script value Katakana_Or_Hiragana (Hrkt). PropertyValueAliases.txt lists the value, and no code
|
|
180
|
+
/// point has it, in Script or in Script_Extensions. Scripts.txt has no line for it, so the generated tables do not
|
|
181
|
+
/// have it.
|
|
182
|
+
static KATAKANA_OR_HIRAGANA: Table = Table { r16: &[], r32: &[] };
|
|
183
|
+
|
|
184
|
+
/// The table of a General_Category value by its short name, such as "Lu" or "L". `None` for any other name.
|
|
185
|
+
pub(crate) fn category(name: &str) -> Option<Ranges> {
|
|
186
|
+
let built = match name {
|
|
187
|
+
"L" => &LETTER,
|
|
188
|
+
"LC" => &CASED_LETTER,
|
|
189
|
+
"M" => &MARK,
|
|
190
|
+
"N" => &NUMBER,
|
|
191
|
+
"P" => &PUNCTUATION,
|
|
192
|
+
"S" => &SYMBOL,
|
|
193
|
+
"Z" => &SEPARATOR,
|
|
194
|
+
"C" => &OTHER,
|
|
195
|
+
_ => return tables::category_table(name).map(Ranges::Table),
|
|
196
|
+
};
|
|
197
|
+
Some(Ranges::Built(built))
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/// The table of a binary property by its canonical name, such as "Alphabetic" or "White_Space". `None` for any
|
|
201
|
+
/// other name. ASCII and Any, which ECMA-262 adds to the properties of Unicode, are not here.
|
|
202
|
+
pub(crate) fn binary(name: &str) -> Option<Ranges> {
|
|
203
|
+
if name == "Assigned" {
|
|
204
|
+
return Some(Ranges::Built(&ASSIGNED));
|
|
205
|
+
}
|
|
206
|
+
tables::binary_table(name).map(Ranges::Table)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/// The generated table of a binary property, for the callers that test one code point.
|
|
210
|
+
pub(crate) fn binary_table(name: &str) -> Option<&'static Table> {
|
|
211
|
+
tables::binary_table(name)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/// The table of a Script value by its long name or an alias, such as "Greek" or "Grek". `None` for any other name.
|
|
215
|
+
pub(crate) fn script(name: &str) -> Option<Ranges> {
|
|
216
|
+
match name {
|
|
217
|
+
"Unknown" | "Zzzz" => Some(Ranges::Built(&UNKNOWN_SCRIPT)),
|
|
218
|
+
"Katakana_Or_Hiragana" | "Hrkt" => Some(Ranges::Table(&KATAKANA_OR_HIRAGANA)),
|
|
219
|
+
_ => tables::script_table(name).map(Ranges::Table),
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/// The table of a Script_Extensions value by the long name of the script or an alias. `None` for any other name.
|
|
224
|
+
pub(crate) fn script_extensions(name: &str) -> Option<Ranges> {
|
|
225
|
+
match name {
|
|
226
|
+
"Unknown" | "Zzzz" => Some(Ranges::Built(&UNKNOWN_SCRIPT)),
|
|
227
|
+
"Katakana_Or_Hiragana" | "Hrkt" => Some(Ranges::Table(&KATAKANA_OR_HIRAGANA)),
|
|
228
|
+
_ => tables::script_extensions_table(name).map(Ranges::Table),
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/// The names of every script. Each element is the long name of one script followed by its aliases.
|
|
233
|
+
#[cfg(test)]
|
|
234
|
+
pub(crate) fn script_names() -> &'static [&'static [&'static str]] {
|
|
235
|
+
tables::SCRIPT_NAMES
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/// The canonical name of every binary property that has a table, which is every name [`binary`] knows but Assigned.
|
|
239
|
+
#[cfg(test)]
|
|
240
|
+
pub(crate) fn binary_names() -> &'static [&'static str] {
|
|
241
|
+
tables::BINARY_NAMES
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/// Maps some of the code points `first`, `first + 1`, ... `first + length - 1` to themselves plus `delta`. The ones
|
|
245
|
+
/// it maps are those whose offset from `first` has none of the bits of `mask`, so a mask of 1 takes every other code
|
|
246
|
+
/// point.
|
|
247
|
+
pub(crate) struct CaseRange {
|
|
248
|
+
pub(super) first: Rune,
|
|
249
|
+
pub(super) delta: i32,
|
|
250
|
+
pub(super) length: u16,
|
|
251
|
+
pub(super) mask: u16,
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
fn map_case(table: &[CaseRange], r: Rune) -> Rune {
|
|
255
|
+
let (mut lo, mut hi) = (0, table.len());
|
|
256
|
+
while lo < hi {
|
|
257
|
+
let mid = (lo + hi) >> 1;
|
|
258
|
+
let row = &table[mid];
|
|
259
|
+
if r < row.first {
|
|
260
|
+
hi = mid;
|
|
261
|
+
} else {
|
|
262
|
+
let offset = r - row.first;
|
|
263
|
+
if offset >= row.length as Rune {
|
|
264
|
+
lo = mid + 1;
|
|
265
|
+
} else if offset & row.mask as Rune == 0 {
|
|
266
|
+
return r + row.delta;
|
|
267
|
+
} else {
|
|
268
|
+
return r;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
r
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/// The simple case folding of a code point (the C and S rows of CaseFolding.txt), which is the code point itself
|
|
276
|
+
/// when it has none. Two code points are equal ignoring case when `fold` gives the same result for both.
|
|
277
|
+
pub(crate) fn fold(r: Rune) -> Rune {
|
|
278
|
+
if r < 0x80 {
|
|
279
|
+
if (b'A' as Rune..=b'Z' as Rune).contains(&r) {
|
|
280
|
+
return r + (b'a' - b'A') as Rune;
|
|
281
|
+
}
|
|
282
|
+
return r;
|
|
283
|
+
}
|
|
284
|
+
map_case(tables::CASE_FOLDS, r)
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/// The simple uppercase mapping of a code point, which is the code point itself when it has none.
|
|
288
|
+
pub(crate) fn to_upper(r: Rune) -> Rune {
|
|
289
|
+
if r < 0x80 {
|
|
290
|
+
if (b'a' as Rune..=b'z' as Rune).contains(&r) {
|
|
291
|
+
return r - (b'a' - b'A') as Rune;
|
|
292
|
+
}
|
|
293
|
+
return r;
|
|
294
|
+
}
|
|
295
|
+
map_case(tables::UPPER_CASES, r)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/// Every code point that [`fold`] changes, in ascending order.
|
|
299
|
+
pub(crate) fn folding() -> Vec<Rune> {
|
|
300
|
+
let mut dst = Vec::new();
|
|
301
|
+
for row in tables::CASE_FOLDS {
|
|
302
|
+
for offset in 0..row.length as Rune {
|
|
303
|
+
if offset & row.mask as Rune == 0 && row.delta != 0 {
|
|
304
|
+
dst.push(row.first + offset);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
dst
|
|
309
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
//! Reading UTF-8, and matching by UTF-16 code unit over UTF-8 text (`units.go`, and what the Go source takes from
|
|
2
|
+
//! the `unicode/utf8` package).
|
|
3
|
+
//!
|
|
4
|
+
//! ECMA-262 matches a pattern that has no u flag a code unit at a time. The engine reads a pattern without the u
|
|
5
|
+
//! flag only when the u flag grammar refuses it, and such a pattern is matched that way. A character of one, two or
|
|
6
|
+
//! three bytes of UTF-8 is one code unit. A character of four bytes is two, a high surrogate and a low one, so the
|
|
7
|
+
//! matcher has to be able to stand between them. That position is written as the offset of the character's third
|
|
8
|
+
//! byte. Each half then spans two bytes, every position is still an offset into the text, a group is still a pair
|
|
9
|
+
//! of offsets, and no UTF-16 copy of the text is made.
|
|
10
|
+
//!
|
|
11
|
+
//! The third byte of a character is a continuation byte, which is no position at all when matching by code point,
|
|
12
|
+
//! so the two readings cannot be confused. Only a text with a character of four bytes differs between the two, and
|
|
13
|
+
//! the instructions that compare bytes (a literal run, a word boundary, a line terminator) need no change: none of
|
|
14
|
+
//! them can hold at the position between the halves, and all of them are right at every other.
|
|
15
|
+
|
|
16
|
+
use super::Rune;
|
|
17
|
+
|
|
18
|
+
/// What a byte that is not UTF-8 decodes to, one byte at a time.
|
|
19
|
+
pub(crate) const RUNE_ERROR: Rune = 0xFFFD;
|
|
20
|
+
/// The first byte value that is not a character by itself.
|
|
21
|
+
pub(crate) const RUNE_SELF: u8 = 0x80;
|
|
22
|
+
|
|
23
|
+
#[inline(always)]
|
|
24
|
+
fn continuation(b: u8) -> bool {
|
|
25
|
+
b & 0xC0 == 0x80
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/// The code point at the start of `p` and its width in bytes: `(RUNE_ERROR, 1)` for bytes that are not UTF-8, and
|
|
29
|
+
/// `(RUNE_ERROR, 0)` for no bytes. (`utf8.DecodeRune`.)
|
|
30
|
+
#[inline]
|
|
31
|
+
pub(crate) fn decode_rune(p: &[u8]) -> (Rune, usize) {
|
|
32
|
+
let Some(&p0) = p.first() else { return (RUNE_ERROR, 0) };
|
|
33
|
+
if p0 < RUNE_SELF {
|
|
34
|
+
return (p0 as Rune, 1);
|
|
35
|
+
}
|
|
36
|
+
match p0 {
|
|
37
|
+
0xC2..=0xDF if p.len() >= 2 && continuation(p[1]) => {
|
|
38
|
+
return (((p0 & 0x1F) as Rune) << 6 | (p[1] & 0x3F) as Rune, 2);
|
|
39
|
+
}
|
|
40
|
+
0xE0..=0xEF if p.len() >= 3 && continuation(p[2]) => {
|
|
41
|
+
let (lo, hi) = match p0 {
|
|
42
|
+
0xE0 => (0xA0, 0xBF),
|
|
43
|
+
0xED => (0x80, 0x9F),
|
|
44
|
+
_ => (0x80, 0xBF),
|
|
45
|
+
};
|
|
46
|
+
if p[1] >= lo && p[1] <= hi {
|
|
47
|
+
return (((p0 & 0x0F) as Rune) << 12 | ((p[1] & 0x3F) as Rune) << 6 | (p[2] & 0x3F) as Rune, 3);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
0xF0..=0xF4 if p.len() >= 4 && continuation(p[2]) && continuation(p[3]) => {
|
|
51
|
+
let (lo, hi) = match p0 {
|
|
52
|
+
0xF0 => (0x90, 0xBF),
|
|
53
|
+
0xF4 => (0x80, 0x8F),
|
|
54
|
+
_ => (0x80, 0xBF),
|
|
55
|
+
};
|
|
56
|
+
if p[1] >= lo && p[1] <= hi {
|
|
57
|
+
return (
|
|
58
|
+
((p0 & 0x07) as Rune) << 18
|
|
59
|
+
| ((p[1] & 0x3F) as Rune) << 12
|
|
60
|
+
| ((p[2] & 0x3F) as Rune) << 6
|
|
61
|
+
| (p[3] & 0x3F) as Rune,
|
|
62
|
+
4,
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
_ => {}
|
|
67
|
+
}
|
|
68
|
+
(RUNE_ERROR, 1)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/// The code point at the end of `p` and its width in bytes. (`utf8.DecodeLastRune`.)
|
|
72
|
+
#[inline]
|
|
73
|
+
pub(crate) fn decode_last_rune(p: &[u8]) -> (Rune, usize) {
|
|
74
|
+
let end = p.len();
|
|
75
|
+
if end == 0 {
|
|
76
|
+
return (RUNE_ERROR, 0);
|
|
77
|
+
}
|
|
78
|
+
let last = p[end - 1];
|
|
79
|
+
if last < RUNE_SELF {
|
|
80
|
+
return (last as Rune, 1);
|
|
81
|
+
}
|
|
82
|
+
// A character is four bytes at most, so its first byte is one of the last four.
|
|
83
|
+
let lim = end.saturating_sub(4);
|
|
84
|
+
let mut start = end - 1;
|
|
85
|
+
while start > lim {
|
|
86
|
+
start -= 1;
|
|
87
|
+
if !continuation(p[start]) {
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
let (r, size) = decode_rune(&p[start..end]);
|
|
92
|
+
if start + size != end {
|
|
93
|
+
return (RUNE_ERROR, 1);
|
|
94
|
+
}
|
|
95
|
+
(r, size)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/// The two UTF-16 code units of a code point beyond the Basic Multilingual Plane.
|
|
99
|
+
#[inline]
|
|
100
|
+
pub(crate) fn high_surrogate(c: Rune) -> Rune {
|
|
101
|
+
0xD800 + ((c - 0x10000) >> 10)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
#[inline]
|
|
105
|
+
pub(crate) fn low_surrogate(c: Rune) -> Rune {
|
|
106
|
+
0xDC00 + ((c - 0x10000) & 0x3FF)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/// Whether the text has a character beyond the Basic Multilingual Plane, which is the only kind of text that code
|
|
110
|
+
/// units and code points read differently. Such a character starts with a byte of 0xF0 or more.
|
|
111
|
+
#[inline]
|
|
112
|
+
pub(crate) fn has_supplementary(input: &[u8]) -> bool {
|
|
113
|
+
input.iter().any(|&c| c >= 0xF0)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/// The code unit at the position and the number of bytes it spans.
|
|
117
|
+
#[inline]
|
|
118
|
+
pub(crate) fn unit_at(input: &[u8], pos: usize) -> (Rune, usize) {
|
|
119
|
+
let c = input[pos];
|
|
120
|
+
if c >= 0xF0 {
|
|
121
|
+
let (r, w) = decode_rune(&input[pos..]);
|
|
122
|
+
if w == 4 {
|
|
123
|
+
return (high_surrogate(r), 2);
|
|
124
|
+
}
|
|
125
|
+
return (RUNE_ERROR, 1);
|
|
126
|
+
}
|
|
127
|
+
if (0x80..0xC0).contains(&c) && pos >= 2 && input[pos - 2] >= 0xF0 {
|
|
128
|
+
// Between the halves of the character that starts two bytes back.
|
|
129
|
+
let (r, w) = decode_rune(&input[pos - 2..]);
|
|
130
|
+
if w == 4 {
|
|
131
|
+
return (low_surrogate(r), 2);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
decode_rune(&input[pos..])
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/// The code unit that ends at the position and the number of bytes it spans.
|
|
138
|
+
#[inline]
|
|
139
|
+
pub(crate) fn unit_before(input: &[u8], pos: usize) -> (Rune, usize) {
|
|
140
|
+
let (r, w) = decode_last_rune(&input[..pos]);
|
|
141
|
+
if w == 4 {
|
|
142
|
+
return (low_surrogate(r), 2);
|
|
143
|
+
}
|
|
144
|
+
if w == 1 && r == RUNE_ERROR && pos >= 2 && input.len() - pos >= 2 && input[pos - 2] >= 0xF0 {
|
|
145
|
+
// Between the halves of the character that starts two bytes back.
|
|
146
|
+
let (r, w) = decode_rune(&input[pos - 2..]);
|
|
147
|
+
if w == 4 {
|
|
148
|
+
return (high_surrogate(r), 2);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
(r, w)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/// The character at the position and its width in bytes: a code unit with `units` set, and a code point otherwise.
|
|
155
|
+
/// It is for the places that are not hot. The matcher's own instructions make the choice themselves.
|
|
156
|
+
#[inline]
|
|
157
|
+
pub(crate) fn decode(input: &[u8], pos: usize, units: bool) -> (Rune, usize) {
|
|
158
|
+
if units { unit_at(input, pos) } else { decode_rune(&input[pos..]) }
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/// [`decode`] for the character that ends at the position.
|
|
162
|
+
#[inline]
|
|
163
|
+
pub(crate) fn decode_last(input: &[u8], pos: usize, units: bool) -> (Rune, usize) {
|
|
164
|
+
if units { unit_before(input, pos) } else { decode_last_rune(&input[..pos]) }
|
|
165
|
+
}
|