1 /*!
2 Converts ranges of Unicode scalar values to equivalent ranges of UTF-8 bytes.
3
4 This is sub-module is useful for constructing byte based automatons that need
5 to embed UTF-8 decoding. The most common use of this module is in conjunction
6 with the [`hir::ClassUnicodeRange`](../hir/struct.ClassUnicodeRange.html) type.
7
8 See the documentation on the `Utf8Sequences` iterator for more details and
9 an example.
10
11 # Wait, what is this?
12
13 This is simplest to explain with an example. Let's say you wanted to test
14 whether a particular byte sequence was a Cyrillic character. One possible
15 scalar value range is `[0400-04FF]`. The set of allowed bytes for this
16 range can be expressed as a sequence of byte ranges:
17
18 ```text
19 [D0-D3][80-BF]
20 ```
21
22 This is simple enough: simply encode the boundaries, `0400` encodes to
23 `D0 80` and `04FF` encodes to `D3 BF`, and create ranges from each
24 corresponding pair of bytes: `D0` to `D3` and `80` to `BF`.
25
26 However, what if you wanted to add the Cyrillic Supplementary characters to
27 your range? Your range might then become `[0400-052F]`. The same procedure
28 as above doesn't quite work because `052F` encodes to `D4 AF`. The byte ranges
29 you'd get from the previous transformation would be `[D0-D4][80-AF]`. However,
30 this isn't quite correct because this range doesn't capture many characters,
31 for example, `04FF` (because its last byte, `BF` isn't in the range `80-AF`).
32
33 Instead, you need multiple sequences of byte ranges:
34
35 ```text
36 [D0-D3][80-BF] # matches codepoints 0400-04FF
37 [D4][80-AF] # matches codepoints 0500-052F
38 ```
39
40 This gets even more complicated if you want bigger ranges, particularly if
41 they naively contain surrogate codepoints. For example, the sequence of byte
42 ranges for the basic multilingual plane (`[0000-FFFF]`) look like this:
43
44 ```text
45 [0-7F]
46 [C2-DF][80-BF]
47 [E0][A0-BF][80-BF]
48 [E1-EC][80-BF][80-BF]
49 [ED][80-9F][80-BF]
50 [EE-EF][80-BF][80-BF]
51 ```
52
53 Note that the byte ranges above will *not* match any erroneous encoding of
54 UTF-8, including encodings of surrogate codepoints.
55
56 And, of course, for all of Unicode (`[000000-10FFFF]`):
57
58 ```text
59 [0-7F]
60 [C2-DF][80-BF]
61 [E0][A0-BF][80-BF]
62 [E1-EC][80-BF][80-BF]
63 [ED][80-9F][80-BF]
64 [EE-EF][80-BF][80-BF]
65 [F0][90-BF][80-BF][80-BF]
66 [F1-F3][80-BF][80-BF][80-BF]
67 [F4][80-8F][80-BF][80-BF]
68 ```
69
70 This module automates the process of creating these byte ranges from ranges of
71 Unicode scalar values.
72
73 # Lineage
74
75 I got the idea and general implementation strategy from Russ Cox in his
76 [article on regexps](https://web.archive.org/web/20160404141123/https://swtch.com/~rsc/regexp/regexp3.html) and RE2.
77 Russ Cox got it from Ken Thompson's `grep` (no source, folk lore?).
78 I also got the idea from
79 [Lucene](https://github.com/apache/lucene-solr/blob/ae93f4e7ac6a3908046391de35d4f50a0d3c59ca/lucene/core/src/java/org/apache/lucene/util/automaton/UTF32ToUTF8.java),
80 which uses it for executing automata on their term index.
81 */
82
83 #![deny(missing_docs)]
84
85 use std::char;
86 use std::fmt;
87 use std::iter::FusedIterator;
88 use std::slice;
89
90 const MAX_UTF8_BYTES: usize = 4;
91
92 /// Utf8Sequence represents a sequence of byte ranges.
93 ///
94 /// To match a Utf8Sequence, a candidate byte sequence must match each
95 /// successive range.
96 ///
97 /// For example, if there are two ranges, `[C2-DF][80-BF]`, then the byte
98 /// sequence `\xDD\x61` would not match because `0x61 < 0x80`.
99 #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
100 pub enum Utf8Sequence {
101 /// One byte range.
102 One(Utf8Range),
103 /// Two successive byte ranges.
104 Two([Utf8Range; 2]),
105 /// Three successive byte ranges.
106 Three([Utf8Range; 3]),
107 /// Four successive byte ranges.
108 Four([Utf8Range; 4]),
109 }
110
111 impl Utf8Sequence {
112 /// Creates a new UTF-8 sequence from the encoded bytes of a scalar value
113 /// range.
114 ///
115 /// This assumes that `start` and `end` have the same length.
from_encoded_range(start: &[u8], end: &[u8]) -> Self116 fn from_encoded_range(start: &[u8], end: &[u8]) -> Self {
117 assert_eq!(start.len(), end.len());
118 match start.len() {
119 2 => Utf8Sequence::Two([
120 Utf8Range::new(start[0], end[0]),
121 Utf8Range::new(start[1], end[1]),
122 ]),
123 3 => Utf8Sequence::Three([
124 Utf8Range::new(start[0], end[0]),
125 Utf8Range::new(start[1], end[1]),
126 Utf8Range::new(start[2], end[2]),
127 ]),
128 4 => Utf8Sequence::Four([
129 Utf8Range::new(start[0], end[0]),
130 Utf8Range::new(start[1], end[1]),
131 Utf8Range::new(start[2], end[2]),
132 Utf8Range::new(start[3], end[3]),
133 ]),
134 n => unreachable!("invalid encoded length: {}", n),
135 }
136 }
137
138 /// Returns the underlying sequence of byte ranges as a slice.
as_slice(&self) -> &[Utf8Range]139 pub fn as_slice(&self) -> &[Utf8Range] {
140 use self::Utf8Sequence::*;
141 match *self {
142 One(ref r) => slice::from_ref(r),
143 Two(ref r) => &r[..],
144 Three(ref r) => &r[..],
145 Four(ref r) => &r[..],
146 }
147 }
148
149 /// Returns the number of byte ranges in this sequence.
150 ///
151 /// The length is guaranteed to be in the closed interval `[1, 4]`.
len(&self) -> usize152 pub fn len(&self) -> usize {
153 self.as_slice().len()
154 }
155
156 /// Reverses the ranges in this sequence.
157 ///
158 /// For example, if this corresponds to the following sequence:
159 ///
160 /// ```text
161 /// [D0-D3][80-BF]
162 /// ```
163 ///
164 /// Then after reversal, it will be
165 ///
166 /// ```text
167 /// [80-BF][D0-D3]
168 /// ```
169 ///
170 /// This is useful when one is constructing a UTF-8 automaton to match
171 /// character classes in reverse.
reverse(&mut self)172 pub fn reverse(&mut self) {
173 match *self {
174 Utf8Sequence::One(_) => {}
175 Utf8Sequence::Two(ref mut x) => x.reverse(),
176 Utf8Sequence::Three(ref mut x) => x.reverse(),
177 Utf8Sequence::Four(ref mut x) => x.reverse(),
178 }
179 }
180
181 /// Returns true if and only if a prefix of `bytes` matches this sequence
182 /// of byte ranges.
matches(&self, bytes: &[u8]) -> bool183 pub fn matches(&self, bytes: &[u8]) -> bool {
184 if bytes.len() < self.len() {
185 return false;
186 }
187 for (&b, r) in bytes.iter().zip(self) {
188 if !r.matches(b) {
189 return false;
190 }
191 }
192 true
193 }
194 }
195
196 impl<'a> IntoIterator for &'a Utf8Sequence {
197 type IntoIter = slice::Iter<'a, Utf8Range>;
198 type Item = &'a Utf8Range;
199
into_iter(self) -> Self::IntoIter200 fn into_iter(self) -> Self::IntoIter {
201 self.as_slice().into_iter()
202 }
203 }
204
205 impl fmt::Debug for Utf8Sequence {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result206 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
207 use self::Utf8Sequence::*;
208 match *self {
209 One(ref r) => write!(f, "{:?}", r),
210 Two(ref r) => write!(f, "{:?}{:?}", r[0], r[1]),
211 Three(ref r) => write!(f, "{:?}{:?}{:?}", r[0], r[1], r[2]),
212 Four(ref r) => {
213 write!(f, "{:?}{:?}{:?}{:?}", r[0], r[1], r[2], r[3])
214 }
215 }
216 }
217 }
218
219 /// A single inclusive range of UTF-8 bytes.
220 #[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord)]
221 pub struct Utf8Range {
222 /// Start of byte range (inclusive).
223 pub start: u8,
224 /// End of byte range (inclusive).
225 pub end: u8,
226 }
227
228 impl Utf8Range {
new(start: u8, end: u8) -> Self229 fn new(start: u8, end: u8) -> Self {
230 Utf8Range { start, end }
231 }
232
233 /// Returns true if and only if the given byte is in this range.
matches(&self, b: u8) -> bool234 pub fn matches(&self, b: u8) -> bool {
235 self.start <= b && b <= self.end
236 }
237 }
238
239 impl fmt::Debug for Utf8Range {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result240 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
241 if self.start == self.end {
242 write!(f, "[{:X}]", self.start)
243 } else {
244 write!(f, "[{:X}-{:X}]", self.start, self.end)
245 }
246 }
247 }
248
249 /// An iterator over ranges of matching UTF-8 byte sequences.
250 ///
251 /// The iteration represents an alternation of comprehensive byte sequences
252 /// that match precisely the set of UTF-8 encoded scalar values.
253 ///
254 /// A byte sequence corresponds to one of the scalar values in the range given
255 /// if and only if it completely matches exactly one of the sequences of byte
256 /// ranges produced by this iterator.
257 ///
258 /// Each sequence of byte ranges matches a unique set of bytes. That is, no two
259 /// sequences will match the same bytes.
260 ///
261 /// # Example
262 ///
263 /// This shows how to match an arbitrary byte sequence against a range of
264 /// scalar values.
265 ///
266 /// ```rust
267 /// use regex_syntax::utf8::{Utf8Sequences, Utf8Sequence};
268 ///
269 /// fn matches(seqs: &[Utf8Sequence], bytes: &[u8]) -> bool {
270 /// for range in seqs {
271 /// if range.matches(bytes) {
272 /// return true;
273 /// }
274 /// }
275 /// false
276 /// }
277 ///
278 /// // Test the basic multilingual plane.
279 /// let seqs: Vec<_> = Utf8Sequences::new('\u{0}', '\u{FFFF}').collect();
280 ///
281 /// // UTF-8 encoding of 'a'.
282 /// assert!(matches(&seqs, &[0x61]));
283 /// // UTF-8 encoding of '☃' (`\u{2603}`).
284 /// assert!(matches(&seqs, &[0xE2, 0x98, 0x83]));
285 /// // UTF-8 encoding of `\u{10348}` (outside the BMP).
286 /// assert!(!matches(&seqs, &[0xF0, 0x90, 0x8D, 0x88]));
287 /// // Tries to match against a UTF-8 encoding of a surrogate codepoint,
288 /// // which is invalid UTF-8, and therefore fails, despite the fact that
289 /// // the corresponding codepoint (0xD800) falls in the range given.
290 /// assert!(!matches(&seqs, &[0xED, 0xA0, 0x80]));
291 /// // And fails against plain old invalid UTF-8.
292 /// assert!(!matches(&seqs, &[0xFF, 0xFF]));
293 /// ```
294 ///
295 /// If this example seems circuitous, that's because it is! It's meant to be
296 /// illustrative. In practice, you could just try to decode your byte sequence
297 /// and compare it with the scalar value range directly. However, this is not
298 /// always possible (for example, in a byte based automaton).
299 #[derive(Debug)]
300 pub struct Utf8Sequences {
301 range_stack: Vec<ScalarRange>,
302 }
303
304 impl Utf8Sequences {
305 /// Create a new iterator over UTF-8 byte ranges for the scalar value range
306 /// given.
new(start: char, end: char) -> Self307 pub fn new(start: char, end: char) -> Self {
308 let mut it = Utf8Sequences { range_stack: vec![] };
309 it.push(start as u32, end as u32);
310 it
311 }
312
313 /// reset resets the scalar value range.
314 /// Any existing state is cleared, but resources may be reused.
315 ///
316 /// N.B. Benchmarks say that this method is dubious.
317 #[doc(hidden)]
reset(&mut self, start: char, end: char)318 pub fn reset(&mut self, start: char, end: char) {
319 self.range_stack.clear();
320 self.push(start as u32, end as u32);
321 }
322
push(&mut self, start: u32, end: u32)323 fn push(&mut self, start: u32, end: u32) {
324 self.range_stack.push(ScalarRange { start, end });
325 }
326 }
327
328 struct ScalarRange {
329 start: u32,
330 end: u32,
331 }
332
333 impl fmt::Debug for ScalarRange {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result334 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
335 write!(f, "ScalarRange({:X}, {:X})", self.start, self.end)
336 }
337 }
338
339 impl Iterator for Utf8Sequences {
340 type Item = Utf8Sequence;
341
next(&mut self) -> Option<Self::Item>342 fn next(&mut self) -> Option<Self::Item> {
343 'TOP: while let Some(mut r) = self.range_stack.pop() {
344 'INNER: loop {
345 if let Some((r1, r2)) = r.split() {
346 self.push(r2.start, r2.end);
347 r.start = r1.start;
348 r.end = r1.end;
349 continue 'INNER;
350 }
351 if !r.is_valid() {
352 continue 'TOP;
353 }
354 for i in 1..MAX_UTF8_BYTES {
355 let max = max_scalar_value(i);
356 if r.start <= max && max < r.end {
357 self.push(max + 1, r.end);
358 r.end = max;
359 continue 'INNER;
360 }
361 }
362 if let Some(ascii_range) = r.as_ascii() {
363 return Some(Utf8Sequence::One(ascii_range));
364 }
365 for i in 1..MAX_UTF8_BYTES {
366 let m = (1 << (6 * i)) - 1;
367 if (r.start & !m) != (r.end & !m) {
368 if (r.start & m) != 0 {
369 self.push((r.start | m) + 1, r.end);
370 r.end = r.start | m;
371 continue 'INNER;
372 }
373 if (r.end & m) != m {
374 self.push(r.end & !m, r.end);
375 r.end = (r.end & !m) - 1;
376 continue 'INNER;
377 }
378 }
379 }
380 let mut start = [0; MAX_UTF8_BYTES];
381 let mut end = [0; MAX_UTF8_BYTES];
382 let n = r.encode(&mut start, &mut end);
383 return Some(Utf8Sequence::from_encoded_range(
384 &start[0..n],
385 &end[0..n],
386 ));
387 }
388 }
389 None
390 }
391 }
392
393 impl FusedIterator for Utf8Sequences {}
394
395 impl ScalarRange {
396 /// split splits this range if it overlaps with a surrogate codepoint.
397 ///
398 /// Either or both ranges may be invalid.
split(&self) -> Option<(ScalarRange, ScalarRange)>399 fn split(&self) -> Option<(ScalarRange, ScalarRange)> {
400 if self.start < 0xE000 && self.end > 0xD7FF {
401 Some((
402 ScalarRange { start: self.start, end: 0xD7FF },
403 ScalarRange { start: 0xE000, end: self.end },
404 ))
405 } else {
406 None
407 }
408 }
409
410 /// is_valid returns true if and only if start <= end.
is_valid(&self) -> bool411 fn is_valid(&self) -> bool {
412 self.start <= self.end
413 }
414
415 /// as_ascii returns this range as a Utf8Range if and only if all scalar
416 /// values in this range can be encoded as a single byte.
as_ascii(&self) -> Option<Utf8Range>417 fn as_ascii(&self) -> Option<Utf8Range> {
418 if self.is_ascii() {
419 Some(Utf8Range::new(self.start as u8, self.end as u8))
420 } else {
421 None
422 }
423 }
424
425 /// is_ascii returns true if the range is ASCII only (i.e., takes a single
426 /// byte to encode any scalar value).
is_ascii(&self) -> bool427 fn is_ascii(&self) -> bool {
428 self.is_valid() && self.end <= 0x7f
429 }
430
431 /// encode writes the UTF-8 encoding of the start and end of this range
432 /// to the corresponding destination slices, and returns the number of
433 /// bytes written.
434 ///
435 /// The slices should have room for at least `MAX_UTF8_BYTES`.
encode(&self, start: &mut [u8], end: &mut [u8]) -> usize436 fn encode(&self, start: &mut [u8], end: &mut [u8]) -> usize {
437 let cs = char::from_u32(self.start).unwrap();
438 let ce = char::from_u32(self.end).unwrap();
439 let ss = cs.encode_utf8(start);
440 let se = ce.encode_utf8(end);
441 assert_eq!(ss.len(), se.len());
442 ss.len()
443 }
444 }
445
max_scalar_value(nbytes: usize) -> u32446 fn max_scalar_value(nbytes: usize) -> u32 {
447 match nbytes {
448 1 => 0x007F,
449 2 => 0x07FF,
450 3 => 0xFFFF,
451 4 => 0x10FFFF,
452 _ => unreachable!("invalid UTF-8 byte sequence size"),
453 }
454 }
455
456 #[cfg(test)]
457 mod tests {
458 use std::char;
459
460 use utf8::{Utf8Range, Utf8Sequences};
461
rutf8(s: u8, e: u8) -> Utf8Range462 fn rutf8(s: u8, e: u8) -> Utf8Range {
463 Utf8Range::new(s, e)
464 }
465
never_accepts_surrogate_codepoints(start: char, end: char)466 fn never_accepts_surrogate_codepoints(start: char, end: char) {
467 for cp in 0xD800..0xE000 {
468 let buf = encode_surrogate(cp);
469 for r in Utf8Sequences::new(start, end) {
470 if r.matches(&buf) {
471 panic!(
472 "Sequence ({:X}, {:X}) contains range {:?}, \
473 which matches surrogate code point {:X} \
474 with encoded bytes {:?}",
475 start as u32, end as u32, r, cp, buf,
476 );
477 }
478 }
479 }
480 }
481
482 #[test]
codepoints_no_surrogates()483 fn codepoints_no_surrogates() {
484 never_accepts_surrogate_codepoints('\u{0}', '\u{FFFF}');
485 never_accepts_surrogate_codepoints('\u{0}', '\u{10FFFF}');
486 never_accepts_surrogate_codepoints('\u{0}', '\u{10FFFE}');
487 never_accepts_surrogate_codepoints('\u{80}', '\u{10FFFF}');
488 never_accepts_surrogate_codepoints('\u{D7FF}', '\u{E000}');
489 }
490
491 #[test]
single_codepoint_one_sequence()492 fn single_codepoint_one_sequence() {
493 // Tests that every range of scalar values that contains a single
494 // scalar value is recognized by one sequence of byte ranges.
495 for i in 0x0..(0x10FFFF + 1) {
496 let c = match char::from_u32(i) {
497 None => continue,
498 Some(c) => c,
499 };
500 let seqs: Vec<_> = Utf8Sequences::new(c, c).collect();
501 assert_eq!(seqs.len(), 1);
502 }
503 }
504
505 #[test]
bmp()506 fn bmp() {
507 use utf8::Utf8Sequence::*;
508
509 let seqs = Utf8Sequences::new('\u{0}', '\u{FFFF}').collect::<Vec<_>>();
510 assert_eq!(
511 seqs,
512 vec![
513 One(rutf8(0x0, 0x7F)),
514 Two([rutf8(0xC2, 0xDF), rutf8(0x80, 0xBF)]),
515 Three([
516 rutf8(0xE0, 0xE0),
517 rutf8(0xA0, 0xBF),
518 rutf8(0x80, 0xBF)
519 ]),
520 Three([
521 rutf8(0xE1, 0xEC),
522 rutf8(0x80, 0xBF),
523 rutf8(0x80, 0xBF)
524 ]),
525 Three([
526 rutf8(0xED, 0xED),
527 rutf8(0x80, 0x9F),
528 rutf8(0x80, 0xBF)
529 ]),
530 Three([
531 rutf8(0xEE, 0xEF),
532 rutf8(0x80, 0xBF),
533 rutf8(0x80, 0xBF)
534 ]),
535 ]
536 );
537 }
538
539 #[test]
reverse()540 fn reverse() {
541 use utf8::Utf8Sequence::*;
542
543 let mut s = One(rutf8(0xA, 0xB));
544 s.reverse();
545 assert_eq!(s.as_slice(), &[rutf8(0xA, 0xB)]);
546
547 let mut s = Two([rutf8(0xA, 0xB), rutf8(0xB, 0xC)]);
548 s.reverse();
549 assert_eq!(s.as_slice(), &[rutf8(0xB, 0xC), rutf8(0xA, 0xB)]);
550
551 let mut s = Three([rutf8(0xA, 0xB), rutf8(0xB, 0xC), rutf8(0xC, 0xD)]);
552 s.reverse();
553 assert_eq!(
554 s.as_slice(),
555 &[rutf8(0xC, 0xD), rutf8(0xB, 0xC), rutf8(0xA, 0xB)]
556 );
557
558 let mut s = Four([
559 rutf8(0xA, 0xB),
560 rutf8(0xB, 0xC),
561 rutf8(0xC, 0xD),
562 rutf8(0xD, 0xE),
563 ]);
564 s.reverse();
565 assert_eq!(
566 s.as_slice(),
567 &[
568 rutf8(0xD, 0xE),
569 rutf8(0xC, 0xD),
570 rutf8(0xB, 0xC),
571 rutf8(0xA, 0xB)
572 ]
573 );
574 }
575
encode_surrogate(cp: u32) -> [u8; 3]576 fn encode_surrogate(cp: u32) -> [u8; 3] {
577 const TAG_CONT: u8 = 0b1000_0000;
578 const TAG_THREE_B: u8 = 0b1110_0000;
579
580 assert!(0xD800 <= cp && cp < 0xE000);
581 let mut dst = [0; 3];
582 dst[0] = (cp >> 12 & 0x0F) as u8 | TAG_THREE_B;
583 dst[1] = (cp >> 6 & 0x3F) as u8 | TAG_CONT;
584 dst[2] = (cp & 0x3F) as u8 | TAG_CONT;
585 dst
586 }
587 }
588