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 
9 use utf16_iterators::Utf16Iterator;
10 use traits::{CharExt, U16UtfExt};
11 use utf8_char::Utf8Char;
12 use errors::{InvalidUtf16Slice, InvalidUtf16Array, InvalidUtf16Tuple};
13 use errors::{NonBMPError, EmptyStrError, FromStrError};
14 extern crate core;
15 use self::core::{hash,fmt};
16 use self::core::cmp::Ordering;
17 use self::core::borrow::Borrow;
18 use self::core::ops::Deref;
19 use self::core::str::FromStr;
20 #[cfg(feature="std")]
21 use self::core::iter::FromIterator;
22 #[cfg(feature="std")]
23 #[allow(deprecated)]
24 use std::ascii::AsciiExt;
25 #[cfg(feature="ascii")]
26 use self::core::char;
27 #[cfg(feature="ascii")]
28 extern crate ascii;
29 #[cfg(feature="ascii")]
30 use 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`.
45 pub struct Utf16Char {
46     units: [u16; 2],
47 }
48 
49 
50   /////////////////////
51  //conversion traits//
52 /////////////////////
53 impl 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     /// ```
from_str(s: &str) -> Result<Self, FromStrError>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 }
79 impl From<char> for Utf16Char {
from(c: char) -> Self80     fn from(c: char) -> Self {
81         let (first, second) = c.to_utf16_tuple();
82         Utf16Char{ units: [first, second.unwrap_or(0)] }
83     }
84 }
85 impl From<Utf8Char> for Utf16Char {
from(utf8: Utf8Char) -> Utf16Char86     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 }
110 impl From<Utf16Char> for char {
from(uc: Utf16Char) -> char111     fn from(uc: Utf16Char) -> char {
112         char::from_utf16_array_unchecked(uc.to_array())
113     }
114 }
115 impl IntoIterator for Utf16Char {
116     type Item=u16;
117     type IntoIter=Utf16Iterator;
118     /// Iterate over the units.
into_iter(self) -> Utf16Iterator119     fn into_iter(self) -> Utf16Iterator {
120         Utf16Iterator::from(self)
121     }
122 }
123 
124 #[cfg(feature="std")]
125 impl Extend<Utf16Char> for Vec<u16> {
extend<I:IntoIterator<Item=Utf16Char>>(&mut self, iter: I)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")]
138 impl<'a> Extend<&'a Utf16Char> for Vec<u16> {
extend<I:IntoIterator<Item=&'a Utf16Char>>(&mut self, iter: I)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")]
144 impl FromIterator<Utf16Char> for Vec<u16> {
from_iter<I:IntoIterator<Item=Utf16Char>>(iter: I) -> Self145     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")]
152 impl<'a> FromIterator<&'a Utf16Char> for Vec<u16> {
from_iter<I:IntoIterator<Item=&'a Utf16Char>>(iter: I) -> Self153     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")]
159 impl Extend<Utf16Char> for String {
extend<I:IntoIterator<Item=Utf16Char>>(&mut self, iter: I)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")]
165 impl<'a> Extend<&'a Utf16Char> for String {
extend<I:IntoIterator<Item=&'a Utf16Char>>(&mut self, iter: I)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")]
171 impl FromIterator<Utf16Char> for String {
from_iter<I:IntoIterator<Item=Utf16Char>>(iter: I) -> Self172     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")]
179 impl<'a> FromIterator<&'a Utf16Char> for String {
from_iter<I:IntoIterator<Item=&'a Utf16Char>>(iter: I) -> Self180     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 /////////////////
189 impl AsRef<[u16]> for Utf16Char {
190     #[inline]
as_ref(&self) -> &[u16]191     fn as_ref(&self) -> &[u16] {
192         &self.units[..self.len()]
193     }
194 }
195 impl Borrow<[u16]> for Utf16Char {
196     #[inline]
borrow(&self) -> &[u16]197     fn borrow(&self) -> &[u16] {
198         self.as_ref()
199     }
200 }
201 impl Deref for Utf16Char {
202     type Target = [u16];
203     #[inline]
deref(&self) -> &[u16]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)]
215 impl AsciiExt for Utf16Char {
216     type Owned = Self;
is_ascii(&self) -> bool217     fn is_ascii(&self) -> bool {
218         self.units[0] < 128
219     }
eq_ignore_ascii_case(&self, other: &Self) -> bool220     fn eq_ignore_ascii_case(&self,  other: &Self) -> bool {
221         self.to_ascii_lowercase() == other.to_ascii_lowercase()
222     }
to_ascii_uppercase(&self) -> Self223     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     }
to_ascii_lowercase(&self) -> Self228     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     }
make_ascii_uppercase(&mut self)233     fn make_ascii_uppercase(&mut self) {
234         *self = self.to_ascii_uppercase()
235     }
make_ascii_lowercase(&mut self)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".
243 impl From<AsciiChar> for Utf16Char {
244     #[inline]
from(ac: AsciiChar) -> Self245     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".
251 impl ToAsciiChar for Utf16Char {
252     #[inline]
to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError>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]
to_ascii_char_unchecked(self) -> AsciiChar258     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 /////////////////////////////////////////////////////////
267 impl hash::Hash for Utf16Char {
hash<H : hash::Hasher>(&self, state: &mut H)268     fn hash<H : hash::Hasher>(&self,  state: &mut H) {
269         self.to_char().hash(state);
270     }
271 }
272 impl fmt::Debug for Utf16Char {
fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result273     fn fmt(&self,  fmtr: &mut fmt::Formatter) -> fmt::Result {
274         fmt::Debug::fmt(&self.to_char(), fmtr)
275     }
276 }
277 impl fmt::Display for Utf16Char {
fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result278     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.
284 impl PartialOrd for Utf16Char {
285     #[inline]
partial_cmp(&self, rhs: &Self) -> Option<Ordering>286     fn partial_cmp(&self,  rhs: &Self) -> Option<Ordering> {
287         Some(self.cmp(rhs))
288     }
289 }
290 impl Ord for Utf16Char {
291     #[inline]
cmp(&self, rhs: &Self) -> Ordering292     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 ////////////////////////////////
311 impl PartialEq<char> for Utf16Char {
eq(&self, u32c: &char) -> bool312     fn eq(&self,  u32c: &char) -> bool {
313         *self == Utf16Char::from(*u32c)
314     }
315 }
316 impl PartialEq<Utf16Char> for char {
eq(&self, u16c: &Utf16Char) -> bool317     fn eq(&self,  u16c: &Utf16Char) -> bool {
318         Utf16Char::from(*self) == *u16c
319     }
320 }
321 impl PartialOrd<char> for Utf16Char {
partial_cmp(&self, u32c: &char) -> Option<Ordering>322     fn partial_cmp(&self,  u32c: &char) -> Option<Ordering> {
323         self.partial_cmp(&Utf16Char::from(*u32c))
324     }
325 }
326 impl PartialOrd<Utf16Char> for char {
partial_cmp(&self, u16c: &Utf16Char) -> Option<Ordering>327     fn partial_cmp(&self,  u16c: &Utf16Char) -> Option<Ordering> {
328         Utf16Char::from(*self).partial_cmp(u16c)
329     }
330 }
331 
332 impl PartialEq<Utf8Char> for Utf16Char {
eq(&self, u8c: &Utf8Char) -> bool333     fn eq(&self,  u8c: &Utf8Char) -> bool {
334         *self == Utf16Char::from(*u8c)
335     }
336 }
337 impl PartialOrd<Utf8Char> for Utf16Char {
partial_cmp(&self, u8c: &Utf8Char) -> Option<Ordering>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 /// ```
358 impl PartialEq<u16> for Utf16Char {
eq(&self, unit: &u16) -> bool359     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 /// ```
373 impl PartialEq<u8> for Utf16Char {
eq(&self, byte: &u8) -> bool374     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.
380 impl PartialEq<AsciiChar> for Utf16Char {
381     #[inline]
eq(&self, ascii: &AsciiChar) -> bool382     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.
388 impl PartialEq<Utf16Char> for AsciiChar {
389     #[inline]
eq(&self, u16c: &Utf16Char) -> bool390     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.
396 impl PartialOrd<AsciiChar> for Utf16Char {
397     #[inline]
partial_cmp(&self, ascii: &AsciiChar) -> Option<Ordering>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.
404 impl PartialOrd<Utf16Char> for AsciiChar {
405     #[inline]
partial_cmp(&self, u16c: &Utf16Char) -> Option<Ordering>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 ///////////////////////////////////////////////////////
415 impl 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     /// ```
from_str_start(s: &str) -> Result<(Self,usize), EmptyStrError>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.
from_slice_start(src: &[u16]) -> Result<(Self,usize), InvalidUtf16Slice>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.
from_slice_start_unchecked(src: &[u16]) -> (Self,usize)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     /// ```
from_array(units: [u16; 2]) -> Result<Self,InvalidUtf16Array>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.
from_array_unchecked(units: [u16; 2]) -> Self525     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()`.
from_tuple(utf16: (u16,Option<u16>)) -> Result<Self,InvalidUtf16Tuple>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.
from_tuple_unchecked(utf16: (u16,Option<u16>)) -> Self541     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     /// ```
from_bmp(bmp_codepoint: u16) -> Result<Self,NonBMPError>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]
from_bmp_unchecked(bmp_codepoint: u16) -> Self578     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]
is_bmp(&self) -> bool591     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]
len(self) -> usize600     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]
is_ascii(&self) -> bool607     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")]
eq_ignore_ascii_case(&self, other: &Self) -> bool614     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")]
to_ascii_uppercase(&self) -> Self622     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")]
to_ascii_lowercase(&self) -> Self632     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")]
make_ascii_uppercase(&mut self)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")]
make_ascii_lowercase(&mut self)650     pub fn make_ascii_lowercase(&mut self) {
651         *self = self.to_ascii_lowercase();
652     }
653 
654     /// Convert from UTF-16 to UTF-32
to_char(self) -> char655     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.
to_slice(self, dst: &mut[u16]) -> usize665     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]
to_array(self) -> [u16;2]679     pub fn to_array(self) -> [u16;2] {
680         self.units
681     }
682     /// The second `u16` is used for surrogate pairs.
683     #[inline]
to_tuple(self) -> (u16,Option<u16>)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 }
688