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