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}