Skip to main content

bstr/
utf8.rs

1use core::{char, cmp, fmt, str};
2
3use crate::{ascii, bstr::BStr, ext_slice::ByteSlice};
4
5// The UTF-8 decoder provided here is based on the one presented here:
6// https://bjoern.hoehrmann.de/utf-8/decoder/dfa/
7//
8// We *could* have done UTF-8 decoding by using a DFA generated by `\p{any}`
9// using regex-automata that is roughly the same size. The real benefit of
10// Hoehrmann's formulation is that the byte class mapping below is manually
11// tailored such that each byte's class doubles as a shift to mask out the
12// bits necessary for constructing the leading bits of each codepoint value
13// from the initial byte.
14//
15// There are some minor differences between this implementation and Hoehrmann's
16// formulation.
17//
18// Firstly, we make REJECT have state ID 0, since it makes the state table
19// itself a little easier to read and is consistent with the notion that 0
20// means "false" or "bad."
21//
22// Secondly, when doing bulk decoding, we add a SIMD accelerated ASCII fast
23// path.
24//
25// Thirdly, we pre-multiply the state IDs to avoid a multiplication instruction
26// in the core decoding loop. (Which is what regex-automata would do by
27// default.)
28//
29// Fourthly, we split the byte class mapping and transition table into two
30// arrays because it's clearer.
31//
32// It is unlikely that this is the fastest way to do UTF-8 decoding, however,
33// it is fairly simple.
34
35const ACCEPT: usize = 12;
36const REJECT: usize = 0;
37
38/// SAFETY: The decode below function relies on the correctness of these
39/// equivalence classes.
40#[rustfmt::skip]
41const CLASSES: [u8; 256] = [
42   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
43   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
44   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
45   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
46   1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,  9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
47   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
48   8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
49  10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
50];
51
52/// SAFETY: The decode below function relies on the correctness of this state
53/// machine.
54#[rustfmt::skip]
55const STATES_FORWARD: &[u8] = &[
56  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
57  12, 0, 24, 36, 60, 96, 84, 0, 0, 0, 48, 72,
58  0, 12, 0, 0, 0, 0, 0, 12, 0, 12, 0, 0,
59  0, 24, 0, 0, 0, 0, 0, 24, 0, 24, 0, 0,
60  0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0,
61  0, 24, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0,
62  0, 0, 0, 0, 0, 0, 0, 36, 0, 36, 0, 0,
63  0, 36, 0, 0, 0, 0, 0, 36, 0, 36, 0, 0,
64  0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
65];
66
67/// An iterator over Unicode scalar values in a byte string.
68///
69/// When invalid UTF-8 byte sequences are found, they are substituted with the
70/// Unicode replacement codepoint (`U+FFFD`) using the
71/// ["maximal subpart" strategy](https://www.unicode.org/review/pr-121.html).
72///
73/// This iterator is created by the
74/// [`chars`](trait.ByteSlice.html#method.chars) method provided by the
75/// [`ByteSlice`](trait.ByteSlice.html) extension trait for `&[u8]`.
76#[derive(Clone, Debug)]
77pub struct Chars<'a> {
78    bs: &'a [u8],
79}
80
81impl<'a> Chars<'a> {
82    pub(crate) fn new(bs: &'a [u8]) -> Chars<'a> {
83        Chars { bs }
84    }
85
86    /// View the underlying data as a subslice of the original data.
87    ///
88    /// The slice returned has the same lifetime as the original slice, and so
89    /// the iterator can continue to be used while this exists.
90    ///
91    /// # Examples
92    ///
93    /// ```
94    /// use bstr::ByteSlice;
95    ///
96    /// let mut chars = b"abc".chars();
97    ///
98    /// assert_eq!(b"abc", chars.as_bytes());
99    /// chars.next();
100    /// assert_eq!(b"bc", chars.as_bytes());
101    /// chars.next();
102    /// chars.next();
103    /// assert_eq!(b"", chars.as_bytes());
104    /// ```
105    #[inline]
106    pub fn as_bytes(&self) -> &'a [u8] {
107        self.bs
108    }
109}
110
111impl<'a> Iterator for Chars<'a> {
112    type Item = char;
113
114    #[inline]
115    fn next(&mut self) -> Option<char> {
116        let (ch, size) = decode_lossy(self.bs);
117        if size == 0 {
118            return None;
119        }
120        self.bs = &self.bs[size..];
121        Some(ch)
122    }
123
124    #[inline]
125    fn count(mut self) -> usize {
126        let mut count = 0;
127        loop {
128            // ASCII fast path taken if two consecutive ASCII chars found
129            match self.bs {
130                [fst, snd, ..] if *fst <= 0x7F && *snd <= 0x7F => {
131                    let size = ascii::first_non_ascii_byte(self.bs);
132                    count += size;
133                    self.bs = &self.bs[size..];
134                }
135                _ => (),
136            }
137
138            let (_ch, size) = decode(self.bs);
139            if size == 0 {
140                return count;
141            } else {
142                count += 1;
143                self.bs = &self.bs[size..];
144            }
145        }
146    }
147}
148
149impl<'a> DoubleEndedIterator for Chars<'a> {
150    #[inline]
151    fn next_back(&mut self) -> Option<char> {
152        let (ch, size) = decode_last_lossy(self.bs);
153        if size == 0 {
154            return None;
155        }
156        self.bs = &self.bs[..self.bs.len() - size];
157        Some(ch)
158    }
159}
160
161/// An iterator over Unicode scalar values in a byte string and their
162/// byte index positions.
163///
164/// When invalid UTF-8 byte sequences are found, they are substituted with the
165/// Unicode replacement codepoint (`U+FFFD`) using the
166/// ["maximal subpart" strategy](https://www.unicode.org/review/pr-121.html).
167///
168/// Note that this is slightly different from the `CharIndices` iterator
169/// provided by the standard library. Aside from working on possibly invalid
170/// UTF-8, this iterator provides both the corresponding starting and ending
171/// byte indices of each codepoint yielded. The ending position is necessary to
172/// slice the original byte string when invalid UTF-8 bytes are converted into
173/// a Unicode replacement codepoint, since a single replacement codepoint can
174/// substitute anywhere from 1 to 3 invalid bytes (inclusive).
175///
176/// This iterator is created by the
177/// [`char_indices`](trait.ByteSlice.html#method.char_indices) method provided
178/// by the [`ByteSlice`](trait.ByteSlice.html) extension trait for `&[u8]`.
179#[derive(Clone, Debug)]
180pub struct CharIndices<'a> {
181    bs: &'a [u8],
182    forward_index: usize,
183    reverse_index: usize,
184}
185
186impl<'a> CharIndices<'a> {
187    pub(crate) fn new(bs: &'a [u8]) -> CharIndices<'a> {
188        CharIndices { bs, forward_index: 0, reverse_index: bs.len() }
189    }
190
191    /// View the underlying data as a subslice of the original data.
192    ///
193    /// The slice returned has the same lifetime as the original slice, and so
194    /// the iterator can continue to be used while this exists.
195    ///
196    /// # Examples
197    ///
198    /// ```
199    /// use bstr::ByteSlice;
200    ///
201    /// let mut it = b"abc".char_indices();
202    ///
203    /// assert_eq!(b"abc", it.as_bytes());
204    /// it.next();
205    /// assert_eq!(b"bc", it.as_bytes());
206    /// it.next();
207    /// it.next();
208    /// assert_eq!(b"", it.as_bytes());
209    /// ```
210    #[inline]
211    pub fn as_bytes(&self) -> &'a [u8] {
212        self.bs
213    }
214}
215
216impl<'a> Iterator for CharIndices<'a> {
217    type Item = (usize, usize, char);
218
219    #[inline]
220    fn next(&mut self) -> Option<(usize, usize, char)> {
221        let index = self.forward_index;
222        let (ch, size) = decode_lossy(self.bs);
223        if size == 0 {
224            return None;
225        }
226        self.bs = &self.bs[size..];
227        self.forward_index += size;
228        Some((index, index + size, ch))
229    }
230}
231
232impl<'a> DoubleEndedIterator for CharIndices<'a> {
233    #[inline]
234    fn next_back(&mut self) -> Option<(usize, usize, char)> {
235        let (ch, size) = decode_last_lossy(self.bs);
236        if size == 0 {
237            return None;
238        }
239        self.bs = &self.bs[..self.bs.len() - size];
240        self.reverse_index -= size;
241        Some((self.reverse_index, self.reverse_index + size, ch))
242    }
243}
244
245impl<'a> ::core::iter::FusedIterator for CharIndices<'a> {}
246
247/// An iterator over chunks of valid UTF-8 in a byte slice.
248///
249/// See [`utf8_chunks`](trait.ByteSlice.html#method.utf8_chunks).
250#[derive(Clone, Debug)]
251pub struct Utf8Chunks<'a> {
252    pub(super) bytes: &'a [u8],
253}
254
255/// A chunk of valid UTF-8, possibly followed by invalid UTF-8 bytes.
256///
257/// This is yielded by the
258/// [`Utf8Chunks`](struct.Utf8Chunks.html)
259/// iterator, which can be created via the
260/// [`ByteSlice::utf8_chunks`](trait.ByteSlice.html#method.utf8_chunks)
261/// method.
262///
263/// The `'a` lifetime parameter corresponds to the lifetime of the bytes that
264/// are being iterated over.
265#[cfg_attr(test, derive(Debug, PartialEq))]
266pub struct Utf8Chunk<'a> {
267    /// A valid UTF-8 piece, at the start, end, or between invalid UTF-8 bytes.
268    ///
269    /// This is empty between adjacent invalid UTF-8 byte sequences.
270    valid: &'a str,
271    /// A sequence of invalid UTF-8 bytes.
272    ///
273    /// Can only be empty in the last chunk.
274    ///
275    /// Should be replaced by a single unicode replacement character, if not
276    /// empty.
277    invalid: &'a BStr,
278    /// Indicates whether the invalid sequence could've been valid if there
279    /// were more bytes.
280    ///
281    /// Can only be true in the last chunk.
282    incomplete: bool,
283}
284
285impl<'a> Utf8Chunk<'a> {
286    /// Returns the (possibly empty) valid UTF-8 bytes in this chunk.
287    ///
288    /// This may be empty if there are consecutive sequences of invalid UTF-8
289    /// bytes.
290    #[inline]
291    pub fn valid(&self) -> &'a str {
292        self.valid
293    }
294
295    /// Returns the (possibly empty) invalid UTF-8 bytes in this chunk that
296    /// immediately follow the valid UTF-8 bytes in this chunk.
297    ///
298    /// This is only empty when this chunk corresponds to the last chunk in
299    /// the original bytes.
300    ///
301    /// The maximum length of this slice is 3. That is, invalid UTF-8 byte
302    /// sequences greater than 1 always correspond to a valid _prefix_ of
303    /// a valid UTF-8 encoded codepoint. This corresponds to the "substitution
304    /// of maximal subparts" strategy that is described in more detail in the
305    /// docs for the
306    /// [`ByteSlice::to_str_lossy`](trait.ByteSlice.html#method.to_str_lossy)
307    /// method.
308    #[inline]
309    pub fn invalid(&self) -> &'a [u8] {
310        self.invalid.as_bytes()
311    }
312
313    /// Returns whether the invalid sequence might still become valid if more
314    /// bytes are added.
315    ///
316    /// Returns true if the end of the input was reached unexpectedly,
317    /// without encountering an unexpected byte.
318    ///
319    /// This can only be the case for the last chunk.
320    #[inline]
321    pub fn incomplete(&self) -> bool {
322        self.incomplete
323    }
324}
325
326impl<'a> Iterator for Utf8Chunks<'a> {
327    type Item = Utf8Chunk<'a>;
328
329    #[inline]
330    fn next(&mut self) -> Option<Utf8Chunk<'a>> {
331        if self.bytes.is_empty() {
332            return None;
333        }
334        match validate(self.bytes) {
335            Ok(()) => {
336                let valid = self.bytes;
337                self.bytes = &[];
338                Some(Utf8Chunk {
339                    // SAFETY: This is safe because of the guarantees provided
340                    // by utf8::validate.
341                    valid: unsafe { str::from_utf8_unchecked(valid) },
342                    invalid: [].as_bstr(),
343                    incomplete: false,
344                })
345            }
346            Err(e) => {
347                let (valid, rest) = self.bytes.split_at(e.valid_up_to());
348                // SAFETY: This is safe because of the guarantees provided by
349                // utf8::validate.
350                let valid = unsafe { str::from_utf8_unchecked(valid) };
351                let (invalid_len, incomplete) = match e.error_len() {
352                    Some(n) => (n, false),
353                    None => (rest.len(), true),
354                };
355                let (invalid, rest) = rest.split_at(invalid_len);
356                self.bytes = rest;
357                Some(Utf8Chunk {
358                    valid,
359                    invalid: invalid.as_bstr(),
360                    incomplete,
361                })
362            }
363        }
364    }
365
366    #[inline]
367    fn size_hint(&self) -> (usize, Option<usize>) {
368        if self.bytes.is_empty() {
369            (0, Some(0))
370        } else {
371            (1, Some(self.bytes.len()))
372        }
373    }
374}
375
376impl<'a> ::core::iter::FusedIterator for Utf8Chunks<'a> {}
377
378/// An error that occurs when UTF-8 decoding fails.
379///
380/// This error occurs when attempting to convert a non-UTF-8 byte
381/// string to a Rust string that must be valid UTF-8. For example,
382/// [`to_str`](trait.ByteSlice.html#method.to_str) is one such method.
383///
384/// # Example
385///
386/// This example shows what happens when a given byte sequence is invalid,
387/// but ends with a sequence that is a possible prefix of valid UTF-8.
388///
389/// ```
390/// use bstr::{B, ByteSlice};
391///
392/// let s = B(b"foobar\xF1\x80\x80");
393/// let err = s.to_str().unwrap_err();
394/// assert_eq!(err.valid_up_to(), 6);
395/// assert_eq!(err.error_len(), None);
396/// ```
397///
398/// This example shows what happens when a given byte sequence contains
399/// invalid UTF-8.
400///
401/// ```
402/// use bstr::ByteSlice;
403///
404/// let s = b"foobar\xF1\x80\x80quux";
405/// let err = s.to_str().unwrap_err();
406/// assert_eq!(err.valid_up_to(), 6);
407/// // The error length reports the maximum number of bytes that correspond to
408/// // a valid prefix of a UTF-8 encoded codepoint.
409/// assert_eq!(err.error_len(), Some(3));
410///
411/// // In contrast to the above which contains a single invalid prefix,
412/// // consider the case of multiple individual bytes that are never valid
413/// // prefixes. Note how the value of error_len changes!
414/// let s = b"foobar\xFF\xFFquux";
415/// let err = s.to_str().unwrap_err();
416/// assert_eq!(err.valid_up_to(), 6);
417/// assert_eq!(err.error_len(), Some(1));
418///
419/// // The fact that it's an invalid prefix does not change error_len even
420/// // when it immediately precedes the end of the string.
421/// let s = b"foobar\xFF";
422/// let err = s.to_str().unwrap_err();
423/// assert_eq!(err.valid_up_to(), 6);
424/// assert_eq!(err.error_len(), Some(1));
425/// ```
426#[derive(Clone, Debug, Eq, PartialEq)]
427pub struct Utf8Error {
428    valid_up_to: usize,
429    error_len: Option<usize>,
430}
431
432impl Utf8Error {
433    /// Returns the byte index of the position immediately following the last
434    /// valid UTF-8 byte.
435    ///
436    /// # Example
437    ///
438    /// This examples shows how `valid_up_to` can be used to retrieve a
439    /// possibly empty prefix that is guaranteed to be valid UTF-8:
440    ///
441    /// ```
442    /// use bstr::ByteSlice;
443    ///
444    /// let s = b"foobar\xF1\x80\x80quux";
445    /// let err = s.to_str().unwrap_err();
446    ///
447    /// // This is guaranteed to never panic.
448    /// let string = s[..err.valid_up_to()].to_str().unwrap();
449    /// assert_eq!(string, "foobar");
450    /// ```
451    #[inline]
452    pub fn valid_up_to(&self) -> usize {
453        self.valid_up_to
454    }
455
456    /// Returns the total number of invalid UTF-8 bytes immediately following
457    /// the position returned by `valid_up_to`. This value is always at least
458    /// `1`, but can be up to `3` if bytes form a valid prefix of some UTF-8
459    /// encoded codepoint.
460    ///
461    /// If the end of the original input was found before a valid UTF-8 encoded
462    /// codepoint could be completed, then this returns `None`. This is useful
463    /// when processing streams, where a `None` value signals that more input
464    /// might be needed.
465    #[inline]
466    pub fn error_len(&self) -> Option<usize> {
467        self.error_len
468    }
469}
470
471#[cfg(feature = "std")]
472impl std::error::Error for Utf8Error {
473    fn description(&self) -> &str {
474        "invalid UTF-8"
475    }
476}
477
478impl fmt::Display for Utf8Error {
479    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
480        write!(f, "invalid UTF-8 found at byte offset {}", self.valid_up_to)
481    }
482}
483
484/// Returns OK if and only if the given slice is completely valid UTF-8.
485///
486/// If the slice isn't valid UTF-8, then an error is returned that explains
487/// the first location at which invalid UTF-8 was detected.
488pub fn validate(slice: &[u8]) -> Result<(), Utf8Error> {
489    // The fast path for validating UTF-8. It steps through a UTF-8 automaton
490    // and uses a SIMD accelerated ASCII fast path on x86_64. If an error is
491    // detected, it backs up and runs the slower version of the UTF-8 automaton
492    // to determine correct error information.
493    fn fast(slice: &[u8]) -> Result<(), Utf8Error> {
494        let mut state = ACCEPT;
495        let mut i = 0;
496
497        while i < slice.len() {
498            let b = slice[i];
499
500            // ASCII fast path. If we see two consecutive ASCII bytes, then try
501            // to validate as much ASCII as possible very quickly.
502            if state == ACCEPT
503                && b <= 0x7F
504                && slice.get(i + 1).map_or(false, |&b| b <= 0x7F)
505            {
506                i += ascii::first_non_ascii_byte(&slice[i..]);
507                continue;
508            }
509
510            state = step(state, b);
511            if state == REJECT {
512                return Err(find_valid_up_to(slice, i));
513            }
514            i += 1;
515        }
516        if state != ACCEPT {
517            Err(find_valid_up_to(slice, slice.len()))
518        } else {
519            Ok(())
520        }
521    }
522
523    // Given the first position at which a UTF-8 sequence was determined to be
524    // invalid, return an error that correctly reports the position at which
525    // the last complete UTF-8 sequence ends.
526    #[inline(never)]
527    fn find_valid_up_to(slice: &[u8], rejected_at: usize) -> Utf8Error {
528        // In order to find the last valid byte, we need to back up an amount
529        // that guarantees every preceding byte is part of a valid UTF-8
530        // code unit sequence. To do this, we simply locate the last leading
531        // byte that occurs before rejected_at.
532        let mut backup = rejected_at.saturating_sub(1);
533        while backup > 0 && !is_leading_or_invalid_utf8_byte(slice[backup]) {
534            backup -= 1;
535        }
536        let upto = cmp::min(slice.len(), rejected_at.saturating_add(1));
537        let mut err = slow(&slice[backup..upto]).unwrap_err();
538        err.valid_up_to += backup;
539        err
540    }
541
542    // Like top-level UTF-8 decoding, except it correctly reports a UTF-8 error
543    // when an invalid sequence is found. This is split out from validate so
544    // that the fast path doesn't need to keep track of the position of the
545    // last valid UTF-8 byte. In particular, tracking this requires checking
546    // for an ACCEPT state on each byte, which degrades throughput pretty
547    // badly.
548    fn slow(slice: &[u8]) -> Result<(), Utf8Error> {
549        let mut state = ACCEPT;
550        let mut valid_up_to = 0;
551        for (i, &b) in slice.iter().enumerate() {
552            state = step(state, b);
553            if state == ACCEPT {
554                valid_up_to = i + 1;
555            } else if state == REJECT {
556                // Our error length must always be at least 1.
557                let error_len = Some(cmp::max(1, i - valid_up_to));
558                return Err(Utf8Error { valid_up_to, error_len });
559            }
560        }
561        if state != ACCEPT {
562            Err(Utf8Error { valid_up_to, error_len: None })
563        } else {
564            Ok(())
565        }
566    }
567
568    // Advance to the next state given the current state and current byte.
569    fn step(state: usize, b: u8) -> usize {
570        let class = CLASSES[b as usize];
571        // SAFETY: This is safe because 'class' is always <=11 and 'state' is
572        // always <=96. Therefore, the maximal index is 96+11 = 107, where
573        // STATES_FORWARD.len() = 108 such that every index is guaranteed to be
574        // valid by construction of the state machine and the byte equivalence
575        // classes.
576        unsafe {
577            *STATES_FORWARD.get_unchecked(state + class as usize) as usize
578        }
579    }
580
581    fast(slice)
582}
583
584/// UTF-8 decode a single Unicode scalar value from the beginning of a slice.
585///
586/// When successful, the corresponding Unicode scalar value is returned along
587/// with the number of bytes it was encoded with. The number of bytes consumed
588/// for a successful decode is always between 1 and 4, inclusive.
589///
590/// When unsuccessful, `None` is returned along with the number of bytes that
591/// make up a maximal prefix of a valid UTF-8 code unit sequence. When there is
592/// no prefix of a valid UTF-8 code unit sequence, then 1 byte is consumed.
593/// Thus, for a non-empty slice given, the number of bytes consumed is always
594/// at least `1`. `0` is only returned when `slice` is empty.
595///
596/// # Examples
597///
598/// Basic usage:
599///
600/// ```
601/// use bstr::decode_utf8;
602///
603/// // Decoding a valid codepoint.
604/// let (ch, size) = decode_utf8(b"\xE2\x98\x83");
605/// assert_eq!(Some('☃'), ch);
606/// assert_eq!(3, size);
607///
608/// // Decoding an incomplete codepoint.
609/// let (ch, size) = decode_utf8(b"\xE2\x98");
610/// assert_eq!(None, ch);
611/// assert_eq!(2, size);
612/// ```
613///
614/// This example shows how to iterate over all codepoints in UTF-8 encoded
615/// bytes, while replacing invalid UTF-8 sequences with the replacement
616/// codepoint:
617///
618/// ```
619/// use bstr::{B, decode_utf8};
620///
621/// let mut bytes = B(b"\xE2\x98\x83\xFF\xF0\x9D\x9E\x83\xE2\x98\x61");
622/// let mut chars = vec![];
623/// while !bytes.is_empty() {
624///     let (ch, size) = decode_utf8(bytes);
625///     bytes = &bytes[size..];
626///     chars.push(ch.unwrap_or('\u{FFFD}'));
627/// }
628/// assert_eq!(vec!['☃', '\u{FFFD}', '𝞃', '\u{FFFD}', 'a'], chars);
629/// ```
630#[inline]
631pub fn decode<B: AsRef<[u8]>>(slice: B) -> (Option<char>, usize) {
632    let slice = slice.as_ref();
633    match slice.first() {
634        None => return (None, 0),
635        Some(&b) if b <= 0x7F => return (Some(b as char), 1),
636        _ => {}
637    }
638
639    let (mut state, mut cp, mut i) = (ACCEPT, 0, 0);
640    while i < slice.len() {
641        decode_step(&mut state, &mut cp, slice[i]);
642        i += 1;
643
644        if state == ACCEPT {
645            // SAFETY: This is safe because `decode_step` guarantees that
646            // `cp` is a valid Unicode scalar value in an ACCEPT state.
647            let ch = unsafe { char::from_u32_unchecked(cp) };
648            return (Some(ch), i);
649        } else if state == REJECT {
650            // At this point, we always want to advance at least one byte.
651            return (None, cmp::max(1, i.saturating_sub(1)));
652        }
653    }
654    (None, i)
655}
656
657/// Lossily UTF-8 decode a single Unicode scalar value from the beginning of a
658/// slice.
659///
660/// When successful, the corresponding Unicode scalar value is returned along
661/// with the number of bytes it was encoded with. The number of bytes consumed
662/// for a successful decode is always between 1 and 4, inclusive.
663///
664/// When unsuccessful, the Unicode replacement codepoint (`U+FFFD`) is returned
665/// along with the number of bytes that make up a maximal prefix of a valid
666/// UTF-8 code unit sequence. In this case, the number of bytes consumed is
667/// always between 0 and 3, inclusive, where 0 is only returned when `slice` is
668/// empty.
669///
670/// # Examples
671///
672/// Basic usage:
673///
674/// ```ignore
675/// use bstr::decode_utf8_lossy;
676///
677/// // Decoding a valid codepoint.
678/// let (ch, size) = decode_utf8_lossy(b"\xE2\x98\x83");
679/// assert_eq!('☃', ch);
680/// assert_eq!(3, size);
681///
682/// // Decoding an incomplete codepoint.
683/// let (ch, size) = decode_utf8_lossy(b"\xE2\x98");
684/// assert_eq!('\u{FFFD}', ch);
685/// assert_eq!(2, size);
686/// ```
687///
688/// This example shows how to iterate over all codepoints in UTF-8 encoded
689/// bytes, while replacing invalid UTF-8 sequences with the replacement
690/// codepoint:
691///
692/// ```ignore
693/// use bstr::{B, decode_utf8_lossy};
694///
695/// let mut bytes = B(b"\xE2\x98\x83\xFF\xF0\x9D\x9E\x83\xE2\x98\x61");
696/// let mut chars = vec![];
697/// while !bytes.is_empty() {
698///     let (ch, size) = decode_utf8_lossy(bytes);
699///     bytes = &bytes[size..];
700///     chars.push(ch);
701/// }
702/// assert_eq!(vec!['☃', '\u{FFFD}', '𝞃', '\u{FFFD}', 'a'], chars);
703/// ```
704#[inline]
705pub fn decode_lossy<B: AsRef<[u8]>>(slice: B) -> (char, usize) {
706    match decode(slice) {
707        (Some(ch), size) => (ch, size),
708        (None, size) => ('\u{FFFD}', size),
709    }
710}
711
712/// UTF-8 decode a single Unicode scalar value from the end of a slice.
713///
714/// When successful, the corresponding Unicode scalar value is returned along
715/// with the number of bytes it was encoded with. The number of bytes consumed
716/// for a successful decode is always between 1 and 4, inclusive.
717///
718/// When unsuccessful, `None` is returned along with the number of bytes that
719/// make up a maximal prefix of a valid UTF-8 code unit sequence. In this case,
720/// the number of bytes consumed is always between 0 and 3, inclusive, where
721/// 0 is only returned when `slice` is empty.
722///
723/// # Examples
724///
725/// Basic usage:
726///
727/// ```
728/// use bstr::decode_last_utf8;
729///
730/// // Decoding a valid codepoint.
731/// let (ch, size) = decode_last_utf8(b"\xE2\x98\x83");
732/// assert_eq!(Some('☃'), ch);
733/// assert_eq!(3, size);
734///
735/// // Decoding an incomplete codepoint.
736/// let (ch, size) = decode_last_utf8(b"\xE2\x98");
737/// assert_eq!(None, ch);
738/// assert_eq!(2, size);
739/// ```
740///
741/// This example shows how to iterate over all codepoints in UTF-8 encoded
742/// bytes in reverse, while replacing invalid UTF-8 sequences with the
743/// replacement codepoint:
744///
745/// ```
746/// use bstr::{B, decode_last_utf8};
747///
748/// let mut bytes = B(b"\xE2\x98\x83\xFF\xF0\x9D\x9E\x83\xE2\x98\x61");
749/// let mut chars = vec![];
750/// while !bytes.is_empty() {
751///     let (ch, size) = decode_last_utf8(bytes);
752///     bytes = &bytes[..bytes.len()-size];
753///     chars.push(ch.unwrap_or('\u{FFFD}'));
754/// }
755/// assert_eq!(vec!['a', '\u{FFFD}', '𝞃', '\u{FFFD}', '☃'], chars);
756/// ```
757#[inline]
758pub fn decode_last<B: AsRef<[u8]>>(slice: B) -> (Option<char>, usize) {
759    // TODO: We could implement this by reversing the UTF-8 automaton, but for
760    // now, we do it the slow way by using the forward automaton.
761
762    let slice = slice.as_ref();
763    if slice.is_empty() {
764        return (None, 0);
765    }
766    let mut start = slice.len() - 1;
767    let limit = slice.len().saturating_sub(4);
768    while start > limit && !is_leading_or_invalid_utf8_byte(slice[start]) {
769        start -= 1;
770    }
771    let (ch, size) = decode(&slice[start..]);
772    // If we didn't consume all of the bytes, then that means there's at least
773    // one stray byte that never occurs in a valid code unit prefix, so we can
774    // advance by one byte.
775    if start + size != slice.len() {
776        (None, 1)
777    } else {
778        (ch, size)
779    }
780}
781
782/// Lossily UTF-8 decode a single Unicode scalar value from the end of a slice.
783///
784/// When successful, the corresponding Unicode scalar value is returned along
785/// with the number of bytes it was encoded with. The number of bytes consumed
786/// for a successful decode is always between 1 and 4, inclusive.
787///
788/// When unsuccessful, the Unicode replacement codepoint (`U+FFFD`) is returned
789/// along with the number of bytes that make up a maximal prefix of a valid
790/// UTF-8 code unit sequence. In this case, the number of bytes consumed is
791/// always between 0 and 3, inclusive, where 0 is only returned when `slice` is
792/// empty.
793///
794/// # Examples
795///
796/// Basic usage:
797///
798/// ```ignore
799/// use bstr::decode_last_utf8_lossy;
800///
801/// // Decoding a valid codepoint.
802/// let (ch, size) = decode_last_utf8_lossy(b"\xE2\x98\x83");
803/// assert_eq!('☃', ch);
804/// assert_eq!(3, size);
805///
806/// // Decoding an incomplete codepoint.
807/// let (ch, size) = decode_last_utf8_lossy(b"\xE2\x98");
808/// assert_eq!('\u{FFFD}', ch);
809/// assert_eq!(2, size);
810/// ```
811///
812/// This example shows how to iterate over all codepoints in UTF-8 encoded
813/// bytes in reverse, while replacing invalid UTF-8 sequences with the
814/// replacement codepoint:
815///
816/// ```ignore
817/// use bstr::decode_last_utf8_lossy;
818///
819/// let mut bytes = B(b"\xE2\x98\x83\xFF\xF0\x9D\x9E\x83\xE2\x98\x61");
820/// let mut chars = vec![];
821/// while !bytes.is_empty() {
822///     let (ch, size) = decode_last_utf8_lossy(bytes);
823///     bytes = &bytes[..bytes.len()-size];
824///     chars.push(ch);
825/// }
826/// assert_eq!(vec!['a', '\u{FFFD}', '𝞃', '\u{FFFD}', '☃'], chars);
827/// ```
828#[inline]
829pub fn decode_last_lossy<B: AsRef<[u8]>>(slice: B) -> (char, usize) {
830    match decode_last(slice) {
831        (Some(ch), size) => (ch, size),
832        (None, size) => ('\u{FFFD}', size),
833    }
834}
835
836/// SAFETY: The decode function relies on state being equal to ACCEPT only if
837/// cp is a valid Unicode scalar value.
838#[inline]
839pub fn decode_step(state: &mut usize, cp: &mut u32, b: u8) {
840    let class = CLASSES[b as usize];
841    let b = u32::from(b);
842    if *state == ACCEPT {
843        *cp = (0xFF >> class) & b;
844    } else {
845        *cp = (b & 0b0011_1111) | (*cp << 6);
846    }
847    *state = STATES_FORWARD[*state + class as usize] as usize;
848}
849
850/// Returns true if and only if the given byte is either a valid leading UTF-8
851/// byte, or is otherwise an invalid byte that can never appear anywhere in a
852/// valid UTF-8 sequence.
853fn is_leading_or_invalid_utf8_byte(b: u8) -> bool {
854    // In the ASCII case, the most significant bit is never set. The leading
855    // byte of a 2/3/4-byte sequence always has the top two most significant
856    // bits set. For bytes that can never appear anywhere in valid UTF-8, this
857    // also returns true, since every such byte has its two most significant
858    // bits set:
859    //
860    //     \xC0 :: 11000000
861    //     \xC1 :: 11000001
862    //     \xF5 :: 11110101
863    //     \xF6 :: 11110110
864    //     \xF7 :: 11110111
865    //     \xF8 :: 11111000
866    //     \xF9 :: 11111001
867    //     \xFA :: 11111010
868    //     \xFB :: 11111011
869    //     \xFC :: 11111100
870    //     \xFD :: 11111101
871    //     \xFE :: 11111110
872    //     \xFF :: 11111111
873    (b & 0b1100_0000) != 0b1000_0000
874}
875
876#[cfg(all(test, feature = "std"))]
877mod tests {
878    use core::char;
879
880    use alloc::{string::String, vec, vec::Vec};
881
882    use crate::{
883        ext_slice::{ByteSlice, B},
884        tests::LOSSY_TESTS,
885        utf8::{self, Utf8Error},
886    };
887
888    fn utf8e(valid_up_to: usize) -> Utf8Error {
889        Utf8Error { valid_up_to, error_len: None }
890    }
891
892    fn utf8e2(valid_up_to: usize, error_len: usize) -> Utf8Error {
893        Utf8Error { valid_up_to, error_len: Some(error_len) }
894    }
895
896    #[test]
897    #[cfg(not(miri))]
898    fn validate_all_codepoints() {
899        for i in 0..(0x10FFFF + 1) {
900            let cp = match char::from_u32(i) {
901                None => continue,
902                Some(cp) => cp,
903            };
904            let mut buf = [0; 4];
905            let s = cp.encode_utf8(&mut buf);
906            assert_eq!(Ok(()), utf8::validate(s.as_bytes()));
907        }
908    }
909
910    #[test]
911    fn validate_multiple_codepoints() {
912        assert_eq!(Ok(()), utf8::validate(b"abc"));
913        assert_eq!(Ok(()), utf8::validate(b"a\xE2\x98\x83a"));
914        assert_eq!(Ok(()), utf8::validate(b"a\xF0\x9D\x9C\xB7a"));
915        assert_eq!(Ok(()), utf8::validate(b"\xE2\x98\x83\xF0\x9D\x9C\xB7",));
916        assert_eq!(
917            Ok(()),
918            utf8::validate(b"a\xE2\x98\x83a\xF0\x9D\x9C\xB7a",)
919        );
920        assert_eq!(
921            Ok(()),
922            utf8::validate(b"\xEF\xBF\xBD\xE2\x98\x83\xEF\xBF\xBD",)
923        );
924    }
925
926    #[test]
927    fn validate_errors() {
928        // single invalid byte
929        assert_eq!(Err(utf8e2(0, 1)), utf8::validate(b"\xFF"));
930        // single invalid byte after ASCII
931        assert_eq!(Err(utf8e2(1, 1)), utf8::validate(b"a\xFF"));
932        // single invalid byte after 2 byte sequence
933        assert_eq!(Err(utf8e2(2, 1)), utf8::validate(b"\xCE\xB2\xFF"));
934        // single invalid byte after 3 byte sequence
935        assert_eq!(Err(utf8e2(3, 1)), utf8::validate(b"\xE2\x98\x83\xFF"));
936        // single invalid byte after 4 byte sequence
937        assert_eq!(Err(utf8e2(4, 1)), utf8::validate(b"\xF0\x9D\x9D\xB1\xFF"));
938
939        // An invalid 2-byte sequence with a valid 1-byte prefix.
940        assert_eq!(Err(utf8e2(0, 1)), utf8::validate(b"\xCE\xF0"));
941        // An invalid 3-byte sequence with a valid 2-byte prefix.
942        assert_eq!(Err(utf8e2(0, 2)), utf8::validate(b"\xE2\x98\xF0"));
943        // An invalid 4-byte sequence with a valid 3-byte prefix.
944        assert_eq!(Err(utf8e2(0, 3)), utf8::validate(b"\xF0\x9D\x9D\xF0"));
945
946        // An overlong sequence. Should be \xE2\x82\xAC, but we encode the
947        // same codepoint value in 4 bytes. This not only tests that we reject
948        // overlong sequences, but that we get valid_up_to correct.
949        assert_eq!(Err(utf8e2(0, 1)), utf8::validate(b"\xF0\x82\x82\xAC"));
950        assert_eq!(Err(utf8e2(1, 1)), utf8::validate(b"a\xF0\x82\x82\xAC"));
951        assert_eq!(
952            Err(utf8e2(3, 1)),
953            utf8::validate(b"\xE2\x98\x83\xF0\x82\x82\xAC",)
954        );
955
956        // Check that encoding a surrogate codepoint using the UTF-8 scheme
957        // fails validation.
958        assert_eq!(Err(utf8e2(0, 1)), utf8::validate(b"\xED\xA0\x80"));
959        assert_eq!(Err(utf8e2(1, 1)), utf8::validate(b"a\xED\xA0\x80"));
960        assert_eq!(
961            Err(utf8e2(3, 1)),
962            utf8::validate(b"\xE2\x98\x83\xED\xA0\x80",)
963        );
964
965        // Check that an incomplete 2-byte sequence fails.
966        assert_eq!(Err(utf8e2(0, 1)), utf8::validate(b"\xCEa"));
967        assert_eq!(Err(utf8e2(1, 1)), utf8::validate(b"a\xCEa"));
968        assert_eq!(
969            Err(utf8e2(3, 1)),
970            utf8::validate(b"\xE2\x98\x83\xCE\xE2\x98\x83",)
971        );
972        // Check that an incomplete 3-byte sequence fails.
973        assert_eq!(Err(utf8e2(0, 2)), utf8::validate(b"\xE2\x98a"));
974        assert_eq!(Err(utf8e2(1, 2)), utf8::validate(b"a\xE2\x98a"));
975        assert_eq!(
976            Err(utf8e2(3, 2)),
977            utf8::validate(b"\xE2\x98\x83\xE2\x98\xE2\x98\x83",)
978        );
979        // Check that an incomplete 4-byte sequence fails.
980        assert_eq!(Err(utf8e2(0, 3)), utf8::validate(b"\xF0\x9D\x9Ca"));
981        assert_eq!(Err(utf8e2(1, 3)), utf8::validate(b"a\xF0\x9D\x9Ca"));
982        assert_eq!(
983            Err(utf8e2(4, 3)),
984            utf8::validate(b"\xF0\x9D\x9C\xB1\xF0\x9D\x9C\xE2\x98\x83",)
985        );
986        assert_eq!(
987            Err(utf8e2(6, 3)),
988            utf8::validate(b"foobar\xF1\x80\x80quux",)
989        );
990
991        // Check that an incomplete (EOF) 2-byte sequence fails.
992        assert_eq!(Err(utf8e(0)), utf8::validate(b"\xCE"));
993        assert_eq!(Err(utf8e(1)), utf8::validate(b"a\xCE"));
994        assert_eq!(Err(utf8e(3)), utf8::validate(b"\xE2\x98\x83\xCE"));
995        // Check that an incomplete (EOF) 3-byte sequence fails.
996        assert_eq!(Err(utf8e(0)), utf8::validate(b"\xE2\x98"));
997        assert_eq!(Err(utf8e(1)), utf8::validate(b"a\xE2\x98"));
998        assert_eq!(Err(utf8e(3)), utf8::validate(b"\xE2\x98\x83\xE2\x98"));
999        // Check that an incomplete (EOF) 4-byte sequence fails.
1000        assert_eq!(Err(utf8e(0)), utf8::validate(b"\xF0\x9D\x9C"));
1001        assert_eq!(Err(utf8e(1)), utf8::validate(b"a\xF0\x9D\x9C"));
1002        assert_eq!(
1003            Err(utf8e(4)),
1004            utf8::validate(b"\xF0\x9D\x9C\xB1\xF0\x9D\x9C",)
1005        );
1006
1007        // Test that we errors correct even after long valid sequences. This
1008        // checks that our "backup" logic for detecting errors is correct.
1009        assert_eq!(
1010            Err(utf8e2(8, 1)),
1011            utf8::validate(b"\xe2\x98\x83\xce\xb2\xe3\x83\x84\xFF",)
1012        );
1013    }
1014
1015    #[test]
1016    fn decode_valid() {
1017        fn d(mut s: &str) -> Vec<char> {
1018            let mut chars = vec![];
1019            while !s.is_empty() {
1020                let (ch, size) = utf8::decode(s.as_bytes());
1021                s = &s[size..];
1022                chars.push(ch.unwrap());
1023            }
1024            chars
1025        }
1026
1027        assert_eq!(vec!['☃'], d("☃"));
1028        assert_eq!(vec!['☃', '☃'], d("☃☃"));
1029        assert_eq!(vec!['α', 'β', 'γ', 'δ', 'ε'], d("αβγδε"));
1030        assert_eq!(vec!['☃', '⛄', '⛇'], d("☃⛄⛇"));
1031        assert_eq!(vec!['𝗮', '𝗯', '𝗰', '𝗱', '𝗲'], d("𝗮𝗯𝗰𝗱𝗲"));
1032    }
1033
1034    #[test]
1035    fn decode_invalid() {
1036        let (ch, size) = utf8::decode(b"");
1037        assert_eq!(None, ch);
1038        assert_eq!(0, size);
1039
1040        let (ch, size) = utf8::decode(b"\xFF");
1041        assert_eq!(None, ch);
1042        assert_eq!(1, size);
1043
1044        let (ch, size) = utf8::decode(b"\xCE\xF0");
1045        assert_eq!(None, ch);
1046        assert_eq!(1, size);
1047
1048        let (ch, size) = utf8::decode(b"\xE2\x98\xF0");
1049        assert_eq!(None, ch);
1050        assert_eq!(2, size);
1051
1052        let (ch, size) = utf8::decode(b"\xF0\x9D\x9D");
1053        assert_eq!(None, ch);
1054        assert_eq!(3, size);
1055
1056        let (ch, size) = utf8::decode(b"\xF0\x9D\x9D\xF0");
1057        assert_eq!(None, ch);
1058        assert_eq!(3, size);
1059
1060        let (ch, size) = utf8::decode(b"\xF0\x82\x82\xAC");
1061        assert_eq!(None, ch);
1062        assert_eq!(1, size);
1063
1064        let (ch, size) = utf8::decode(b"\xED\xA0\x80");
1065        assert_eq!(None, ch);
1066        assert_eq!(1, size);
1067
1068        let (ch, size) = utf8::decode(b"\xCEa");
1069        assert_eq!(None, ch);
1070        assert_eq!(1, size);
1071
1072        let (ch, size) = utf8::decode(b"\xE2\x98a");
1073        assert_eq!(None, ch);
1074        assert_eq!(2, size);
1075
1076        let (ch, size) = utf8::decode(b"\xF0\x9D\x9Ca");
1077        assert_eq!(None, ch);
1078        assert_eq!(3, size);
1079    }
1080
1081    #[test]
1082    fn decode_lossy() {
1083        let (ch, size) = utf8::decode_lossy(b"");
1084        assert_eq!('\u{FFFD}', ch);
1085        assert_eq!(0, size);
1086
1087        let (ch, size) = utf8::decode_lossy(b"\xFF");
1088        assert_eq!('\u{FFFD}', ch);
1089        assert_eq!(1, size);
1090
1091        let (ch, size) = utf8::decode_lossy(b"\xCE\xF0");
1092        assert_eq!('\u{FFFD}', ch);
1093        assert_eq!(1, size);
1094
1095        let (ch, size) = utf8::decode_lossy(b"\xE2\x98\xF0");
1096        assert_eq!('\u{FFFD}', ch);
1097        assert_eq!(2, size);
1098
1099        let (ch, size) = utf8::decode_lossy(b"\xF0\x9D\x9D\xF0");
1100        assert_eq!('\u{FFFD}', ch);
1101        assert_eq!(3, size);
1102
1103        let (ch, size) = utf8::decode_lossy(b"\xF0\x82\x82\xAC");
1104        assert_eq!('\u{FFFD}', ch);
1105        assert_eq!(1, size);
1106
1107        let (ch, size) = utf8::decode_lossy(b"\xED\xA0\x80");
1108        assert_eq!('\u{FFFD}', ch);
1109        assert_eq!(1, size);
1110
1111        let (ch, size) = utf8::decode_lossy(b"\xCEa");
1112        assert_eq!('\u{FFFD}', ch);
1113        assert_eq!(1, size);
1114
1115        let (ch, size) = utf8::decode_lossy(b"\xE2\x98a");
1116        assert_eq!('\u{FFFD}', ch);
1117        assert_eq!(2, size);
1118
1119        let (ch, size) = utf8::decode_lossy(b"\xF0\x9D\x9Ca");
1120        assert_eq!('\u{FFFD}', ch);
1121        assert_eq!(3, size);
1122    }
1123
1124    #[test]
1125    fn decode_last_valid() {
1126        fn d(mut s: &str) -> Vec<char> {
1127            let mut chars = vec![];
1128            while !s.is_empty() {
1129                let (ch, size) = utf8::decode_last(s.as_bytes());
1130                s = &s[..s.len() - size];
1131                chars.push(ch.unwrap());
1132            }
1133            chars
1134        }
1135
1136        assert_eq!(vec!['☃'], d("☃"));
1137        assert_eq!(vec!['☃', '☃'], d("☃☃"));
1138        assert_eq!(vec!['ε', 'δ', 'γ', 'β', 'α'], d("αβγδε"));
1139        assert_eq!(vec!['⛇', '⛄', '☃'], d("☃⛄⛇"));
1140        assert_eq!(vec!['𝗲', '𝗱', '𝗰', '𝗯', '𝗮'], d("𝗮𝗯𝗰𝗱𝗲"));
1141    }
1142
1143    #[test]
1144    fn decode_last_invalid() {
1145        let (ch, size) = utf8::decode_last(b"");
1146        assert_eq!(None, ch);
1147        assert_eq!(0, size);
1148
1149        let (ch, size) = utf8::decode_last(b"\xFF");
1150        assert_eq!(None, ch);
1151        assert_eq!(1, size);
1152
1153        let (ch, size) = utf8::decode_last(b"\xCE\xF0");
1154        assert_eq!(None, ch);
1155        assert_eq!(1, size);
1156
1157        let (ch, size) = utf8::decode_last(b"\xCE");
1158        assert_eq!(None, ch);
1159        assert_eq!(1, size);
1160
1161        let (ch, size) = utf8::decode_last(b"\xE2\x98\xF0");
1162        assert_eq!(None, ch);
1163        assert_eq!(1, size);
1164
1165        let (ch, size) = utf8::decode_last(b"\xE2\x98");
1166        assert_eq!(None, ch);
1167        assert_eq!(2, size);
1168
1169        let (ch, size) = utf8::decode_last(b"\xF0\x9D\x9D\xF0");
1170        assert_eq!(None, ch);
1171        assert_eq!(1, size);
1172
1173        let (ch, size) = utf8::decode_last(b"\xF0\x9D\x9D");
1174        assert_eq!(None, ch);
1175        assert_eq!(3, size);
1176
1177        let (ch, size) = utf8::decode_last(b"\xF0\x82\x82\xAC");
1178        assert_eq!(None, ch);
1179        assert_eq!(1, size);
1180
1181        let (ch, size) = utf8::decode_last(b"\xED\xA0\x80");
1182        assert_eq!(None, ch);
1183        assert_eq!(1, size);
1184
1185        let (ch, size) = utf8::decode_last(b"\xED\xA0");
1186        assert_eq!(None, ch);
1187        assert_eq!(1, size);
1188
1189        let (ch, size) = utf8::decode_last(b"\xED");
1190        assert_eq!(None, ch);
1191        assert_eq!(1, size);
1192
1193        let (ch, size) = utf8::decode_last(b"a\xCE");
1194        assert_eq!(None, ch);
1195        assert_eq!(1, size);
1196
1197        let (ch, size) = utf8::decode_last(b"a\xE2\x98");
1198        assert_eq!(None, ch);
1199        assert_eq!(2, size);
1200
1201        let (ch, size) = utf8::decode_last(b"a\xF0\x9D\x9C");
1202        assert_eq!(None, ch);
1203        assert_eq!(3, size);
1204    }
1205
1206    #[test]
1207    fn decode_last_lossy() {
1208        let (ch, size) = utf8::decode_last_lossy(b"");
1209        assert_eq!('\u{FFFD}', ch);
1210        assert_eq!(0, size);
1211
1212        let (ch, size) = utf8::decode_last_lossy(b"\xFF");
1213        assert_eq!('\u{FFFD}', ch);
1214        assert_eq!(1, size);
1215
1216        let (ch, size) = utf8::decode_last_lossy(b"\xCE\xF0");
1217        assert_eq!('\u{FFFD}', ch);
1218        assert_eq!(1, size);
1219
1220        let (ch, size) = utf8::decode_last_lossy(b"\xCE");
1221        assert_eq!('\u{FFFD}', ch);
1222        assert_eq!(1, size);
1223
1224        let (ch, size) = utf8::decode_last_lossy(b"\xE2\x98\xF0");
1225        assert_eq!('\u{FFFD}', ch);
1226        assert_eq!(1, size);
1227
1228        let (ch, size) = utf8::decode_last_lossy(b"\xE2\x98");
1229        assert_eq!('\u{FFFD}', ch);
1230        assert_eq!(2, size);
1231
1232        let (ch, size) = utf8::decode_last_lossy(b"\xF0\x9D\x9D\xF0");
1233        assert_eq!('\u{FFFD}', ch);
1234        assert_eq!(1, size);
1235
1236        let (ch, size) = utf8::decode_last_lossy(b"\xF0\x9D\x9D");
1237        assert_eq!('\u{FFFD}', ch);
1238        assert_eq!(3, size);
1239
1240        let (ch, size) = utf8::decode_last_lossy(b"\xF0\x82\x82\xAC");
1241        assert_eq!('\u{FFFD}', ch);
1242        assert_eq!(1, size);
1243
1244        let (ch, size) = utf8::decode_last_lossy(b"\xED\xA0\x80");
1245        assert_eq!('\u{FFFD}', ch);
1246        assert_eq!(1, size);
1247
1248        let (ch, size) = utf8::decode_last_lossy(b"\xED\xA0");
1249        assert_eq!('\u{FFFD}', ch);
1250        assert_eq!(1, size);
1251
1252        let (ch, size) = utf8::decode_last_lossy(b"\xED");
1253        assert_eq!('\u{FFFD}', ch);
1254        assert_eq!(1, size);
1255
1256        let (ch, size) = utf8::decode_last_lossy(b"a\xCE");
1257        assert_eq!('\u{FFFD}', ch);
1258        assert_eq!(1, size);
1259
1260        let (ch, size) = utf8::decode_last_lossy(b"a\xE2\x98");
1261        assert_eq!('\u{FFFD}', ch);
1262        assert_eq!(2, size);
1263
1264        let (ch, size) = utf8::decode_last_lossy(b"a\xF0\x9D\x9C");
1265        assert_eq!('\u{FFFD}', ch);
1266        assert_eq!(3, size);
1267    }
1268
1269    #[test]
1270    fn chars() {
1271        for (i, &(expected, input)) in LOSSY_TESTS.iter().enumerate() {
1272            assert_eq!(
1273                B(input).chars().collect::<Vec<char>>().len(),
1274                B(input).chars().count(),
1275                "chars.count(ith: {:?}, given: {:?})",
1276                i,
1277                input
1278            );
1279
1280            let got: String = B(input).chars().collect();
1281            assert_eq!(
1282                expected, got,
1283                "chars(ith: {:?}, given: {:?})",
1284                i, input,
1285            );
1286            let got: String =
1287                B(input).char_indices().map(|(_, _, ch)| ch).collect();
1288            assert_eq!(
1289                expected, got,
1290                "char_indices(ith: {:?}, given: {:?})",
1291                i, input,
1292            );
1293
1294            let expected: String = expected.chars().rev().collect();
1295
1296            let got: String = B(input).chars().rev().collect();
1297            assert_eq!(
1298                expected, got,
1299                "chars.rev(ith: {:?}, given: {:?})",
1300                i, input,
1301            );
1302            let got: String =
1303                B(input).char_indices().rev().map(|(_, _, ch)| ch).collect();
1304            assert_eq!(
1305                expected, got,
1306                "char_indices.rev(ith: {:?}, given: {:?})",
1307                i, input,
1308            );
1309        }
1310    }
1311
1312    #[test]
1313    fn utf8_chunks() {
1314        let mut c = utf8::Utf8Chunks { bytes: b"123\xC0" };
1315        assert_eq!(
1316            (c.next(), c.next()),
1317            (
1318                Some(utf8::Utf8Chunk {
1319                    valid: "123",
1320                    invalid: b"\xC0".as_bstr(),
1321                    incomplete: false,
1322                }),
1323                None,
1324            )
1325        );
1326
1327        let mut c = utf8::Utf8Chunks { bytes: b"123\xFF\xFF" };
1328        assert_eq!(
1329            (c.next(), c.next(), c.next()),
1330            (
1331                Some(utf8::Utf8Chunk {
1332                    valid: "123",
1333                    invalid: b"\xFF".as_bstr(),
1334                    incomplete: false,
1335                }),
1336                Some(utf8::Utf8Chunk {
1337                    valid: "",
1338                    invalid: b"\xFF".as_bstr(),
1339                    incomplete: false,
1340                }),
1341                None,
1342            )
1343        );
1344
1345        let mut c = utf8::Utf8Chunks { bytes: b"123\xD0" };
1346        assert_eq!(
1347            (c.next(), c.next()),
1348            (
1349                Some(utf8::Utf8Chunk {
1350                    valid: "123",
1351                    invalid: b"\xD0".as_bstr(),
1352                    incomplete: true,
1353                }),
1354                None,
1355            )
1356        );
1357
1358        let mut c = utf8::Utf8Chunks { bytes: b"123\xD0456" };
1359        assert_eq!(
1360            (c.next(), c.next(), c.next()),
1361            (
1362                Some(utf8::Utf8Chunk {
1363                    valid: "123",
1364                    invalid: b"\xD0".as_bstr(),
1365                    incomplete: false,
1366                }),
1367                Some(utf8::Utf8Chunk {
1368                    valid: "456",
1369                    invalid: b"".as_bstr(),
1370                    incomplete: false,
1371                }),
1372                None,
1373            )
1374        );
1375
1376        let mut c = utf8::Utf8Chunks { bytes: b"123\xE2\x98" };
1377        assert_eq!(
1378            (c.next(), c.next()),
1379            (
1380                Some(utf8::Utf8Chunk {
1381                    valid: "123",
1382                    invalid: b"\xE2\x98".as_bstr(),
1383                    incomplete: true,
1384                }),
1385                None,
1386            )
1387        );
1388
1389        let mut c = utf8::Utf8Chunks { bytes: b"123\xF4\x8F\xBF" };
1390        assert_eq!(
1391            (c.next(), c.next()),
1392            (
1393                Some(utf8::Utf8Chunk {
1394                    valid: "123",
1395                    invalid: b"\xF4\x8F\xBF".as_bstr(),
1396                    incomplete: true,
1397                }),
1398                None,
1399            )
1400        );
1401    }
1402}