encode_unicode/
utf16_char.rs

1/* Copyright 2016 The encode_unicode Developers
2 *
3 * Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4 * http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5 * http://opensource.org/licenses/MIT>, at your option. This file may not be
6 * copied, modified, or distributed except according to those terms.
7 */
8
9use utf16_iterators::Utf16Iterator;
10use traits::{CharExt, U16UtfExt};
11use utf8_char::Utf8Char;
12use errors::{InvalidUtf16Slice, InvalidUtf16Array, InvalidUtf16Tuple};
13use errors::{NonBMPError, EmptyStrError, FromStrError};
14extern crate core;
15use self::core::{hash,fmt};
16use self::core::cmp::Ordering;
17use self::core::borrow::Borrow;
18use self::core::ops::Deref;
19use self::core::str::FromStr;
20#[cfg(feature="std")]
21use self::core::iter::FromIterator;
22#[cfg(feature="std")]
23#[allow(deprecated)]
24use std::ascii::AsciiExt;
25#[cfg(feature="ascii")]
26use self::core::char;
27#[cfg(feature="ascii")]
28extern crate ascii;
29#[cfg(feature="ascii")]
30use self::ascii::{AsciiChar,ToAsciiChar,ToAsciiCharError};
31
32
33// I don't think there is any good default value for char, but char does.
34#[derive(Default)]
35// char doesn't do anything more advanced than u32 for Eq/Ord, so we shouldn't either.
36// When it's a single unit, the second is zero, so Eq works.
37// #[derive(Ord)] however, breaks on surrogate pairs.
38#[derive(PartialEq,Eq)]
39#[derive(Clone,Copy)]
40
41
42/// An unicode codepoint stored as UTF-16.
43///
44/// It can be borrowed as an `u16` slice, and has the same size as `char`.
45pub struct Utf16Char {
46    units: [u16; 2],
47}
48
49
50  /////////////////////
51 //conversion traits//
52/////////////////////
53impl FromStr for Utf16Char {
54    type Err = FromStrError;
55    /// Create an `Utf16Char` from a string slice.
56    /// The string must contain exactly one codepoint.
57    ///
58    /// # Examples
59    ///
60    /// ```
61    /// use encode_unicode::error::FromStrError::*;
62    /// use encode_unicode::Utf16Char;
63    /// use std::str::FromStr;
64    ///
65    /// assert_eq!(Utf16Char::from_str("a"), Ok(Utf16Char::from('a')));
66    /// assert_eq!(Utf16Char::from_str("🂠"), Ok(Utf16Char::from('🂠')));
67    /// assert_eq!(Utf16Char::from_str(""), Err(Empty));
68    /// assert_eq!(Utf16Char::from_str("ab"), Err(MultipleCodepoints));
69    /// assert_eq!(Utf16Char::from_str("é"), Err(MultipleCodepoints));// 'e'+u301 combining mark
70    /// ```
71    fn from_str(s: &str) -> Result<Self, FromStrError> {
72        match Utf16Char::from_str_start(s) {
73            Ok((u16c,bytes)) if bytes == s.len() => Ok(u16c),
74            Ok((_,_)) => Err(FromStrError::MultipleCodepoints),
75            Err(EmptyStrError) => Err(FromStrError::Empty),
76        }
77    }
78}
79impl From<char> for Utf16Char {
80    fn from(c: char) -> Self {
81        let (first, second) = c.to_utf16_tuple();
82        Utf16Char{ units: [first, second.unwrap_or(0)] }
83    }
84}
85impl From<Utf8Char> for Utf16Char {
86    fn from(utf8: Utf8Char) -> Utf16Char {
87        let (b, utf8_len) = utf8.to_array();
88        match utf8_len {
89            1 => Utf16Char{ units: [b[0] as u16, 0] },
90            4 => {// need surrogate
91                let mut first = 0xd800 - (0x01_00_00u32 >> 10) as u16;
92                first += (b[0] as u16 & 0x07) << 8;
93                first += (b[1] as u16 & 0x3f) << 2;
94                first += (b[2] as u16 & 0x30) >> 4;
95                let mut second = 0xdc00;
96                second |= (b[2] as u16 & 0x0f) << 6;
97                second |=  b[3] as u16 & 0x3f;
98                Utf16Char{ units: [first, second] }
99            },
100            _ => { // 2 or 3
101                let mut unit = ((b[0] as u16 & 0x1f) << 6) | (b[1] as u16 & 0x3f);
102                if utf8_len == 3 {
103                    unit = (unit << 6) | (b[2] as u16 & 0x3f);
104                }
105                Utf16Char{ units: [unit, 0] }
106            },
107        }
108    }
109}
110impl From<Utf16Char> for char {
111    fn from(uc: Utf16Char) -> char {
112        char::from_utf16_array_unchecked(uc.to_array())
113    }
114}
115impl IntoIterator for Utf16Char {
116    type Item=u16;
117    type IntoIter=Utf16Iterator;
118    /// Iterate over the units.
119    fn into_iter(self) -> Utf16Iterator {
120        Utf16Iterator::from(self)
121    }
122}
123
124#[cfg(feature="std")]
125impl Extend<Utf16Char> for Vec<u16> {
126    fn extend<I:IntoIterator<Item=Utf16Char>>(&mut self,  iter: I) {
127        let iter = iter.into_iter();
128        self.reserve(iter.size_hint().0);
129        for u16c in iter {
130            self.push(u16c.units[0]);
131            if u16c.units[1] != 0 {
132                self.push(u16c.units[1]);
133            }
134        }
135    }
136}
137#[cfg(feature="std")]
138impl<'a> Extend<&'a Utf16Char> for Vec<u16> {
139    fn extend<I:IntoIterator<Item=&'a Utf16Char>>(&mut self,  iter: I) {
140        self.extend(iter.into_iter().cloned())
141    }
142}
143#[cfg(feature="std")]
144impl FromIterator<Utf16Char> for Vec<u16> {
145    fn from_iter<I:IntoIterator<Item=Utf16Char>>(iter: I) -> Self {
146        let mut vec = Vec::new();
147        vec.extend(iter);
148        return vec;
149    }
150}
151#[cfg(feature="std")]
152impl<'a> FromIterator<&'a Utf16Char> for Vec<u16> {
153    fn from_iter<I:IntoIterator<Item=&'a Utf16Char>>(iter: I) -> Self {
154        Self::from_iter(iter.into_iter().cloned())
155    }
156}
157
158#[cfg(feature="std")]
159impl Extend<Utf16Char> for String {
160    fn extend<I:IntoIterator<Item=Utf16Char>>(&mut self,  iter: I) {
161        self.extend(iter.into_iter().map(|u16c| Utf8Char::from(u16c) ));
162    }
163}
164#[cfg(feature="std")]
165impl<'a> Extend<&'a Utf16Char> for String {
166    fn extend<I:IntoIterator<Item=&'a Utf16Char>>(&mut self,  iter: I) {
167        self.extend(iter.into_iter().cloned());
168    }
169}
170#[cfg(feature="std")]
171impl FromIterator<Utf16Char> for String {
172    fn from_iter<I:IntoIterator<Item=Utf16Char>>(iter: I) -> Self {
173        let mut s = String::new();
174        s.extend(iter);
175        return s;
176    }
177}
178#[cfg(feature="std")]
179impl<'a> FromIterator<&'a Utf16Char> for String {
180    fn from_iter<I:IntoIterator<Item=&'a Utf16Char>>(iter: I) -> Self {
181        Self::from_iter(iter.into_iter().cloned())
182    }
183}
184
185
186  /////////////////
187 //getter traits//
188/////////////////
189impl AsRef<[u16]> for Utf16Char {
190    #[inline]
191    fn as_ref(&self) -> &[u16] {
192        &self.units[..self.len()]
193    }
194}
195impl Borrow<[u16]> for Utf16Char {
196    #[inline]
197    fn borrow(&self) -> &[u16] {
198        self.as_ref()
199    }
200}
201impl Deref for Utf16Char {
202    type Target = [u16];
203    #[inline]
204    fn deref(&self) -> &[u16] {
205        self.as_ref()
206    }
207}
208
209
210  ////////////////
211 //ascii traits//
212////////////////
213#[cfg(feature="std")]
214#[allow(deprecated)]
215impl AsciiExt for Utf16Char {
216    type Owned = Self;
217    fn is_ascii(&self) -> bool {
218        self.units[0] < 128
219    }
220    fn eq_ignore_ascii_case(&self,  other: &Self) -> bool {
221        self.to_ascii_lowercase() == other.to_ascii_lowercase()
222    }
223    fn to_ascii_uppercase(&self) -> Self {
224        let n = self.units[0].wrapping_sub(b'a' as u16);
225        if n < 26 {Utf16Char{ units: [n+b'A' as u16, 0] }}
226        else      {*self}
227    }
228    fn to_ascii_lowercase(&self) -> Self {
229        let n = self.units[0].wrapping_sub(b'A' as u16);
230        if n < 26 {Utf16Char{ units: [n+b'a' as u16, 0] }}
231        else      {*self}
232    }
233    fn make_ascii_uppercase(&mut self) {
234        *self = self.to_ascii_uppercase()
235    }
236    fn make_ascii_lowercase(&mut self) {
237        *self = self.to_ascii_lowercase();
238    }
239}
240
241#[cfg(feature="ascii")]
242/// Requires the feature "ascii".
243impl From<AsciiChar> for Utf16Char {
244    #[inline]
245    fn from(ac: AsciiChar) -> Self {
246        Utf16Char{ units: [ac.as_byte() as u16, 0] }
247    }
248}
249#[cfg(feature="ascii")]
250/// Requires the feature "ascii".
251impl ToAsciiChar for Utf16Char {
252    #[inline]
253    fn to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError> {
254        // ToAsciiCHar is not implemented for u16 in ascii 0.9.0
255        if self.is_ascii() {self.units[0] as u8} else {255}.to_ascii_char()
256    }
257    #[inline]
258    unsafe fn to_ascii_char_unchecked(self) -> AsciiChar {
259        (self.units[0] as u8).to_ascii_char_unchecked()
260    }
261}
262
263
264  /////////////////////////////////////////////////////////
265 //Genaral traits that cannot be derived to emulate char//
266/////////////////////////////////////////////////////////
267impl hash::Hash for Utf16Char {
268    fn hash<H : hash::Hasher>(&self,  state: &mut H) {
269        self.to_char().hash(state);
270    }
271}
272impl fmt::Debug for Utf16Char {
273    fn fmt(&self,  fmtr: &mut fmt::Formatter) -> fmt::Result {
274        fmt::Debug::fmt(&self.to_char(), fmtr)
275    }
276}
277impl fmt::Display for Utf16Char {
278    fn fmt(&self,  fmtr: &mut fmt::Formatter) -> fmt::Result {
279        fmt::Display::fmt(&Utf8Char::from(*self), fmtr)
280    }
281}
282// Cannot derive these impls because two-unit characters must always compare
283// greater than one-unit ones.
284impl PartialOrd for Utf16Char {
285    #[inline]
286    fn partial_cmp(&self,  rhs: &Self) -> Option<Ordering> {
287        Some(self.cmp(rhs))
288    }
289}
290impl Ord for Utf16Char {
291    #[inline]
292    fn cmp(&self,  rhs: &Self) -> Ordering {
293        // Shift the first unit by 0xd if surrogate, and 0 otherwise.
294        // This ensures surrogates are always greater than 0xffff, and
295        // that the second unit only affect the result when the first are equal.
296        // Multiplying by a constant factor isn't enough because that factor
297        // would have to be greater than 1023 and smaller than 5.5.
298        // This transformation is less complicated than combine_surrogates().
299        let lhs = (self.units[0] as u32, self.units[1] as u32);
300        let rhs = (rhs.units[0] as u32, rhs.units[1] as u32);
301        let lhs = (lhs.0 << (lhs.1 >> 12)) + lhs.1;
302        let rhs = (rhs.0 << (rhs.1 >> 12)) + rhs.1;
303        lhs.cmp(&rhs)
304    }
305}
306
307
308  ////////////////////////////////
309 //Comparisons with other types//
310////////////////////////////////
311impl PartialEq<char> for Utf16Char {
312    fn eq(&self,  u32c: &char) -> bool {
313        *self == Utf16Char::from(*u32c)
314    }
315}
316impl PartialEq<Utf16Char> for char {
317    fn eq(&self,  u16c: &Utf16Char) -> bool {
318        Utf16Char::from(*self) == *u16c
319    }
320}
321impl PartialOrd<char> for Utf16Char {
322    fn partial_cmp(&self,  u32c: &char) -> Option<Ordering> {
323        self.partial_cmp(&Utf16Char::from(*u32c))
324    }
325}
326impl PartialOrd<Utf16Char> for char {
327    fn partial_cmp(&self,  u16c: &Utf16Char) -> Option<Ordering> {
328        Utf16Char::from(*self).partial_cmp(u16c)
329    }
330}
331
332impl PartialEq<Utf8Char> for Utf16Char {
333    fn eq(&self,  u8c: &Utf8Char) -> bool {
334        *self == Utf16Char::from(*u8c)
335    }
336}
337impl PartialOrd<Utf8Char> for Utf16Char {
338    fn partial_cmp(&self,  u8c: &Utf8Char) -> Option<Ordering> {
339        self.partial_cmp(&Utf16Char::from(*u8c))
340    }
341}
342// The other direction is implemented in utf8_char.rs
343
344/// Only considers the unit equal if the codepoint of the `Utf16Char` is not
345/// made up of a surrogate pair.
346///
347/// There is no impl in the opposite direction, as this should only be used to
348/// compare `Utf16Char`s against constants.
349///
350/// # Examples
351///
352/// ```
353/// # use encode_unicode::Utf16Char;
354/// assert!(Utf16Char::from('6') == b'6' as u16);
355/// assert!(Utf16Char::from('\u{FFFF}') == 0xffff_u16);
356/// assert!(Utf16Char::from_tuple((0xd876, Some(0xdef9))).unwrap() != 0xd876_u16);
357/// ```
358impl PartialEq<u16> for Utf16Char {
359    fn eq(&self,  unit: &u16) -> bool {
360        self.units[0] == *unit  &&  self.units[1] == 0
361    }
362}
363/// Only considers the byte equal if the codepoint of the `Utf16Char` is <= U+FF.
364///
365/// # Examples
366///
367/// ```
368/// # use encode_unicode::Utf16Char;
369/// assert!(Utf16Char::from('6') == b'6');
370/// assert!(Utf16Char::from('\u{00FF}') == b'\xff');
371/// assert!(Utf16Char::from('\u{0100}') != b'\0');
372/// ```
373impl PartialEq<u8> for Utf16Char {
374    fn eq(&self,  byte: &u8) -> bool {
375        self.units[0] == *byte as u16
376    }
377}
378#[cfg(feature = "ascii")]
379/// `Utf16Char`s that are not ASCII never compare equal.
380impl PartialEq<AsciiChar> for Utf16Char {
381    #[inline]
382    fn eq(&self,  ascii: &AsciiChar) -> bool {
383        self.units[0] == *ascii as u16
384    }
385}
386#[cfg(feature = "ascii")]
387/// `Utf16Char`s that are not ASCII never compare equal.
388impl PartialEq<Utf16Char> for AsciiChar {
389    #[inline]
390    fn eq(&self,  u16c: &Utf16Char) -> bool {
391        *self as u16 == u16c.units[0]
392    }
393}
394#[cfg(feature = "ascii")]
395/// `Utf16Char`s that are not ASCII always compare greater.
396impl PartialOrd<AsciiChar> for Utf16Char {
397    #[inline]
398    fn partial_cmp(&self,  ascii: &AsciiChar) -> Option<Ordering> {
399        self.units[0].partial_cmp(&(*ascii as u16))
400    }
401}
402#[cfg(feature = "ascii")]
403/// `Utf16Char`s that are not ASCII always compare greater.
404impl PartialOrd<Utf16Char> for AsciiChar {
405    #[inline]
406    fn partial_cmp(&self,  u16c: &Utf16Char) -> Option<Ordering> {
407        (*self as u16).partial_cmp(&u16c.units[0])
408    }
409}
410
411
412  ///////////////////////////////////////////////////////
413 //pub impls that should be together for nicer rustdoc//
414///////////////////////////////////////////////////////
415impl Utf16Char {
416    /// Create an `Utf16Char` from the first codepoint in a string slice,
417    /// converting from UTF-8 to UTF-16.
418    ///
419    /// The returned `usize` is the number of UTF-8 bytes used from the str,
420    /// and not the number of UTF-16 units.
421    ///
422    /// Returns an error if the `str` is empty.
423    ///
424    /// # Examples
425    ///
426    /// ```
427    /// use encode_unicode::Utf16Char;
428    ///
429    /// assert_eq!(Utf16Char::from_str_start("a"), Ok((Utf16Char::from('a'),1)));
430    /// assert_eq!(Utf16Char::from_str_start("ab"), Ok((Utf16Char::from('a'),1)));
431    /// assert_eq!(Utf16Char::from_str_start("🂠 "), Ok((Utf16Char::from('🂠'),4)));
432    /// assert_eq!(Utf16Char::from_str_start("é"), Ok((Utf16Char::from('e'),1)));// 'e'+u301 combining mark
433    /// assert!(Utf16Char::from_str_start("").is_err());
434    /// ```
435    pub fn from_str_start(s: &str) -> Result<(Self,usize), EmptyStrError> {
436        if s.is_empty() {
437            return Err(EmptyStrError);
438        }
439        let b = s.as_bytes();
440        // Read the last byte first to reduce the number of unnecesary length checks.
441        match b[0] {
442            0...127 => {// 1 byte => 1 unit
443                let unit = b[0] as u16;// 0b0000_0000_0xxx_xxxx
444                Ok((Utf16Char{ units: [unit, 0] }, 1))
445            },
446            0b1000_0000...0b1101_1111 => {// 2 bytes => 1 unit
447                let unit = (((b[1] & 0x3f) as u16) << 0) // 0b0000_0000_00xx_xxxx
448                         | (((b[0] & 0x1f) as u16) << 6);// 0b0000_0xxx_xx00_0000
449                Ok((Utf16Char{ units: [unit, 0] }, 2))
450            },
451            0b1110_0000...0b1110_1111 => {// 3 bytes => 1 unit
452                let unit = (((b[2] & 0x3f) as u16) <<  0) // 0b0000_0000_00xx_xxxx
453                         | (((b[1] & 0x3f) as u16) <<  6) // 0b0000_xxxx_xx00_0000
454                         | (((b[0] & 0x0f) as u16) << 12);// 0bxxxx_0000_0000_0000
455                Ok((Utf16Char{ units: [unit, 0] }, 3))
456            },
457            _ => {// 4 bytes => 2 units
458                let second = 0xdc00                        // 0b1101_1100_0000_0000
459                           | (((b[3] & 0x3f) as u16) << 0) // 0b0000_0000_00xx_xxxx
460                           | (((b[2] & 0x0f) as u16) << 6);// 0b0000_00xx_xx00_0000
461                let first = 0xd800-(0x01_00_00u32>>10) as u16// 0b1101_0111_1100_0000
462                          + (((b[2] & 0x30) as u16) >> 4)    // 0b0000_0000_0000_00xx
463                          + (((b[1] & 0x3f) as u16) << 2)    // 0b0000_0000_xxxx_xx00
464                          + (((b[0] & 0x07) as u16) << 8);   // 0b0000_0xxx_0000_0000
465                Ok((Utf16Char{ units: [first, second] }, 4))
466            }
467        }
468    }
469    /// Validate and store the first UTF-16 codepoint in the slice.
470    /// Also return how many units were needed.
471    pub fn from_slice_start(src: &[u16]) -> Result<(Self,usize), InvalidUtf16Slice> {
472        char::from_utf16_slice_start(src).map(|(_,len)| {
473            let second = if len==2 {src[1]} else {0};
474            (Utf16Char{ units: [src[0], second] }, len)
475        })
476    }
477    /// Store the first UTF-16 codepoint of the slice.
478    ///
479    /// # Safety
480    ///
481    /// The slice must be non-empty and start with a valid UTF-16 codepoint.  
482    /// The length of the slice is never checked.
483    pub unsafe fn from_slice_start_unchecked(src: &[u16]) -> (Self,usize) {
484        let first = *src.get_unchecked(0);
485        if first.is_utf16_leading_surrogate() {
486            (Utf16Char{ units: [first, *src.get_unchecked(1)] }, 2)
487        } else {
488            (Utf16Char{ units: [first, 0] }, 1)
489        }
490    }
491    /// Validate and store an UTF-16 array as returned from `char.to_utf16_array()`.
492    ///
493    /// # Examples
494    ///
495    /// ```
496    /// use encode_unicode::Utf16Char;
497    /// use encode_unicode::error::InvalidUtf16Array;
498    ///
499    /// assert_eq!(Utf16Char::from_array(['x' as u16, 'y' as u16]), Ok(Utf16Char::from('x')));
500    /// assert_eq!(Utf16Char::from_array(['睷' as u16, 0]), Ok(Utf16Char::from('睷')));
501    /// assert_eq!(Utf16Char::from_array([0xda6f, 0xdcde]), Ok(Utf16Char::from('\u{abcde}')));
502    /// assert_eq!(Utf16Char::from_array([0xf111, 0xdbad]), Ok(Utf16Char::from('\u{f111}')));
503    /// assert_eq!(Utf16Char::from_array([0xdaaf, 0xdaaf]), Err(InvalidUtf16Array::SecondIsNotTrailingSurrogate));
504    /// assert_eq!(Utf16Char::from_array([0xdcac, 0x9000]), Err(InvalidUtf16Array::FirstIsTrailingSurrogate));
505    /// ```
506    pub fn from_array(units: [u16; 2]) -> Result<Self,InvalidUtf16Array> {
507        if (units[0] & 0xf8_00) != 0xd8_00 {
508            Ok(Utf16Char { units: [units[0], 0] })
509        } else if units[0] < 0xdc_00  &&  (units[1] & 0xfc_00) == 0xdc_00 {
510            Ok(Utf16Char { units: units })
511        } else if units[0] < 0xdc_00 {
512            Err(InvalidUtf16Array::SecondIsNotTrailingSurrogate)
513        } else {
514            Err(InvalidUtf16Array::FirstIsTrailingSurrogate)
515        }
516    }
517    /// Create an `Utf16Char` from an array as returned from `char.to_utf16_array()`.
518    ///
519    /// # Safety
520    ///
521    /// The units must form a valid codepoint, and the second unit must be 0
522    /// when a surrogate pair is not required.
523    /// Violating this can easily lead to undefined behavior, although unlike
524    /// `char` bad `Utf16Char`s simply existing is not immediately UB.
525    pub unsafe fn from_array_unchecked(units: [u16; 2]) -> Self {
526        Utf16Char { units: units }
527    }
528    /// Validate and store a UTF-16 pair as returned from `char.to_utf16_tuple()`.
529    pub fn from_tuple(utf16: (u16,Option<u16>)) -> Result<Self,InvalidUtf16Tuple> {
530        unsafe {char::from_utf16_tuple(utf16).map(|_|
531            Self::from_tuple_unchecked(utf16)
532        )}
533    }
534    /// Create an `Utf16Char` from a tuple as returned from `char.to_utf16_tuple()`.
535    ///
536    /// # Safety
537    ///
538    /// The units must form a valid codepoint with the second being 0 when a
539    /// surrogate pair is not required.
540    /// Violating this can easily lead to undefined behavior.
541    pub unsafe fn from_tuple_unchecked(utf16: (u16,Option<u16>)) -> Self {
542        Utf16Char { units: [utf16.0, utf16.1.unwrap_or(0)] }
543    }
544    /// Create an `Utf16Char` from a single unit.
545    ///
546    /// Codepoints < '\u{1_0000}' (which fit in a `u16`) are part of the basic
547    /// multilingual plane unless they are reserved for surrogate pairs.
548    ///
549    /// # Errors
550    ///
551    /// Returns `NonBMPError` if the unit is in the range `0xd800..0xe000`
552    /// (which means that it's part of a surrogat pair)
553    ///
554    /// # Examples
555    ///
556    /// ```
557    /// # use encode_unicode::Utf16Char;
558    /// assert_eq!(Utf16Char::from_bmp(0x40).unwrap(), '@');
559    /// assert_eq!(Utf16Char::from_bmp('ø' as u16).unwrap(), 'ø');
560    /// assert!(Utf16Char::from_bmp(0xdddd).is_err());
561    /// ```
562    pub fn from_bmp(bmp_codepoint: u16) -> Result<Self,NonBMPError> {
563        if bmp_codepoint & 0xf800 != 0xd800 {
564            Ok(Utf16Char{ units: [bmp_codepoint, 0] })
565        } else {
566            Err(NonBMPError)
567        }
568    }
569    /// Create an `Utf16Char` from a single unit without checking that it's a
570    /// valid codepoint on its own.
571    ///
572    /// # Safety
573    ///
574    /// The unit must be less than 0xd800 or greater than 0xdfff.
575    /// In other words, not part of a surrogate pair.  
576    /// Violating this can easily lead to undefined behavior.
577    #[inline]
578    pub unsafe fn from_bmp_unchecked(bmp_codepoint: u16) -> Self {
579        Utf16Char{ units: [bmp_codepoint, 0] }
580    }
581    /// Checks that the codepoint is in the basic multilingual plane.
582    ///
583    /// # Examples
584    /// ```
585    /// # use encode_unicode::Utf16Char;
586    /// assert_eq!(Utf16Char::from('e').is_bmp(), true);
587    /// assert_eq!(Utf16Char::from('€').is_bmp(), true);
588    /// assert_eq!(Utf16Char::from('𝔼').is_bmp(), false);
589    /// ```
590    #[inline]
591    pub fn is_bmp(&self) -> bool {
592        self.units[1] == 0
593    }
594
595    /// The number of units this character is made up of.
596    ///
597    /// Is either 1 or 2 and identical to `.as_char().len_utf16()`
598    /// or `.as_ref().len()`.
599    #[inline]
600    pub fn len(self) -> usize {
601        1 + (self.units[1] as usize >> 15)
602    }
603    // There is no `.is_emty()` because it would always return false.
604
605    /// Checks that the codepoint is an ASCII character.
606    #[inline]
607    pub fn is_ascii(&self) -> bool {
608        self.units[0] <= 127
609    }
610    /// Checks that two characters are an ASCII case-insensitive match.
611    ///
612    /// Is equivalent to `a.to_ascii_lowercase() == b.to_ascii_lowercase()`.
613    #[cfg(feature="std")]
614    pub fn eq_ignore_ascii_case(&self,  other: &Self) -> bool {
615        self.to_ascii_lowercase() == other.to_ascii_lowercase()
616    }
617    /// Converts the character to its ASCII upper case equivalent.
618    ///
619    /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
620    /// but non-ASCII letters are unchanged.
621    #[cfg(feature="std")]
622    pub fn to_ascii_uppercase(&self) -> Self {
623        let n = self.units[0].wrapping_sub(b'a' as u16);
624        if n < 26 {Utf16Char{ units: [n+b'A' as u16, 0] }}
625        else      {*self}
626    }
627    /// Converts the character to its ASCII lower case equivalent.
628    ///
629    /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
630    /// but non-ASCII letters are unchanged.
631    #[cfg(feature="std")]
632    pub fn to_ascii_lowercase(&self) -> Self {
633        let n = self.units[0].wrapping_sub(b'A' as u16);
634        if n < 26 {Utf16Char{ units: [n+b'a' as u16, 0] }}
635        else      {*self}
636    }
637    /// Converts the character to its ASCII upper case equivalent in-place.
638    ///
639    /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
640    /// but non-ASCII letters are unchanged.
641    #[cfg(feature="std")]
642    pub fn make_ascii_uppercase(&mut self) {
643        *self = self.to_ascii_uppercase()
644    }
645    /// Converts the character to its ASCII lower case equivalent in-place.
646    ///
647    /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
648    /// but non-ASCII letters are unchanged.
649    #[cfg(feature="std")]
650    pub fn make_ascii_lowercase(&mut self) {
651        *self = self.to_ascii_lowercase();
652    }
653
654    /// Convert from UTF-16 to UTF-32
655    pub fn to_char(self) -> char {
656        self.into()
657    }
658    /// Write the internal representation to a slice,
659    /// and then returns the number of `u16`s written.
660    ///
661    /// # Panics
662    /// Will panic the buffer is too small;
663    /// You can get the required length from `.len()`,
664    /// but a buffer of length two is always large enough.
665    pub fn to_slice(self,  dst: &mut[u16]) -> usize {
666        // Write the last unit first to avoid repeated length checks.
667        let extra = self.units[1] as usize >> 15;
668        match dst.get_mut(extra) {
669            Some(first) => *first = self.units[extra],
670            None => panic!("The provided buffer is too small.")
671        }
672        if extra != 0 {dst[0] = self.units[0];}
673        extra+1
674    }
675    /// Get the character represented as an array of two units.
676    ///
677    /// The second `u16` is zero for codepoints that fit in one unit.
678    #[inline]
679    pub fn to_array(self) -> [u16;2] {
680        self.units
681    }
682    /// The second `u16` is used for surrogate pairs.
683    #[inline]
684    pub fn to_tuple(self) -> (u16,Option<u16>) {
685        (self.units[0],  if self.units[1]==0 {None} else {Some(self.units[1])})
686    }
687}