encode_unicode/utf8_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::errors::{FromStrError, EmptyStrError, NonAsciiError, Utf8Error};
10use crate::utf8_iterators::Utf8Iterator;
11use crate::traits::{CharExt, U8UtfExt};
12use crate::utf16_char::Utf16Char;
13extern crate core;
14use core::{hash, fmt, str, ptr};
15use core::cmp::Ordering;
16use core::borrow::Borrow;
17use core::ops::Deref;
18#[cfg(feature="std")]
19use core::iter::FromIterator;
20#[cfg(feature="ascii")]
21extern crate ascii;
22#[cfg(feature="ascii")]
23use ascii::{AsciiChar,ToAsciiChar,ToAsciiCharError};
24
25
26// I don't think there is any good default value for char, but char does.
27#[derive(Default)]
28// char doesn't do anything more advanced than u32 for Eq/Ord, so we shouldn't either.
29// The default impl of Ord for arrays works out because longer codepoints
30// start with more ones, so if they're equal, the length is the same,
31// breaks down for values above 0x1f_ff_ff but those can only be created by unsafe code.
32#[derive(PartialEq,Eq, PartialOrd,Ord)]
33
34#[derive(Clone,Copy)]
35
36
37/// An unicode codepoint stored as UTF-8.
38///
39/// It can be borrowed as a `str`, and has the same size as `char`.
40pub struct Utf8Char {
41 bytes: [u8; 4],
42}
43
44
45 /////////////////////
46 //conversion traits//
47/////////////////////
48impl str::FromStr for Utf8Char {
49 type Err = FromStrError;
50 /// Create an `Utf8Char` from a string slice.
51 /// The string must contain exactly one codepoint.
52 ///
53 /// # Examples
54 ///
55 /// ```
56 /// use encode_unicode::error::FromStrError::*;
57 /// use encode_unicode::Utf8Char;
58 /// use std::str::FromStr;
59 ///
60 /// assert_eq!(Utf8Char::from_str("a"), Ok(Utf8Char::from('a')));
61 /// assert_eq!(Utf8Char::from_str("🂠"), Ok(Utf8Char::from('🂠')));
62 /// assert_eq!(Utf8Char::from_str(""), Err(Empty));
63 /// assert_eq!(Utf8Char::from_str("ab"), Err(MultipleCodepoints));
64 /// assert_eq!(Utf8Char::from_str("é"), Err(MultipleCodepoints));// 'e'+u301 combining mark
65 /// ```
66 fn from_str(s: &str) -> Result<Self, FromStrError> {
67 if s.is_empty() {
68 Err(FromStrError::Empty)
69 } else if s.len() != 1+s.as_bytes()[0].extra_utf8_bytes_unchecked() {
70 Err(FromStrError::MultipleCodepoints)
71 } else {
72 let mut bytes = [0; 4];
73 bytes[..s.len()].copy_from_slice(s.as_bytes());
74 Ok(Utf8Char{bytes})
75 }
76 }
77}
78impl From<Utf16Char> for Utf8Char {
79 fn from(utf16: Utf16Char) -> Utf8Char {
80 match utf16.to_tuple() {
81 (ascii @ 0..=0x00_7f, _) => {
82 Utf8Char{ bytes: [ascii as u8, 0, 0, 0] }
83 },
84 (unit @ 0..=0x07_ff, _) => {
85 let byte2 = 0x80 | (unit & 0x00_3f) as u8;
86 let byte1 = 0xc0 | ((unit & 0x07_c0) >> 6) as u8;
87 Utf8Char{ bytes: [byte1, byte2, 0, 0] }
88 },
89 (unit, None) => {
90 let byte3 = 0x80 | (unit & 0x00_3f) as u8;
91 let byte2 = 0x80 | ((unit & 0x0f_c0) >> 6) as u8;
92 let byte1 = 0xe0 | ((unit & 0xf0_00) >> 12) as u8;
93 Utf8Char{ bytes: [byte1, byte2, byte3, 0] }
94 },
95 (first, Some(second)) => {
96 let first = first + (0x01_00_00u32 >> 10) as u16;
97 let byte4 = 0x80 | (second & 0x00_3f) as u8;
98 let byte3 = 0x80 | ((second & 0x03_c0) >> 6) as u8
99 | (( first & 0x00_03) << 4) as u8;
100 let byte2 = 0x80 | (( first & 0x00_fc) >> 2) as u8;
101 let byte1 = 0xf0 | (( first & 0x07_00) >> 8) as u8;
102 Utf8Char{ bytes: [byte1, byte2, byte3, byte4] }
103 }
104 }
105 }
106}
107impl From<char> for Utf8Char {
108 fn from(c: char) -> Self {
109 Utf8Char::new(c)
110 }
111}
112impl From<Utf8Char> for char {
113 fn from(uc: Utf8Char) -> char {
114 uc.to_char()
115 }
116}
117impl IntoIterator for Utf8Char {
118 type Item=u8;
119 type IntoIter=Utf8Iterator;
120 /// Iterate over the byte values.
121 fn into_iter(self) -> Utf8Iterator {
122 Utf8Iterator::from(self)
123 }
124}
125
126#[cfg(feature="std")]
127impl Extend<Utf8Char> for Vec<u8> {
128 fn extend<I:IntoIterator<Item=Utf8Char>>(&mut self, iter: I) {
129 let iter = iter.into_iter();
130 self.reserve(iter.size_hint().0);
131 for u8c in iter {
132 // twice as fast as self.extend_from_slice(u8c.as_bytes());
133 self.push(u8c.bytes[0]);
134 for &extra in &u8c.bytes[1..] {
135 if extra != 0 {
136 self.push(extra);
137 }
138 }
139 }
140 }
141}
142#[cfg(feature="std")]
143impl<'a> Extend<&'a Utf8Char> for Vec<u8> {
144 fn extend<I:IntoIterator<Item=&'a Utf8Char>>(&mut self, iter: I) {
145 self.extend(iter.into_iter().cloned())
146 }
147}
148#[cfg(feature="std")]
149impl Extend<Utf8Char> for String {
150 fn extend<I:IntoIterator<Item=Utf8Char>>(&mut self, iter: I) {
151 unsafe { self.as_mut_vec().extend(iter) }
152 }
153}
154#[cfg(feature="std")]
155impl<'a> Extend<&'a Utf8Char> for String {
156 fn extend<I:IntoIterator<Item=&'a Utf8Char>>(&mut self, iter: I) {
157 self.extend(iter.into_iter().cloned())
158 }
159}
160#[cfg(feature="std")]
161impl FromIterator<Utf8Char> for String {
162 fn from_iter<I:IntoIterator<Item=Utf8Char>>(iter: I) -> String {
163 let mut string = String::new();
164 string.extend(iter);
165 return string;
166 }
167}
168#[cfg(feature="std")]
169impl<'a> FromIterator<&'a Utf8Char> for String {
170 fn from_iter<I:IntoIterator<Item=&'a Utf8Char>>(iter: I) -> String {
171 iter.into_iter().cloned().collect()
172 }
173}
174#[cfg(feature="std")]
175impl FromIterator<Utf8Char> for Vec<u8> {
176 fn from_iter<I:IntoIterator<Item=Utf8Char>>(iter: I) -> Self {
177 iter.into_iter().collect::<String>().into_bytes()
178 }
179}
180#[cfg(feature="std")]
181impl<'a> FromIterator<&'a Utf8Char> for Vec<u8> {
182 fn from_iter<I:IntoIterator<Item=&'a Utf8Char>>(iter: I) -> Self {
183 iter.into_iter().cloned().collect::<String>().into_bytes()
184 }
185}
186
187
188 /////////////////
189 //getter traits//
190/////////////////
191impl AsRef<[u8]> for Utf8Char {
192 fn as_ref(&self) -> &[u8] {
193 &self.bytes[..self.len()]
194 }
195}
196impl AsRef<str> for Utf8Char {
197 fn as_ref(&self) -> &str {
198 unsafe{ str::from_utf8_unchecked( self.as_ref() ) }
199 }
200}
201impl Borrow<[u8]> for Utf8Char {
202 fn borrow(&self) -> &[u8] {
203 self.as_ref()
204 }
205}
206impl Borrow<str> for Utf8Char {
207 fn borrow(&self) -> &str {
208 self.as_ref()
209 }
210}
211impl Deref for Utf8Char {
212 type Target = str;
213 fn deref(&self) -> &Self::Target {
214 self.as_ref()
215 }
216}
217
218
219 ////////////////
220 //ascii traits//
221////////////////
222#[cfg(feature="ascii")]
223/// Requires the feature "ascii".
224impl From<AsciiChar> for Utf8Char {
225 fn from(ac: AsciiChar) -> Self {
226 Utf8Char{ bytes: [ac.as_byte(),0,0,0] }
227 }
228}
229#[cfg(feature="ascii")]
230/// Requires the feature "ascii".
231impl ToAsciiChar for Utf8Char {
232 fn to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError> {
233 self.bytes[0].to_ascii_char()
234 }
235 unsafe fn to_ascii_char_unchecked(self) -> AsciiChar {
236 unsafe { self.bytes[0].to_ascii_char_unchecked() }
237 }
238}
239
240
241 /////////////////////////////////////////////////////////
242 //Genaral traits that cannot be derived to emulate char//
243/////////////////////////////////////////////////////////
244impl hash::Hash for Utf8Char {
245 fn hash<H : hash::Hasher>(&self, state: &mut H) {
246 self.to_char().hash(state);
247 }
248}
249impl fmt::Debug for Utf8Char {
250 fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
251 fmt::Debug::fmt(&self.to_char(), fmtr)
252 }
253}
254impl fmt::Display for Utf8Char {
255 fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
256 fmtr.write_str(self.as_str())
257 }
258}
259
260
261 ////////////////////////////////
262 //Comparisons with other types//
263////////////////////////////////
264impl PartialEq<char> for Utf8Char {
265 fn eq(&self, u32c: &char) -> bool {
266 *self == Utf8Char::from(*u32c)
267 }
268}
269impl PartialEq<Utf8Char> for char {
270 fn eq(&self, u8c: &Utf8Char) -> bool {
271 Utf8Char::from(*self) == *u8c
272 }
273}
274impl PartialOrd<char> for Utf8Char {
275 fn partial_cmp(&self, u32c: &char) -> Option<Ordering> {
276 self.partial_cmp(&Self::from(*u32c))
277 }
278}
279impl PartialOrd<Utf8Char> for char {
280 fn partial_cmp(&self, u8c: &Utf8Char) -> Option<Ordering> {
281 Utf8Char::from(*self).partial_cmp(u8c)
282 }
283}
284
285impl PartialEq<Utf16Char> for Utf8Char {
286 fn eq(&self, u16c: &Utf16Char) -> bool {
287 *self == Self::from(*u16c)
288 }
289}
290impl PartialOrd<Utf16Char> for Utf8Char {
291 fn partial_cmp(&self, u16c: &Utf16Char) -> Option<Ordering> {
292 self.partial_cmp(&Self::from(*u16c))
293 }
294}
295// The other direction is implemented in utf16_char.rs
296
297/// Only considers the byte equal if both it and the `Utf8Char` represents ASCII characters.
298///
299/// There is no impl in the opposite direction, as this should only be used to
300/// compare `Utf8Char`s against constants.
301///
302/// # Examples
303///
304/// ```
305/// # use encode_unicode::Utf8Char;
306/// assert!(Utf8Char::from('8') == b'8');
307/// assert!(Utf8Char::from_array([0xf1,0x80,0x80,0x80]).unwrap() != 0xf1);
308/// assert!(Utf8Char::from('\u{ff}') != 0xff);
309/// assert!(Utf8Char::from('\u{80}') != 0x80);
310/// ```
311impl PartialEq<u8> for Utf8Char {
312 fn eq(&self, byte: &u8) -> bool {
313 self.bytes[0] == *byte && self.bytes[1] == 0
314 }
315}
316#[cfg(feature = "ascii")]
317/// `Utf8Char`s that are not ASCII never compare equal.
318impl PartialEq<AsciiChar> for Utf8Char {
319 #[inline]
320 fn eq(&self, ascii: &AsciiChar) -> bool {
321 self.bytes[0] == *ascii as u8
322 }
323}
324#[cfg(feature = "ascii")]
325/// `Utf8Char`s that are not ASCII never compare equal.
326impl PartialEq<Utf8Char> for AsciiChar {
327 #[inline]
328 fn eq(&self, u8c: &Utf8Char) -> bool {
329 u8c == self
330 }
331}
332#[cfg(feature = "ascii")]
333/// `Utf8Char`s that are not ASCII always compare greater.
334impl PartialOrd<AsciiChar> for Utf8Char {
335 #[inline]
336 fn partial_cmp(&self, ascii: &AsciiChar) -> Option<Ordering> {
337 self.bytes[0].partial_cmp(ascii)
338 }
339}
340#[cfg(feature = "ascii")]
341/// `Utf8Char`s that are not ASCII always compare greater.
342impl PartialOrd<Utf8Char> for AsciiChar {
343 #[inline]
344 fn partial_cmp(&self, u8c: &Utf8Char) -> Option<Ordering> {
345 self.partial_cmp(&u8c.bytes[0])
346 }
347}
348
349
350 ///////////////////////////////////////////////////////
351 //pub impls that should be together for nicer rustdoc//
352///////////////////////////////////////////////////////
353impl Utf8Char {
354 /// A `const fn` alternative to the trait-based `Utf8Char::from(char)`.
355 ///
356 /// # Example
357 ///
358 /// ```
359 /// # use encode_unicode::Utf8Char;
360 /// const REPLACEMENT_CHARACTER: Utf8Char = Utf8Char::new('\u{fffd}');
361 /// ```
362 pub const fn new(c: char) -> Self {
363 if c.is_ascii() {
364 Utf8Char{bytes: [c as u8, 0, 0, 0]}
365 } else {
366 // How many extra UTF-8 bytes that are needed to represent an
367 // UTF-32 codepoint with a number of bits.
368 // Stored as a bit-packed array using two bits per value.
369 // 0..=7 bits = no extra bytes
370 // +4 = 8..=11 bits = one xtra byte (5+6 bits)
371 // +5 = 12..=16 bits = two extra bytes (4+6+6 bits)
372 // +5 = 17..=21 bits = three extra bytes (3+6+6+6 bits)
373 const EXTRA_BYTES: u64 = 0b11_11_11_11_11__10_10_10_10_10__01_01_01_01__00_00_00_00_00_00_00__00;
374 let bits_used = 32 - (c as u32).leading_zeros();
375 let len = 1 + ((EXTRA_BYTES >> (bits_used*2)) & 0b11);
376 // copied from CharExt::to_utf8_array()
377 let mut c = c as u32;
378 let mut parts = 0;// convert to 6-bit bytes
379 parts |= c & 0x3f; c>>=6;
380 parts<<=8; parts |= c & 0x3f; c>>=6;
381 parts<<=8; parts |= c & 0x3f; c>>=6;
382 parts<<=8; parts |= c & 0x3f;
383 parts |= 0x80_80_80_80;// set the most significant bit
384 parts >>= 8*(4-len);// right-align bytes
385 // Now, unused bytes are zero, (which matters for Utf8Char.eq())
386 // and the rest are 0b10xx_xxxx
387
388 // set header on first byte
389 parts |= (0xff_00u32 >> len) & 0xff;// store length
390 parts &= !(1u32 << (7-len));// clear the next bit after it
391
392 Utf8Char {bytes: parts.to_le_bytes()}
393 }
394 }
395
396 /// Create an `Utf8Char` from the first codepoint in a `str`.
397 ///
398 /// Returns an error if the `str` is empty.
399 ///
400 /// # Examples
401 ///
402 /// ```
403 /// use encode_unicode::Utf8Char;
404 ///
405 /// assert_eq!(Utf8Char::from_str_start("a"), Ok((Utf8Char::from('a'),1)));
406 /// assert_eq!(Utf8Char::from_str_start("ab"), Ok((Utf8Char::from('a'),1)));
407 /// assert_eq!(Utf8Char::from_str_start("🂠 "), Ok((Utf8Char::from('🂠'),4)));
408 /// assert_eq!(Utf8Char::from_str_start("é"), Ok((Utf8Char::from('e'),1)));// 'e'+u301 combining mark
409 /// assert!(Utf8Char::from_str_start("").is_err());
410 /// ```
411 pub fn from_str_start(src: &str) -> Result<(Self,usize),EmptyStrError> {
412 unsafe {
413 if src.is_empty() {
414 Err(EmptyStrError)
415 } else {
416 Ok(Utf8Char::from_slice_start_unchecked(src.as_bytes()))
417 }
418 }
419 }
420 /// Create an `Utf8Char` of the first codepoint in an UTF-8 slice.
421 /// Also returns the length of the UTF-8 sequence for the codepoint.
422 ///
423 /// If the slice is from a `str`, use `::from_str_start()` to skip UTF-8 validation.
424 ///
425 /// # Errors
426 ///
427 /// Returns an `Err` if the slice is empty, doesn't start with a valid
428 /// UTF-8 sequence or is too short for the sequence.
429 ///
430 /// # Examples
431 ///
432 /// ```
433 /// use encode_unicode::Utf8Char;
434 /// use encode_unicode::error::Utf8ErrorKind::*;
435 ///
436 /// assert_eq!(Utf8Char::from_slice_start(&[b'A', b'B', b'C']), Ok((Utf8Char::from('A'),1)));
437 /// assert_eq!(Utf8Char::from_slice_start(&[0xdd, 0xbb]), Ok((Utf8Char::from('\u{77b}'),2)));
438 ///
439 /// assert_eq!(Utf8Char::from_slice_start(&[]).unwrap_err().kind(), TooFewBytes);
440 /// assert_eq!(Utf8Char::from_slice_start(&[0xf0, 0x99]).unwrap_err().kind(), TooFewBytes);
441 /// assert_eq!(Utf8Char::from_slice_start(&[0xee, b'F', 0x80]).unwrap_err().kind(), InterruptedSequence);
442 /// assert_eq!(Utf8Char::from_slice_start(&[0xee, 0x99, 0x0f]).unwrap_err().kind(), InterruptedSequence);
443 /// ```
444 pub fn from_slice_start(src: &[u8]) -> Result<(Self,usize),Utf8Error> {
445 char::from_utf8_slice_start(src).map(|(_,len)| {
446 let mut bytes = [0; 4];
447 bytes[..len].copy_from_slice(&src[..len]);
448 (Utf8Char{bytes}, len)
449 })
450 }
451 /// A `from_slice_start()` that doesn't validate the codepoint.
452 ///
453 /// # Safety
454 ///
455 /// The slice must be non-empty and start with a valid UTF-8 codepoint.
456 /// Invalid or incomplete values might cause reads of uninitalized memory.
457 pub unsafe fn from_slice_start_unchecked(src: &[u8]) -> (Self,usize) {
458 unsafe {
459 let len = 1+src.get_unchecked(0).extra_utf8_bytes_unchecked();
460 let mut bytes = [0; 4];
461 ptr::copy_nonoverlapping(src.as_ptr(), bytes.as_mut_ptr() as *mut u8, len);
462 (Utf8Char{bytes}, len)
463 }
464 }
465 /// Create an `Utf8Char` from a byte array after validating it.
466 ///
467 /// The codepoint must start at the first byte.
468 /// Unused bytes are set to zero by this function and so can be anything.
469 ///
470 /// # Errors
471 ///
472 /// Returns an `Err` if the array doesn't start with a valid UTF-8 sequence.
473 ///
474 /// # Examples
475 ///
476 /// ```
477 /// use encode_unicode::Utf8Char;
478 /// use encode_unicode::error::Utf8ErrorKind::*;
479 ///
480 /// assert_eq!(Utf8Char::from_array([b'A', 0, 0, 0]), Ok(Utf8Char::from('A')));
481 /// assert_eq!(Utf8Char::from_array([0xf4, 0x8b, 0xbb, 0xbb]), Ok(Utf8Char::from('\u{10befb}')));
482 /// assert_eq!(Utf8Char::from_array([b'A', b'B', b'C', b'D']), Ok(Utf8Char::from('A')));
483 /// assert_eq!(Utf8Char::from_array([0, 0, 0xcc, 0xbb]), Ok(Utf8Char::from('\0')));
484 ///
485 /// assert_eq!(Utf8Char::from_array([0xef, b'F', 0x80, 0x80]).unwrap_err().kind(), InterruptedSequence);
486 /// assert_eq!(Utf8Char::from_array([0xc1, 0x80, 0, 0]).unwrap_err().kind(), NonUtf8Byte);
487 /// assert_eq!(Utf8Char::from_array([0xe0, 0x9a, 0xbf, 0]).unwrap_err().kind(), OverlongEncoding);
488 /// assert_eq!(Utf8Char::from_array([0xf4, 0xaa, 0x99, 0x88]).unwrap_err().kind(), TooHighCodepoint);
489 /// ```
490 pub fn from_array(utf8: [u8;4]) -> Result<Self,Utf8Error> {
491 // perform all validation
492 char::from_utf8_array(utf8)?;
493 let extra = utf8[0].extra_utf8_bytes_unchecked() as u32;
494 // zero unused bytes in one operation by transmuting the arrary to
495 // u32, apply an endian-corrected mask and transmute back
496 let mask = u32::from_le(0xff_ff_ff_ff >> (8*(3-extra)));
497 let unused_zeroed = mask & u32::from_ne_bytes(utf8); // native endian
498 Ok(Utf8Char{ bytes: unused_zeroed.to_ne_bytes() })
499 }
500 /// Zero-cost constructor.
501 ///
502 /// # Safety
503 ///
504 /// Must contain a valid codepoint starting at the first byte, with the
505 /// unused bytes zeroed.
506 /// Bad values can easily lead to undefined behavior.
507 #[inline]
508 pub const unsafe fn from_array_unchecked(utf8: [u8;4]) -> Self {
509 Utf8Char{ bytes: utf8 }
510 }
511 /// Create an `Utf8Char` from a single byte.
512 ///
513 /// The byte must be an ASCII character.
514 ///
515 /// # Errors
516 ///
517 /// Returns `NonAsciiError` if the byte greater than 127.
518 ///
519 /// # Examples
520 ///
521 /// ```
522 /// # use encode_unicode::Utf8Char;
523 /// assert_eq!(Utf8Char::from_ascii(b'a').unwrap(), 'a');
524 /// assert!(Utf8Char::from_ascii(128).is_err());
525 /// ```
526 pub const fn from_ascii(ascii: u8) -> Result<Self,NonAsciiError> {
527 [Ok(Utf8Char{ bytes: [ascii, 0, 0, 0] }), Err(NonAsciiError)][(ascii >> 7) as usize]
528 }
529 /// Create an `Utf8Char` from a single byte without checking that it's a
530 /// valid codepoint on its own, which is only true for ASCII characters.
531 ///
532 /// # Safety
533 ///
534 /// The byte must be less than 128.
535 #[inline]
536 pub const unsafe fn from_ascii_unchecked(ascii: u8) -> Self {
537 Utf8Char{ bytes: [ascii, 0, 0, 0] }
538 }
539
540 /// The number of bytes this character needs.
541 ///
542 /// Is between 1 and 4 (inclusive) and identical to `.as_ref().len()` or
543 /// `.as_char().len_utf8()`.
544 #[inline]
545 pub const fn len(self) -> usize {
546 // Invariants of the extra bytes enambles algorithms that
547 // `u8.extra_utf8_bytes_unchecked()` cannot use.
548 // Some of them turned out to require fewer x86 instructions:
549
550 // Exploits that unused bytes are zero and calculates the number of
551 // trailing zero bytes.
552 // Setting a bit in the first byte prevents the function from returning
553 // 0 for '\0' (which has 32 leading zeros).
554 // trailing and leading is swapped below to optimize for little-endian
555 // architectures.
556 (4 - (u32::from_le_bytes(self.bytes)|1).leading_zeros()/8) as usize
557
558 // Exploits that the extra bytes have their most significant bit set if
559 // in use.
560 // Takes fewer instructions than the one above if popcnt can be used,
561 // (which it cannot by default,
562 // set RUSTFLAGS='-C target-cpu=native' to enable)
563 //let all = u32::from_ne_bytes(self.bytes);
564 //let msb_mask = u32::from_be(0x00808080);
565 //let add_one = u32::from_be(0x80000000);
566 //((all & msb_mask) | add_one).count_ones() as usize
567 }
568 // There is no .is_emty() because this type is never empty.
569
570 /// Checks that the codepoint is an ASCII character.
571 pub const fn is_ascii(self) -> bool {
572 self.bytes[0].is_ascii()
573 }
574 /// Checks that two characters are an ASCII case-insensitive match.
575 ///
576 /// Is equivalent to `a.to_ascii_lowercase() == b.to_ascii_lowercase()`.
577 pub const fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
578 if self.is_ascii() {
579 self.bytes[0].eq_ignore_ascii_case(&other.bytes[0])
580 } else {
581 // [u8; 4] can't be const compared as of Rust 1.60, but u32 can
582 u32::from_le_bytes(self.bytes) == u32::from_le_bytes(other.bytes)
583 }
584 }
585 /// Converts the character to its ASCII upper case equivalent.
586 ///
587 /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
588 /// but non-ASCII letters are unchanged.
589 pub const fn to_ascii_uppercase(mut self) -> Self {
590 self.bytes[0] = self.bytes[0].to_ascii_uppercase();
591 self
592 }
593 /// Converts the character to its ASCII lower case equivalent.
594 ///
595 /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
596 /// but non-ASCII letters are unchanged.
597 pub const fn to_ascii_lowercase(mut self) -> Self {
598 self.bytes[0] = self.bytes[0].to_ascii_lowercase();
599 self
600 }
601 /// Converts the character to its ASCII upper case equivalent in-place.
602 ///
603 /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
604 /// but non-ASCII letters are unchanged.
605 #[inline]
606 pub fn make_ascii_uppercase(&mut self) {
607 self.bytes[0].make_ascii_uppercase()
608 }
609 /// Converts the character to its ASCII lower case equivalent in-place.
610 ///
611 /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
612 /// but non-ASCII letters are unchanged.
613 #[inline]
614 pub fn make_ascii_lowercase(&mut self) {
615 self.bytes[0].make_ascii_lowercase();
616 }
617
618 /// Convert from UTF-8 to UTF-32
619 pub fn to_char(self) -> char {
620 unsafe { char::from_utf8_exact_slice_unchecked(&self.bytes[..self.len()]) }
621 }
622 /// Write the internal representation to a slice,
623 /// and then returns the number of bytes written.
624 ///
625 /// # Panics
626 ///
627 /// Will panic the buffer is too small;
628 /// You can get the required length from `.len()`,
629 /// but a buffer of length four is always large enough.
630 pub fn to_slice(self, dst: &mut[u8]) -> usize {
631 if self.len() > dst.len() {
632 panic!("The provided buffer is too small.");
633 }
634 dst[..self.len()].copy_from_slice(&self.bytes[..self.len()]);
635 self.len()
636 }
637 /// Expose the internal array and the number of used bytes.
638 pub const fn to_array(self) -> ([u8;4],usize) {
639 (self.bytes, self.len())
640 }
641 /// Return a `str` view of the array the codepoint is stored as.
642 ///
643 /// Is an unambiguous version of `.as_ref()`.
644 pub fn as_str(&self) -> &str {
645 self.deref()
646 }
647}