encode_unicode/
traits.rs

1/* Copyright 2016-2022 Torbjørn Birch Moltu
2 * Copyright 2018 Aljoscha Meyer
3 *
4 * Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
5 * http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
6 * http://opensource.org/licenses/MIT>, at your option. This file may not be
7 * copied, modified, or distributed except according to those terms.
8 */
9
10use crate::utf8_char::Utf8Char;
11use crate::utf16_char::Utf16Char;
12use crate::utf8_iterators::*;
13use crate::utf16_iterators::*;
14use crate::decoding_iterators::*;
15use crate::error::*;
16use crate::error::Utf8ErrorKind::*;
17extern crate core;
18use core::{char, u32};
19use core::ops::{Not, Index, RangeFull};
20use core::borrow::Borrow;
21#[cfg(feature="ascii")]
22extern crate ascii;
23#[cfg(feature="ascii")]
24use ascii::AsciiStr;
25
26// TODO better docs and tests
27
28/// Methods for working with `u8`s as UTF-8 bytes.
29pub trait U8UtfExt {
30    /// How many more bytes will you need to complete this codepoint?
31    ///
32    /// # Errors
33    ///
34    /// An error is returned if the byte is not a valid start of an UTF-8
35    /// codepoint:
36    ///
37    /// * `128..192`: [`UnexpectedContinuationByte`](error/enum.Utf8ErrorKind.html#variant.UnexpectedContinuationByte)
38    /// * `245..`, `192` and `193`: [`NonUtf8Byte`](error/enum.Utf8ErrorKind.html#variant.NonUtf8Byte)  
39    fn extra_utf8_bytes(self) -> Result<usize,Utf8Error>;
40
41    /// How many more bytes will you need to complete this codepoint?
42    ///
43    /// This function assumes that the byte is a valid UTF-8 start, and might
44    /// return any value otherwise. (but the function is safe to call with any
45    /// value and will return a consistent result).
46    fn extra_utf8_bytes_unchecked(self) -> usize;
47}
48
49impl U8UtfExt for u8 {
50    #[inline]
51    fn extra_utf8_bytes(self) -> Result<usize,Utf8Error> {
52        match self {
53            0x00..=0x7f => Ok(0),
54            0xc2..=0xdf => Ok(1),
55            0xe0..=0xef => Ok(2),
56            0xf0..=0xf4 => Ok(3),
57            0xc0..=0xc1 | 0xf5..=0xff => Err(Utf8Error{ kind: NonUtf8Byte }),// too big or overlong
58            0x80..=0xbf => Err(Utf8Error{ kind: UnexpectedContinuationByte }),// following byte
59        }
60    }
61    #[inline]
62    fn extra_utf8_bytes_unchecked(self) -> usize {
63        // For fun I've optimized this function (for x86 instruction count):
64        // The most straightforward implementation, that lets the compiler do
65        // the optimizing:
66        //match self {
67        //    0b0000_0000...0b0111_1111 => 0,
68        //    0b1100_0010...0b1101_1111 => 1,
69        //    0b1110_0000...0b1110_1111 => 2,
70        //    0b1111_0000...0b1111_0100 => 3,
71        //                _             => whatever()
72        //}
73        // Using `unsafe{core::hint::unreachable_unchecked()}` for the
74        // "don't care" case is a terrible idea: while having the function
75        // non-deterministically return whatever happens to be in a register
76        // MIGHT be acceptable, it permits the function to not `ret`urn at all,
77        // but let execution fall through to whatever comes after it in the
78        // binary! (in other words completely UB).
79        // Currently unreachable_unchecked() might trap too,
80        // which is certainly not what we want.
81        // I also think `unsafe{mem::unitialized()}` is much more likely to
82        // explicitly produce whatever happens to be in a register than tell
83        // the compiler it can ignore this branch but needs to produce a value.
84        //
85        // From the bit patterns we see that for non-ASCII values the result is
86        // (number of leading set bits) - 1
87        // The standard library doesn't have a method for counting leading ones,
88        // but it has leading_zeros(), which can be used after inverting.
89        // This function can therefore be reduced to the one-liner
90        //`self.not().leading_zeros().saturating_sub(1) as usize`, which would
91        // be branchless for architectures with instructions for
92        // leading_zeros() and saturating_sub().
93
94        // Shortest version as long as ASCII-ness can be predicted: (especially
95        // if the BSR instruction which leading_zeros() uses is microcoded or
96        // doesn't exist)
97        // u8.leading_zeros() would cast to a bigger type internally, so that's
98        // free. compensating by shifting left by 24 before inverting lets the
99        // compiler know that the value passed to leading_zeros() is not zero,
100        // for which BSR's output is undefined and leading_zeros() normally has
101        // special case with a branch.
102        // Shifting one bit too many left acts as a saturating_sub(1).
103        if self<128 {0} else {((self as u32)<<25).not().leading_zeros() as usize}
104
105        // Branchless but longer version: (9 instructions)
106        // It's tempting to try (self|0x80).not().leading_zeros().wrapping_sub(1),
107        // but that produces high lengths for ASCII values 0b01xx_xxxx.
108        // If we could somehow (branchlessy) clear that bit for ASCII values...
109        // We can by masking with the value shifted right with sign extension!
110        // (any nonzero number of bits in range works)
111        //let extended = self as i8 as i32;
112        //let ascii_cleared = (extended<<25) & (extended>>25);
113        //ascii_cleared.not().leading_zeros() as usize
114
115        // cmov version: (7 instructions)
116        //(((self as u32)<<24).not().leading_zeros() as usize).saturating_sub(1)
117    }
118}
119
120
121/// Methods for working with `u16`s as UTF-16 units.
122pub trait U16UtfExt {
123    /// Will you need an extra unit to complete this codepoint?
124    ///
125    /// Returns `Err` for trailing surrogates, `Ok(true)` for leading surrogates,
126    /// and `Ok(false)` for others.
127    fn utf16_needs_extra_unit(self) -> Result<bool,Utf16FirstUnitError>;
128
129    /// Does this `u16` need another `u16` to complete a codepoint?
130    /// Returns `(self & 0xfc00) == 0xd800`
131    ///
132    /// Is basically an unchecked variant of `utf16_needs_extra_unit()`.
133    fn is_utf16_leading_surrogate(self) -> bool;
134}
135impl U16UtfExt for u16 {
136    #[inline]
137    fn utf16_needs_extra_unit(self) -> Result<bool,Utf16FirstUnitError> {
138        match self {
139            // https://en.wikipedia.org/wiki/UTF-16#U.2B10000_to_U.2B10FFFF
140            0x00_00..=0xd7_ff | 0xe0_00..=0xff_ff => Ok(false),
141            0xd8_00..=0xdb_ff => Ok(true),
142                    _         => Err(Utf16FirstUnitError)
143        }
144    }
145    #[inline]
146    fn is_utf16_leading_surrogate(self) -> bool {
147        (self & 0xfc00) == 0xd800// Clear the ten content bytes of a surrogate,
148                                 // and see if it's a leading surrogate.
149    }
150}
151
152
153
154
155/// Extension trait for `char` that adds methods for converting to and from UTF-8 or UTF-16.
156pub trait CharExt: Sized {
157    /// Get the UTF-8 representation of this codepoint.
158    ///
159    /// `Utf8Char` is to `[u8;4]` what `char` is to `u32`:
160    /// a restricted type that cannot be mutated internally.
161    fn to_utf8(self) -> Utf8Char;
162
163    /// Get the UTF-16 representation of this codepoint.
164    ///
165    /// `Utf16Char` is to `[u16;2]` what `char` is to `u32`:
166    /// a restricted type that cannot be mutated internally.
167    fn to_utf16(self) -> Utf16Char;
168
169    /// Iterate over or [read](https://doc.rust-lang.org/std/io/trait.Read.html)
170    /// the one to four bytes in the UTF-8 representation of this codepoint.
171    ///
172    /// An identical alternative to the unstable `char.encode_utf8()`.
173    /// That method somehow still exist on stable, so I have to use a different name.
174    fn iter_utf8_bytes(self) -> Utf8Iterator;
175
176    /// Iterate over the one or two units in the UTF-16 representation of this codepoint.
177    ///
178    /// An identical alternative to the unstable `char.encode_utf16()`.
179    /// That method somehow still exist on stable, so I have to use a different name.
180    fn iter_utf16_units(self) -> Utf16Iterator;
181
182
183    /// Convert this char to an UTF-8 array, and also return how many bytes of
184    /// the array are used,
185    ///
186    /// The returned array is left-aligned with unused bytes set to zero.
187    fn to_utf8_array(self) -> ([u8; 4], usize);
188
189    /// Convert this `char` to UTF-16.
190    ///
191    /// The second element is non-zero when a surrogate pair is required.
192    ///
193    /// # Examples
194    ///
195    /// ```
196    /// use encode_unicode::CharExt;
197    ///
198    /// assert_eq!('@'.to_utf16_array(), ['@' as u16, 0]);
199    /// assert_eq!('睷'.to_utf16_array(), ['睷' as u16, 0]);
200    /// assert_eq!('\u{abcde}'.to_utf16_array(), [0xda6f, 0xdcde]);
201    /// ```
202    fn to_utf16_array(self) -> [u16; 2];
203
204    /// Convert this `char` to UTF-16.
205    /// The second item is `Some` if a surrogate pair is required.
206    ///
207    /// # Examples
208    ///
209    /// ```
210    /// use encode_unicode::CharExt;
211    ///
212    /// assert_eq!('@'.to_utf16_tuple(), ('@' as u16, None));
213    /// assert_eq!('睷'.to_utf16_tuple(), ('睷' as u16, None));
214    /// assert_eq!('\u{abcde}'.to_utf16_tuple(), (0xda6f, Some(0xdcde)));
215    /// ```
216    fn to_utf16_tuple(self) -> (u16, Option<u16>);
217
218
219
220    /// Create a `char` from the start of an UTF-8 slice,
221    /// and also return how many bytes were used.
222    ///
223    /// # Errors
224    ///
225    /// Returns an `Err` if the slice is empty, doesn't start with a valid
226    /// UTF-8 sequence or is too short for the sequence.
227    ///
228    /// # Examples
229    ///
230    /// ```
231    /// use encode_unicode::CharExt;
232    /// use encode_unicode::error::Utf8ErrorKind::*;
233    ///
234    /// assert_eq!(char::from_utf8_slice_start(&[b'A', b'B', b'C']), Ok(('A',1)));
235    /// assert_eq!(char::from_utf8_slice_start(&[0xdd, 0xbb]), Ok(('\u{77b}',2)));
236    ///
237    /// assert_eq!(char::from_utf8_slice_start(&[]).unwrap_err(), TooFewBytes);
238    /// assert_eq!(char::from_utf8_slice_start(&[0xf0, 0x99]).unwrap_err(), TooFewBytes);
239    /// assert_eq!(char::from_utf8_slice_start(&[0xee, b'F', 0x80]).unwrap_err(), InterruptedSequence);
240    /// assert_eq!(char::from_utf8_slice_start(&[0xee, 0x99, 0x0f]).unwrap_err(), InterruptedSequence);
241    /// ```
242    fn from_utf8_slice_start(src: &[u8]) -> Result<(Self,usize),Utf8Error>;
243
244    /// Create a `char` from the start of an UTF-16 slice,
245    /// and also return how many units were used.
246    ///
247    /// If you want to continue after an error, continue with the next `u16` unit.
248    fn from_utf16_slice_start(src: &[u16]) -> Result<(Self,usize), Utf16SliceError>;
249
250
251    /// Convert an UTF-8 sequence as returned from `.to_utf8_array()` into a `char`
252    ///
253    /// The codepoint must start at the first byte, and leftover bytes are ignored.
254    ///
255    /// # Errors
256    ///
257    /// Returns an `Err` if the array doesn't start with a valid UTF-8 sequence.
258    ///
259    /// # Examples
260    ///
261    /// ```
262    /// use encode_unicode::CharExt;
263    /// use encode_unicode::error::Utf8ErrorKind::*;
264    ///
265    /// assert_eq!(char::from_utf8_array([b'A', 0, 0, 0]), Ok('A'));
266    /// assert_eq!(char::from_utf8_array([0xf4, 0x8b, 0xbb, 0xbb]), Ok('\u{10befb}'));
267    /// assert_eq!(char::from_utf8_array([b'A', b'B', b'C', b'D']), Ok('A'));
268    /// assert_eq!(char::from_utf8_array([0, 0, 0xcc, 0xbb]), Ok('\0'));
269    ///
270    /// assert_eq!(char::from_utf8_array([0xef, b'F', 0x80, 0x80]).unwrap_err(), InterruptedSequence);
271    /// assert_eq!(char::from_utf8_array([0xc1, 0x80, 0, 0]).unwrap_err().kind(), NonUtf8Byte);
272    /// assert_eq!(char::from_utf8_array([0xe0, 0x9a, 0xbf, 0]).unwrap_err().kind(), OverlongEncoding);
273    /// assert_eq!(char::from_utf8_array([0xf4, 0xaa, 0x99, 0x88]).unwrap_err(), TooHighCodepoint);
274    /// ```
275    fn from_utf8_array(utf8: [u8; 4]) -> Result<Self,Utf8Error>;
276
277    /// Convert a UTF-16 pair as returned from `.to_utf16_array()` into a `char`.
278    ///
279    /// The second element is ignored when not required.
280    ///
281    /// # Examples
282    ///
283    /// ```
284    /// use encode_unicode::CharExt;
285    /// use encode_unicode::error::Utf16ArrayError;
286    ///
287    /// assert_eq!(char::from_utf16_array(['x' as u16, 'y' as u16]), Ok('x'));
288    /// assert_eq!(char::from_utf16_array(['睷' as u16, 0]), Ok('睷'));
289    /// assert_eq!(char::from_utf16_array([0xda6f, 0xdcde]), Ok('\u{abcde}'));
290    /// assert_eq!(char::from_utf16_array([0xf111, 0xdbad]), Ok('\u{f111}'));
291    /// assert_eq!(char::from_utf16_array([0xdaaf, 0xdaaf]), Err(Utf16ArrayError::SecondIsNotTrailingSurrogate));
292    /// assert_eq!(char::from_utf16_array([0xdcac, 0x9000]), Err(Utf16ArrayError::FirstIsTrailingSurrogate));
293    /// ```
294    fn from_utf16_array(utf16: [u16; 2]) -> Result<Self, Utf16ArrayError>;
295
296    /// Convert a UTF-16 pair as returned from `.to_utf16_tuple()` into a `char`.
297    fn from_utf16_tuple(utf16: (u16, Option<u16>)) -> Result<Self, Utf16TupleError>;
298
299
300    /// Convert an UTF-8 sequence into a char.
301    ///
302    /// The length of the slice is taken as length of the sequence;
303    /// it should be 1,2,3 or 4.
304    ///
305    /// # Safety
306    ///
307    /// The slice must contain exactly one, valid, UTF-8 sequence.
308    ///
309    /// Passing a slice that produces an invalid codepoint is always undefined
310    /// behavior; Later checks that the codepoint is valid can be removed
311    /// by the compiler.
312    ///
313    /// # Panics
314    ///
315    /// If the slice is empty
316    unsafe fn from_utf8_exact_slice_unchecked(src: &[u8]) -> Self;
317
318    /// Convert a UTF-16 array as returned from `.to_utf16_array()` into a
319    /// `char`.
320    ///
321    /// This function is safe because it avoids creating invalid codepoints,
322    /// but the returned value might not be what one expectedd.
323    ///
324    /// # Examples
325    ///
326    /// ```
327    /// use encode_unicode::CharExt;
328    ///
329    /// // starts with a trailing surrogate - converted as if it was a valid
330    /// // surrogate pair anyway.
331    /// assert_eq!(char::from_utf16_array_unchecked([0xdbad, 0xf19e]), '\u{fb59e}');
332    /// // missing trailing surrogate - ditto
333    /// assert_eq!(char::from_utf16_array_unchecked([0xd802, 0]), '\u{10800}');
334    /// ```
335    fn from_utf16_array_unchecked(utf16: [u16;2]) -> Self;
336
337    /// Convert a UTF-16 tuple as returned from `.to_utf16_tuple()` into a `char`.
338    ///
339    /// # Safety
340    ///
341    /// If the second element is `None`, the first element must be a codepoint
342    /// in the basic multilingual pane.
343    /// (In other words, outside the range`0xd8_00..0xe0_00`.)  
344    /// Violating this results in an invalid `char` in that reserved range
345    /// being created, which is (or can easily lead to) undefined behavior.
346    unsafe fn from_utf16_tuple_unchecked(utf16: (u16, Option<u16>)) -> Self;
347
348
349    /// Produces more detailed errors than `char::from_u32()`
350    ///
351    /// # Errors
352    ///
353    /// This function will return an error if
354    ///
355    /// * the value is greater than 0x10ffff
356    /// * the value is between 0xd800 and 0xdfff (inclusive)
357    ///
358    /// # Examples
359    ///
360    /// ```
361    /// use encode_unicode::CharExt;
362    /// use encode_unicode::error::CodepointError;
363    ///
364    /// assert_eq!(char::from_u32_detailed(0x41), Ok('A'));
365    /// assert_eq!(char::from_u32_detailed(0x40_00_00), Err(CodepointError::TooHigh));
366    /// assert_eq!(char::from_u32_detailed(0xd951), Err(CodepointError::Utf16Reserved));
367    /// assert_eq!(char::from_u32_detailed(0xdddd), Err(CodepointError::Utf16Reserved));
368    /// assert_eq!(char::from_u32_detailed(0xdd), Ok('Ý'));
369    /// assert_eq!(char::from_u32_detailed(0x1f331), Ok('🌱'));
370    /// ```
371    fn from_u32_detailed(c: u32) -> Result<Self,CodepointError>;
372}
373
374
375
376impl CharExt for char {
377      /////////
378     //UTF-8//
379    /////////
380
381    fn to_utf8(self) -> Utf8Char {
382        self.into()
383    }
384    fn iter_utf8_bytes(self) -> Utf8Iterator {
385        self.to_utf8().into_iter()
386    }
387
388    fn to_utf8_array(self) -> ([u8; 4], usize) {
389        let len = self.len_utf8();
390        let mut c = self as u32;
391        if len == 1 {// ASCII, the common case
392            ([c as u8, 0, 0, 0],  1)
393        } else {
394            let mut parts = 0;// convert to 6-bit bytes
395                        parts |= c & 0x3f;  c>>=6;
396            parts<<=8;  parts |= c & 0x3f;  c>>=6;
397            parts<<=8;  parts |= c & 0x3f;  c>>=6;
398            parts<<=8;  parts |= c & 0x3f;
399            parts |= 0x80_80_80_80;// set the most significant bit
400            parts >>= 8*(4-len);// right-align bytes
401            // Now, unused bytes are zero, (which matters for Utf8Char.eq())
402            // and the rest are 0b10xx_xxxx
403
404            // set header on first byte
405            parts |= (0xff_00u32 >> len)  &  0xff;// store length
406            parts &= Not::not(1u32 << (7-len));// clear the next bit after it
407
408            (parts.to_le_bytes(), len)
409        }
410    }
411
412
413    fn from_utf8_slice_start(src: &[u8]) -> Result<(Self,usize),Utf8Error> {
414        let first = match src.first() {
415            Some(first) => *first,
416            None => return Err(Utf8Error{ kind: TooFewBytes }),
417        };
418        let bytes = match first.extra_utf8_bytes() {
419            Err(e)    => return Err(e),
420            Ok(0)     => return Ok((first as char, 1)),
421            Ok(extra) if extra >= src.len()
422                      => return Err(Utf8Error{ kind: TooFewBytes }),
423            Ok(extra) => &src[..=extra],
424        };
425        if bytes.iter().skip(1).any(|&b| (b >> 6) != 0b10 ) {
426            Err(Utf8Error{ kind: InterruptedSequence })
427        } else if overlong(bytes[0], bytes[1]) {
428            Err(Utf8Error{ kind: OverlongEncoding })
429        } else {
430            match char::from_u32_detailed(merge_nonascii_unchecked_utf8(bytes)) {
431                Ok(c) => Ok((c, bytes.len())),
432                Err(CodepointError::Utf16Reserved) => {
433                    Err(Utf8Error{ kind: Utf16ReservedCodepoint })
434                },
435                Err(CodepointError::TooHigh) => Err(Utf8Error{ kind: TooHighCodepoint }),
436            }
437        }
438    }
439
440    fn from_utf8_array(utf8: [u8; 4]) -> Result<Self,Utf8Error> {
441        let src = match utf8[0].extra_utf8_bytes() {
442            Err(error) => return Err(error),
443            Ok(0)      => return Ok(utf8[0] as char),
444            Ok(extra)  => &utf8[..=extra],
445        };
446        if src[1..].iter().any(|&b| (b >> 6) != 0b10 ) {
447            Err(Utf8Error{ kind: InterruptedSequence })
448        } else if overlong(utf8[0], utf8[1]) {
449            Err(Utf8Error{ kind: OverlongEncoding })
450        } else {
451            match char::from_u32_detailed(merge_nonascii_unchecked_utf8(src)) {
452                Ok(c) => Ok(c),
453                Err(CodepointError::Utf16Reserved) => {
454                    Err(Utf8Error{ kind: Utf16ReservedCodepoint })
455                },
456                Err(CodepointError::TooHigh) => Err(Utf8Error{ kind: TooHighCodepoint }),
457            }
458        }
459    }
460
461    unsafe fn from_utf8_exact_slice_unchecked(src: &[u8]) -> Self {
462        unsafe {
463            if src.len() == 1 {
464                src[0] as char
465            } else {
466                char::from_u32_unchecked(merge_nonascii_unchecked_utf8(src))
467            }
468        }
469    }
470
471
472
473      //////////
474     //UTF-16//
475    //////////
476
477    fn to_utf16(self) -> Utf16Char {
478        Utf16Char::from(self)
479    }
480    fn iter_utf16_units(self) -> Utf16Iterator {
481        self.to_utf16().into_iter()
482    }
483
484    fn to_utf16_array(self) -> [u16;2] {
485        let (first, second) = self.to_utf16_tuple();
486        [first, second.unwrap_or(0)]
487    }
488    fn to_utf16_tuple(self) -> (u16, Option<u16>) {
489        if self <= '\u{ffff}' {// single
490            (self as u16, None)
491        } else {// double
492            let c = self as u32 - 0x_01_00_00;
493            let high = 0x_d8_00 + (c >> 10);
494            let low = 0x_dc_00 + (c & 0x_03_ff);
495            (high as u16,  Some(low as u16))
496        }
497    }
498
499
500    fn from_utf16_slice_start(src: &[u16]) -> Result<(Self,usize), Utf16SliceError> {
501        use crate::errors::Utf16SliceError::*;
502        unsafe {match (src.get(0), src.get(1)) {
503            (Some(&u @ 0x00_00..=0xd7_ff), _) |
504            (Some(&u @ 0xe0_00..=0xff_ff), _)
505                => Ok((char::from_u32_unchecked(u as u32), 1)),
506            (Some(0xdc_00..=0xdf_ff), _) => Err(FirstIsTrailingSurrogate),
507            (None, _) => Err(EmptySlice),
508            (Some(&f @ 0xd8_00..=0xdb_ff), Some(&s @ 0xdc_00..=0xdf_ff))
509                => Ok((char::from_utf16_tuple_unchecked((f, Some(s))), 2)),
510            (Some(0xd8_00..=0xdb_ff), Some(_)) => Err(SecondIsNotTrailingSurrogate),
511            (Some(0xd8_00..=0xdb_ff), None) => Err(MissingSecond),
512        }}
513    }
514
515    fn from_utf16_array(utf16: [u16;2]) -> Result<Self, Utf16ArrayError> {
516        use crate::errors::Utf16ArrayError::*;
517        if let Some(c) = char::from_u32(utf16[0] as u32) {
518            Ok(c) // single
519        } else if utf16[0] < 0xdc_00  &&  utf16[1] & 0xfc_00 == 0xdc_00 {
520            // correct surrogate pair
521            Ok(combine_surrogates(utf16[0], utf16[1]))
522        } else if utf16[0] < 0xdc_00 {
523            Err(SecondIsNotTrailingSurrogate)
524        } else {
525            Err(FirstIsTrailingSurrogate)
526        }
527    }
528    fn from_utf16_tuple(utf16: (u16, Option<u16>)) -> Result<Self, Utf16TupleError> {
529        unsafe {
530            match Utf16Char::validate_tuple(utf16) {
531                Ok(()) => Ok(Self::from_utf16_tuple_unchecked(utf16)),
532                Err(e) => Err(e),
533            }
534        }
535    }
536
537    fn from_utf16_array_unchecked(utf16: [u16;2]) -> Self {
538        // treat any array with a surrogate value in [0] as a surrogate because
539        // combine_surrogates() is safe.
540        // `(utf16[0] & 0xf800) == 0xd80` might not be quite as fast as
541        // `utf16[1] != 0`, but avoiding the potential for UB is worth it
542        // since the conversion isn't zero-cost in either case.
543        char::from_u32(utf16[0] as u32)
544            .unwrap_or_else(|| combine_surrogates(utf16[0], utf16[1]) )
545    }
546    unsafe fn from_utf16_tuple_unchecked(utf16: (u16, Option<u16>)) -> Self {
547        unsafe {
548            match utf16.1 {
549                Some(second) => combine_surrogates(utf16.0, second),
550                None         => char::from_u32_unchecked(utf16.0 as u32)
551            }
552        }
553    }
554
555
556    fn from_u32_detailed(c: u32) -> Result<Self,CodepointError> {
557        match char::from_u32(c) {
558            Some(c) => Ok(c),
559            None if c > 0x10_ff_ff => Err(CodepointError::TooHigh),
560            None => Err(CodepointError::Utf16Reserved),
561        }
562    }
563}
564
565// Adapted from https://www.cl.cam.ac.uk/~mgk25/ucs/utf8_check.c
566fn overlong(first: u8, second: u8) -> bool {
567    if first < 0x80 {
568        false
569    } else if (first & 0xe0) == 0xc0 {
570        (first & 0xfe) == 0xc0
571    } else if (first & 0xf0) == 0xe0 {
572        first == 0xe0 && (second & 0xe0) == 0x80
573    } else {
574        first == 0xf0 && (second & 0xf0) == 0x80
575    }
576}
577
578/// Decodes the codepoint represented by a multi-byte UTF-8 sequence.
579///
580/// Does not check that the codepoint is valid,
581/// and returns `u32` because casting invalid codepoints to `char` is insta UB.
582fn merge_nonascii_unchecked_utf8(src: &[u8]) -> u32 {
583    let mut c = src[0] as u32 & (0x7f >> src.len());
584    for b in &src[1..] {
585        c = (c << 6)  |  (b & 0b0011_1111) as u32;
586    }
587    c
588}
589
590/// Create a `char` from a leading and a trailing surrogate.
591///
592/// This function is safe because it ignores the six most significant bits of
593/// each argument and always produces a codepoint in `0x01_00_00..=0x10_ff_ff`.
594fn combine_surrogates(first: u16,  second: u16) -> char {
595    unsafe {
596        let high = (first & 0x_03_ff) as u32;
597        let low = (second & 0x_03_ff) as u32;
598        let c = ((high << 10) | low) + 0x_01_00_00; // no, the constant can't be or'd in
599        char::from_u32_unchecked(c)
600    }
601}
602
603
604
605/// Adds `.utf8chars()` and `.utf16chars()` iterator constructors to `&str`.
606pub trait StrExt: AsRef<str> {
607    /// Equivalent to `.chars()` but produces `Utf8Char`s.
608    fn utf8chars(&self) -> Utf8Chars;
609    /// Equivalent to `.chars()` but produces `Utf16Char`s.
610    fn utf16chars(&self) -> Utf16Chars;
611    /// Equivalent to `.char_indices()` but produces `Utf8Char`s.
612    fn utf8char_indices(&self) -> Utf8CharIndices;
613    /// Equivalent to `.char_indices()` but produces `Utf16Char`s.
614    fn utf16char_indices(&self) -> Utf16CharIndices;
615}
616
617impl StrExt for str {
618    fn utf8chars(&self) -> Utf8Chars {
619        Utf8Chars::from(self)
620    }
621    fn utf16chars(&self) -> Utf16Chars {
622        Utf16Chars::from(self)
623    }
624    fn utf8char_indices(&self) -> Utf8CharIndices {
625        Utf8CharIndices::from(self)
626    }
627    fn utf16char_indices(&self) -> Utf16CharIndices {
628        Utf16CharIndices::from(self)
629    }
630}
631
632#[cfg(feature="ascii")]
633impl StrExt for AsciiStr {
634    fn utf8chars(&self) -> Utf8Chars {
635        Utf8Chars::from(self.as_str())
636    }
637    fn utf16chars(&self) -> Utf16Chars {
638        Utf16Chars::from(self.as_str())
639    }
640    fn utf8char_indices(&self) -> Utf8CharIndices {
641        Utf8CharIndices::from(self.as_str())
642    }
643    fn utf16char_indices(&self) -> Utf16CharIndices {
644        Utf16CharIndices::from(self.as_str())
645    }
646}
647
648
649
650/// Iterator methods that convert between `u8`s and `Utf8Char` or `u16`s and `Utf16Char`
651///
652/// All the iterator adapters also accept iterators that produce references of
653/// the type they convert from.
654pub trait IterExt: Iterator+Sized {
655    /// Converts an iterator of `Utf8Char`s or `&Utf8Char`s to an iterator of
656    /// `u8`s.
657    ///
658    /// Has the same effect as `.flat_map()` or `.flatten()`, but the returned
659    /// iterator is ~40% faster.
660    ///
661    /// The iterator also implements `Read`
662    /// (when the `std` feature isn't disabled).  
663    /// Reading will never produce an error, and calls to `.read()` and `.next()`
664    /// can be mixed.
665    ///
666    /// The exact number of bytes cannot be known in advance, but `size_hint()`
667    /// gives the possible range.
668    /// (min: all remaining characters are ASCII, max: all require four bytes)
669    ///
670    /// # Examples
671    ///
672    /// From iterator of values:
673    ///
674    /// ```
675    /// use encode_unicode::{IterExt, StrExt};
676    ///
677    /// let iterator = "foo".utf8chars();
678    /// let mut bytes = [0; 4];
679    /// iterator.to_bytes().zip(&mut bytes).for_each(|(b,dst)| *dst = b );
680    /// assert_eq!(&bytes, b"foo\0");
681    /// ```
682    ///
683    /// From iterator of references:
684    ///
685    #[cfg_attr(feature="std", doc=" ```")]
686    #[cfg_attr(not(feature="std"), doc=" ```no_compile")]
687    /// use encode_unicode::{IterExt, StrExt, Utf8Char};
688    ///
689    /// let chars: Vec<Utf8Char> = "💣 bomb 💣".utf8chars().collect();
690    /// let bytes: Vec<u8> = chars.iter().to_bytes().collect();
691    /// let flat_map: Vec<u8> = chars.iter().cloned().flatten().collect();
692    /// assert_eq!(bytes, flat_map);
693    /// ```
694    ///
695    /// `Read`ing from it:
696    ///
697    #[cfg_attr(feature="std", doc=" ```")]
698    #[cfg_attr(not(feature="std"), doc=" ```no_compile")]
699    /// use encode_unicode::{IterExt, StrExt};
700    /// use std::io::Read;
701    ///
702    /// let s = "Ååh‽";
703    /// assert_eq!(s.len(), 8);
704    /// let mut buf = [b'E'; 9];
705    /// let mut reader = s.utf8chars().to_bytes();
706    /// assert_eq!(reader.read(&mut buf[..]).unwrap(), 8);
707    /// assert_eq!(reader.read(&mut buf[..]).unwrap(), 0);
708    /// assert_eq!(&buf[..8], s.as_bytes());
709    /// assert_eq!(buf[8], b'E');
710    /// ```
711    fn to_bytes(self) -> Utf8CharSplitter<Self::Item,Self> where Self::Item: Borrow<Utf8Char>;
712
713    /// Converts an iterator of `Utf16Char` (or `&Utf16Char`) to an iterator of
714    /// `u16`s.
715    ///
716    /// Has the same effect as `.flat_map()` or `.flatten()`, but the returned
717    /// iterator is about twice as fast.
718    ///
719    /// The exact number of units cannot be known in advance, but `size_hint()`
720    /// gives the possible range.
721    ///
722    /// # Examples
723    ///
724    /// From iterator of values:
725    ///
726    /// ```
727    /// use encode_unicode::{IterExt, StrExt};
728    ///
729    /// let iterator = "foo".utf16chars();
730    /// let mut units = [0; 4];
731    /// iterator.to_units().zip(&mut units).for_each(|(u,dst)| *dst = u );
732    ///
733    /// assert_eq!(units, ['f' as u16, 'o' as u16, 'o' as u16, 0]);
734    /// ```
735    ///
736    /// From iterator of references:
737    ///
738    #[cfg_attr(feature="std", doc=" ```")]
739    #[cfg_attr(not(feature="std"), doc=" ```no_compile")]
740    /// use encode_unicode::{IterExt, StrExt, Utf16Char};
741    ///
742    /// // (💣 takes two units)
743    /// let chars: Vec<Utf16Char> = "💣 bomb 💣".utf16chars().collect();
744    /// let units: Vec<u16> = chars.iter().to_units().collect();
745    /// let flat_map: Vec<u16> = chars.iter().flat_map(|u16c| *u16c ).collect();
746    ///
747    /// assert_eq!(units, flat_map);
748    /// ```
749    fn to_units(self) -> Utf16CharSplitter<Self::Item,Self> where Self::Item: Borrow<Utf16Char>;
750
751    /// Decodes bytes as UTF-8 and groups them into `Utf8Char`s
752    ///
753    /// When errors (invalid values or sequences) are encountered,
754    /// it continues with the byte right after the start of the error sequence.  
755    /// This is neither the most intelligent choiche (sometimes it is guaranteed to
756    ///  produce another error), nor the easiest to implement, but I believe it to
757    /// be the most predictable.
758    /// It also means that ASCII characters are never hidden by errors.
759    ///
760    /// # Examples
761    ///
762    /// Replace all errors with u+FFFD REPLACEMENT_CHARACTER:
763    /// ```
764    /// use encode_unicode::{Utf8Char, IterExt};
765    ///
766    /// let mut buf = [b'\0'; 255];
767    /// let len = b"foo\xCFbar".iter()
768    ///     .to_utf8chars()
769    ///     .flat_map(|r| r.unwrap_or(Utf8Char::from('\u{FFFD}')) )
770    ///     .zip(&mut buf[..])
771    ///     .map(|(byte, dst)| *dst = byte )
772    ///     .count();
773    ///
774    /// assert_eq!(&buf[..len], "foo\u{FFFD}bar".as_bytes());
775    /// ```
776    ///
777    /// Collect everything up until the first error into a string:
778    #[cfg_attr(feature="std", doc=" ```")]
779    #[cfg_attr(not(feature="std"), doc=" ```no_compile")]
780    /// use encode_unicode::iterator::Utf8CharMerger;
781    /// let mut good = String::new();
782    /// for r in Utf8CharMerger::from(b"foo\xcc\xbbbar\xcc\xddbaz") {
783    ///     if let Ok(uc) = r {
784    ///         good.push_str(uc.as_str());
785    ///     } else {
786    ///         break;
787    ///     }
788    /// }
789    /// assert_eq!(good, "foo̻bar");
790    /// ```
791    ///
792    /// Abort decoding on error:
793    #[cfg_attr(feature="std", doc=" ```")]
794    #[cfg_attr(not(feature="std"), doc=" ```no_compile")]
795    /// use encode_unicode::{IterExt, Utf8Char};
796    /// use encode_unicode::error::{Utf8Error, Utf8ErrorKind};
797    ///
798    /// let result = b"ab\0\xe0\xbc\xa9 \xf3\x80\x77".iter()
799    ///     .to_utf8chars()
800    ///     .collect::<Result<String,Utf8Error>>();
801    ///
802    /// assert_eq!(result.unwrap_err().kind(), Utf8ErrorKind::InterruptedSequence);
803    /// ```
804    fn to_utf8chars(self) -> Utf8CharMerger<Self::Item,Self> where Self::Item: Borrow<u8>;
805
806    /// Decodes bytes as UTF-16 and groups them into `Utf16Char`s
807    ///
808    /// When errors (unmatched leading surrogates or unexpected trailing surrogates)
809    /// are encountered, an error is produced for every unit.
810    ///
811    /// # Examples
812    ///
813    /// Replace errors with '�':
814    #[cfg_attr(feature="std", doc=" ```")]
815    #[cfg_attr(not(feature="std"), doc=" ```no_compile")]
816    /// use encode_unicode::{IterExt, Utf16Char};
817    ///
818    /// let slice = &['a' as u16, 0xdf00, 0xd83c, 0xdca0][..];
819    /// let string = slice.iter()
820    ///     .to_utf16chars()
821    ///     .map(|r| r.unwrap_or(Utf16Char::from('\u{fffd}')) ) // REPLACEMENT_CHARACTER
822    ///     .collect::<String>();
823    ///
824    /// assert_eq!(string, "a�🂠");
825    /// ```
826    ///
827    /// ```
828    /// use encode_unicode::{IterExt, Utf16Char};
829    /// use encode_unicode::error::Utf16PairError::*;
830    ///
831    /// let slice = [0xdcba, 0xdeff, 0xd8be, 0xdeee, 'Y' as u16, 0xdab1, 0xdab1];
832    /// let mut iter = slice.iter().to_utf16chars();
833    /// assert_eq!(iter.size_hint(), (3, Some(7)));
834    /// assert_eq!(iter.next(), Some(Err(UnexpectedTrailingSurrogate)));
835    /// assert_eq!(iter.next(), Some(Err(UnexpectedTrailingSurrogate)));
836    /// assert_eq!(iter.next(), Some(Ok(Utf16Char::from('\u{3faee}'))));
837    /// assert_eq!(iter.next(), Some(Ok(Utf16Char::from('Y'))));
838    /// assert_eq!(iter.next(), Some(Err(UnmatchedLeadingSurrogate)));
839    /// assert_eq!(iter.next(), Some(Err(Incomplete)));
840    /// assert_eq!(iter.into_remaining_units().next(), None);
841    /// ```
842    ///
843    /// Search for a codepoint and return the codepoint index of the first match:
844    /// ```
845    /// use encode_unicode::{IterExt, Utf16Char};
846    ///
847    /// let position = [0xd875, 0xdd4f, '≈' as u16, '2' as u16].iter()
848    ///     .to_utf16chars()
849    ///     .position(|r| r == Ok(Utf16Char::from('≈')) );
850    ///
851    /// assert_eq!(position, Some(1));
852    /// ```
853    fn to_utf16chars(self) -> Utf16CharMerger<Self::Item,Self> where Self::Item: Borrow<u16>;
854}
855
856impl<I:Iterator> IterExt for I {
857    fn to_bytes(self) -> Utf8CharSplitter<Self::Item,Self> where Self::Item: Borrow<Utf8Char> {
858        Utf8CharSplitter::from(self)
859    }
860    fn to_units(self) -> Utf16CharSplitter<Self::Item,Self> where Self::Item: Borrow<Utf16Char> {
861        Utf16CharSplitter::from(self)
862    }
863    fn to_utf8chars(self) -> Utf8CharMerger<Self::Item,Self> where Self::Item: Borrow<u8> {
864        Utf8CharMerger::from(self)
865    }
866    fn to_utf16chars(self) -> Utf16CharMerger<Self::Item,Self> where Self::Item: Borrow<u16> {
867        Utf16CharMerger::from(self)
868    }
869}
870
871
872/// Methods for iterating over `u8` and `u16` slices as UTF-8 or UTF-16 characters.
873///
874/// The iterators are slightly faster than the similar methods in [`IterExt`](trait.IterExt.html)
875/// because they con "push back" items for free after errors and don't need a
876/// separate buffer that must be checked on every call to `.next()`.
877pub trait SliceExt: Index<RangeFull> {
878    /// Decode `u8` slices as UTF-8 and iterate over the codepoints as `Utf8Char`s,
879    ///
880    /// # Examples
881    ///
882    /// Get the index and error type of the first error:
883    #[cfg_attr(feature="std", doc=" ```")]
884    #[cfg_attr(not(feature="std"), doc=" ```no_compile")]
885    /// use encode_unicode::{SliceExt, Utf8Char, error::Utf8ErrorKind};
886    ///
887    /// let slice = b"ab\0\xe0\xbc\xa9 \xf3\x80\x77";
888    /// let result = slice.utf8char_indices()
889    ///     .map(|(offset,r,length)| r.map_err(|e| (offset,e.kind(),length) ) )
890    ///     .collect::<Result<String,(usize,Utf8ErrorKind,usize)>>();
891    ///
892    /// assert_eq!(result, Err((7, Utf8ErrorKind::TooFewBytes, 1)));
893    /// ```
894    ///
895    /// ```
896    /// use encode_unicode::{SliceExt, Utf8Char};
897    /// use std::error::Error;
898    ///
899    /// let slice = b"\xf0\xbf\xbf\xbfXY\xdd\xbb\xe1\x80\x99quux123";
900    /// let mut fixed_size = [Utf8Char::default(); 8];
901    /// for (cp_i, (byte_index, r, _)) in slice.utf8char_indices().enumerate().take(8) {
902    ///     match r {
903    ///         Ok(u8c) => fixed_size[cp_i] = u8c,
904    ///         Err(e) => panic!("Invalid codepoint at index {} ({})", cp_i, e),
905    ///     }
906    /// }
907    /// let chars = ['\u{3ffff}', 'X', 'Y', '\u{77b}', '\u{1019}', 'q', 'u', 'u'];
908    /// assert_eq!(fixed_size, chars);
909    /// ```
910    ///
911    #[cfg_attr(feature="std", doc=" ```")]
912    #[cfg_attr(not(feature="std"), doc=" ```no_compile")]
913    /// use encode_unicode::{SliceExt, Utf8Char, error::Utf8ErrorKind};
914    ///
915    /// let bytes = b"\xfa-\xf4\x8f\xee\xa1\x8f-\xed\xa9\x87\xf0\xcc\xbb";
916    /// let mut errors = Vec::new();
917    /// let mut lengths = Vec::new();
918    /// let mut string = String::new();
919    /// for (offset,result,length) in bytes.utf8char_indices() {
920    ///     lengths.push((offset,length));
921    ///     let c = result.unwrap_or_else(|error| {
922    ///         errors.push((offset, error.kind()));
923    ///         Utf8Char::from('\u{fffd}') // replacement character
924    ///     });
925    ///     string.push_str(c.as_str());
926    /// }
927    ///
928    /// assert_eq!(string, "�-��\u{e84f}-����\u{33b}");
929    /// assert_eq!(lengths, [(0,1), (1,1), (2,1), (3,1), (4,3), (7,1),
930    ///                      (8,1), (9,1), (10,1), (11,1), (12,2)]);
931    /// assert_eq!(errors, [
932    ///     ( 0, Utf8ErrorKind::NonUtf8Byte),
933    ///     ( 2, Utf8ErrorKind::InterruptedSequence),
934    ///     ( 3, Utf8ErrorKind::UnexpectedContinuationByte),
935    ///     ( 8, Utf8ErrorKind::Utf16ReservedCodepoint),
936    ///     ( 9, Utf8ErrorKind::UnexpectedContinuationByte),
937    ///     (10, Utf8ErrorKind::UnexpectedContinuationByte),
938    ///     (11, Utf8ErrorKind::TooFewBytes), // (but it was not the last element returned!)
939    /// ]);
940    /// ```
941    fn utf8char_indices(&self) -> Utf8CharDecoder where Self::Output: Borrow<[u8]>;
942
943
944    /// Decode `u16` slices as UTF-16 and iterate over the codepoints as `Utf16Char`s,
945    ///
946    /// The iterator produces `(usize,Result<Utf16Char,Utf16Error>,usize)`,
947    /// and the slice is validated as you go.
948    ///
949    /// The first `usize` contains the offset from the start of the slice and
950    /// the last `usize` contains the length of the codepoint or error.
951    /// The length is either 1 or 2, and always 1 for errors.
952    ///
953    /// # Examples
954    ///
955    #[cfg_attr(feature="std", doc=" ```")]
956    #[cfg_attr(not(feature="std"), doc=" ```no_compile")]
957    /// use encode_unicode::{SliceExt, Utf8Char};
958    ///
959    /// let slice = &['a' as u16, 0xdf00, 0xd83c, 0xdca0][..];
960    /// let mut errors = Vec::new();
961    /// let string = slice.utf16char_indices().map(|(offset,r,_)| match r {
962    ///     Ok(u16c) => Utf8Char::from(u16c),
963    ///     Err(_) => {
964    ///         errors.push(offset);
965    ///         Utf8Char::from('\u{fffd}') // REPLACEMENT_CHARACTER
966    ///     }
967    /// }).collect::<String>();
968    ///
969    /// assert_eq!(string, "a�🂠");
970    /// assert_eq!(errors, [1]);
971    /// ```
972    ///
973    /// Search for a codepoint and return its unit and codepoint index.
974    /// ```
975    /// use encode_unicode::{SliceExt, Utf16Char};
976    ///
977    /// let slice = [0xd875,/*'𝕏'*/ 0xdd4f, '≈' as u16, '2' as u16];
978    /// let position = slice.utf16char_indices()
979    ///     .enumerate()
980    ///     .find(|&(_,(_,r,_))| r == Ok(Utf16Char::from('≈')) )
981    ///     .map(|(codepoint, (offset, _, _))| (codepoint, offset) );
982    ///
983    /// assert_eq!(position, Some((1,2)));
984    /// ```
985    ///
986    /// Error types:
987    /// ```
988    /// use encode_unicode::{SliceExt, Utf16Char};
989    /// use encode_unicode::error::Utf16PairError::*;
990    ///
991    /// let slice = [0xdcba, 0xdeff, 0xd8be, 0xdeee, 'λ' as u16, 0xdab1, 0xdab1];
992    /// let mut iter = slice.utf16char_indices();
993    /// assert_eq!(iter.next(), Some((0, Err(UnexpectedTrailingSurrogate), 1)));
994    /// assert_eq!(iter.next(), Some((1, Err(UnexpectedTrailingSurrogate), 1)));
995    /// assert_eq!(iter.next(), Some((2, Ok(Utf16Char::from('\u{3faee}')), 2)));
996    /// assert_eq!(iter.next(), Some((4, Ok(Utf16Char::from('λ')), 1)));
997    /// assert_eq!(iter.next(), Some((5, Err(UnmatchedLeadingSurrogate), 1)));
998    /// assert_eq!(iter.next(), Some((6, Err(Incomplete), 1)));
999    /// assert_eq!(iter.next(), None);
1000    /// assert_eq!(iter.as_slice(), [])
1001    /// ```
1002    fn utf16char_indices(&self) -> Utf16CharDecoder where Self::Output: Borrow<[u16]>;
1003}
1004
1005impl<S: ?Sized+Index<RangeFull>> SliceExt for S {
1006    fn utf8char_indices(&self) -> Utf8CharDecoder where Self::Output: Borrow<[u8]> {
1007        Utf8CharDecoder::from(self[..].borrow())
1008    }
1009    fn utf16char_indices(&self) -> Utf16CharDecoder where Self::Output: Borrow<[u16]> {
1010        Utf16CharDecoder::from(self[..].borrow())
1011    }
1012}