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