1#![allow(dead_code)]
17
18#[cfg(test)]
19mod tests;
20
21use core::char::{encode_utf8_raw, encode_utf16_raw};
22use core::clone::CloneToUninit;
23use core::str::next_code_point;
24
25use crate::borrow::Cow;
26use crate::collections::TryReserveError;
27use crate::hash::{Hash, Hasher};
28use crate::iter::FusedIterator;
29use crate::rc::Rc;
30use crate::sync::Arc;
31use crate::sys_common::AsInner;
32use crate::{fmt, mem, ops, slice, str};
33
34const UTF8_REPLACEMENT_CHARACTER: &str = "\u{FFFD}";
35
36#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
42pub struct CodePoint {
43 value: u32,
44}
45
46impl fmt::Debug for CodePoint {
49 #[inline]
50 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
51 write!(formatter, "U+{:04X}", self.value)
52 }
53}
54
55impl CodePoint {
56 #[inline]
60 pub unsafe fn from_u32_unchecked(value: u32) -> CodePoint {
61 CodePoint { value }
62 }
63
64 #[inline]
68 pub fn from_u32(value: u32) -> Option<CodePoint> {
69 match value {
70 0..=0x10FFFF => Some(CodePoint { value }),
71 _ => None,
72 }
73 }
74
75 #[inline]
79 pub fn from_char(value: char) -> CodePoint {
80 CodePoint { value: value as u32 }
81 }
82
83 #[inline]
85 pub fn to_u32(&self) -> u32 {
86 self.value
87 }
88
89 #[inline]
91 pub fn to_lead_surrogate(&self) -> Option<u16> {
92 match self.value {
93 lead @ 0xD800..=0xDBFF => Some(lead as u16),
94 _ => None,
95 }
96 }
97
98 #[inline]
100 pub fn to_trail_surrogate(&self) -> Option<u16> {
101 match self.value {
102 trail @ 0xDC00..=0xDFFF => Some(trail as u16),
103 _ => None,
104 }
105 }
106
107 #[inline]
111 pub fn to_char(&self) -> Option<char> {
112 match self.value {
113 0xD800..=0xDFFF => None,
114 _ => Some(unsafe { char::from_u32_unchecked(self.value) }),
115 }
116 }
117
118 #[inline]
123 pub fn to_char_lossy(&self) -> char {
124 self.to_char().unwrap_or('\u{FFFD}')
125 }
126}
127
128#[derive(Eq, PartialEq, Ord, PartialOrd, Clone)]
133pub struct Wtf8Buf {
134 bytes: Vec<u8>,
135
136 is_known_utf8: bool,
143}
144
145impl ops::Deref for Wtf8Buf {
146 type Target = Wtf8;
147
148 fn deref(&self) -> &Wtf8 {
149 self.as_slice()
150 }
151}
152
153impl ops::DerefMut for Wtf8Buf {
154 fn deref_mut(&mut self) -> &mut Wtf8 {
155 self.as_mut_slice()
156 }
157}
158
159impl fmt::Debug for Wtf8Buf {
163 #[inline]
164 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
165 fmt::Debug::fmt(&**self, formatter)
166 }
167}
168
169impl Wtf8Buf {
170 #[inline]
172 pub fn new() -> Wtf8Buf {
173 Wtf8Buf { bytes: Vec::new(), is_known_utf8: true }
174 }
175
176 #[inline]
178 pub fn with_capacity(capacity: usize) -> Wtf8Buf {
179 Wtf8Buf { bytes: Vec::with_capacity(capacity), is_known_utf8: true }
180 }
181
182 #[inline]
187 pub unsafe fn from_bytes_unchecked(value: Vec<u8>) -> Wtf8Buf {
188 Wtf8Buf { bytes: value, is_known_utf8: false }
189 }
190
191 #[inline]
197 pub fn from_string(string: String) -> Wtf8Buf {
198 Wtf8Buf { bytes: string.into_bytes(), is_known_utf8: true }
199 }
200
201 #[inline]
207 pub fn from_str(s: &str) -> Wtf8Buf {
208 Wtf8Buf { bytes: <[_]>::to_vec(s.as_bytes()), is_known_utf8: true }
209 }
210
211 pub fn clear(&mut self) {
212 self.bytes.clear();
213 self.is_known_utf8 = true;
214 }
215
216 pub fn from_wide(v: &[u16]) -> Wtf8Buf {
221 let mut string = Wtf8Buf::with_capacity(v.len());
222 for item in char::decode_utf16(v.iter().cloned()) {
223 match item {
224 Ok(ch) => string.push_char(ch),
225 Err(surrogate) => {
226 let surrogate = surrogate.unpaired_surrogate();
227 let code_point = unsafe { CodePoint::from_u32_unchecked(surrogate as u32) };
229 string.is_known_utf8 = false;
231 string.push_code_point_unchecked(code_point);
234 }
235 }
236 }
237 string
238 }
239
240 fn push_code_point_unchecked(&mut self, code_point: CodePoint) {
243 let mut bytes = [0; 4];
244 let bytes = encode_utf8_raw(code_point.value, &mut bytes);
245 self.bytes.extend_from_slice(bytes)
246 }
247
248 #[inline]
249 pub fn as_slice(&self) -> &Wtf8 {
250 unsafe { Wtf8::from_bytes_unchecked(&self.bytes) }
251 }
252
253 #[inline]
254 pub fn as_mut_slice(&mut self) -> &mut Wtf8 {
255 unsafe { Wtf8::from_mut_bytes_unchecked(&mut self.bytes) }
259 }
260
261 #[inline]
269 pub fn reserve(&mut self, additional: usize) {
270 self.bytes.reserve(additional)
271 }
272
273 #[inline]
285 pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
286 self.bytes.try_reserve(additional)
287 }
288
289 #[inline]
290 pub fn reserve_exact(&mut self, additional: usize) {
291 self.bytes.reserve_exact(additional)
292 }
293
294 #[inline]
311 pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
312 self.bytes.try_reserve_exact(additional)
313 }
314
315 #[inline]
316 pub fn shrink_to_fit(&mut self) {
317 self.bytes.shrink_to_fit()
318 }
319
320 #[inline]
321 pub fn shrink_to(&mut self, min_capacity: usize) {
322 self.bytes.shrink_to(min_capacity)
323 }
324
325 #[inline]
326 pub fn leak<'a>(self) -> &'a mut Wtf8 {
327 unsafe { Wtf8::from_mut_bytes_unchecked(self.bytes.leak()) }
328 }
329
330 #[inline]
332 pub fn capacity(&self) -> usize {
333 self.bytes.capacity()
334 }
335
336 #[inline]
338 pub fn push_str(&mut self, other: &str) {
339 self.bytes.extend_from_slice(other.as_bytes())
340 }
341
342 #[inline]
348 pub fn push_wtf8(&mut self, other: &Wtf8) {
349 match ((&*self).final_lead_surrogate(), other.initial_trail_surrogate()) {
350 (Some(lead), Some(trail)) => {
352 let len_without_lead_surrogate = self.len() - 3;
353 self.bytes.truncate(len_without_lead_surrogate);
354 let other_without_trail_surrogate = &other.bytes[3..];
355 self.bytes.reserve(4 + other_without_trail_surrogate.len());
357 self.push_char(decode_surrogate_pair(lead, trail));
358 self.bytes.extend_from_slice(other_without_trail_surrogate);
359 }
360 _ => {
361 if other.next_surrogate(0).is_some() {
364 self.is_known_utf8 = false;
365 }
366
367 self.bytes.extend_from_slice(&other.bytes);
368 }
369 }
370 }
371
372 #[inline]
374 pub fn push_char(&mut self, c: char) {
375 self.push_code_point_unchecked(CodePoint::from_char(c))
376 }
377
378 #[inline]
384 pub fn push(&mut self, code_point: CodePoint) {
385 if let Some(trail) = code_point.to_trail_surrogate() {
386 if let Some(lead) = (&*self).final_lead_surrogate() {
387 let len_without_lead_surrogate = self.len() - 3;
388 self.bytes.truncate(len_without_lead_surrogate);
389 self.push_char(decode_surrogate_pair(lead, trail));
390 return;
391 }
392
393 self.is_known_utf8 = false;
395 } else if code_point.to_lead_surrogate().is_some() {
396 self.is_known_utf8 = false;
398 }
399
400 self.push_code_point_unchecked(code_point)
402 }
403
404 #[inline]
411 pub fn truncate(&mut self, new_len: usize) {
412 assert!(is_code_point_boundary(self, new_len));
413 self.bytes.truncate(new_len)
414 }
415
416 #[inline]
418 pub fn into_bytes(self) -> Vec<u8> {
419 self.bytes
420 }
421
422 pub fn into_string(self) -> Result<String, Wtf8Buf> {
430 if self.is_known_utf8 || self.next_surrogate(0).is_none() {
431 Ok(unsafe { String::from_utf8_unchecked(self.bytes) })
432 } else {
433 Err(self)
434 }
435 }
436
437 pub fn into_string_lossy(mut self) -> String {
443 if self.is_known_utf8 {
445 return unsafe { String::from_utf8_unchecked(self.bytes) };
446 }
447
448 let mut pos = 0;
449 loop {
450 match self.next_surrogate(pos) {
451 Some((surrogate_pos, _)) => {
452 pos = surrogate_pos + 3;
453 self.bytes[surrogate_pos..pos]
454 .copy_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes());
455 }
456 None => return unsafe { String::from_utf8_unchecked(self.bytes) },
457 }
458 }
459 }
460
461 #[inline]
463 pub fn into_box(self) -> Box<Wtf8> {
464 unsafe { mem::transmute(self.bytes.into_boxed_slice()) }
466 }
467
468 pub fn from_box(boxed: Box<Wtf8>) -> Wtf8Buf {
470 let bytes: Box<[u8]> = unsafe { mem::transmute(boxed) };
471 Wtf8Buf { bytes: bytes.into_vec(), is_known_utf8: false }
472 }
473
474 #[inline]
478 pub(crate) fn extend_from_slice(&mut self, other: &[u8]) {
479 self.bytes.extend_from_slice(other);
480 self.is_known_utf8 = false;
481 }
482}
483
484impl FromIterator<CodePoint> for Wtf8Buf {
489 fn from_iter<T: IntoIterator<Item = CodePoint>>(iter: T) -> Wtf8Buf {
490 let mut string = Wtf8Buf::new();
491 string.extend(iter);
492 string
493 }
494}
495
496impl Extend<CodePoint> for Wtf8Buf {
501 fn extend<T: IntoIterator<Item = CodePoint>>(&mut self, iter: T) {
502 let iterator = iter.into_iter();
503 let (low, _high) = iterator.size_hint();
504 self.bytes.reserve(low);
506 iterator.for_each(move |code_point| self.push(code_point));
507 }
508
509 #[inline]
510 fn extend_one(&mut self, code_point: CodePoint) {
511 self.push(code_point);
512 }
513
514 #[inline]
515 fn extend_reserve(&mut self, additional: usize) {
516 self.bytes.reserve(additional);
518 }
519}
520
521#[derive(Eq, Ord, PartialEq, PartialOrd)]
526#[repr(transparent)]
527pub struct Wtf8 {
528 bytes: [u8],
529}
530
531impl AsInner<[u8]> for Wtf8 {
532 #[inline]
533 fn as_inner(&self) -> &[u8] {
534 &self.bytes
535 }
536}
537
538impl fmt::Debug for Wtf8 {
542 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
543 fn write_str_escaped(f: &mut fmt::Formatter<'_>, s: &str) -> fmt::Result {
544 use crate::fmt::Write;
545 for c in s.chars().flat_map(|c| c.escape_debug()) {
546 f.write_char(c)?
547 }
548 Ok(())
549 }
550
551 formatter.write_str("\"")?;
552 let mut pos = 0;
553 while let Some((surrogate_pos, surrogate)) = self.next_surrogate(pos) {
554 write_str_escaped(formatter, unsafe {
555 str::from_utf8_unchecked(&self.bytes[pos..surrogate_pos])
556 })?;
557 write!(formatter, "\\u{{{:x}}}", surrogate)?;
558 pos = surrogate_pos + 3;
559 }
560 write_str_escaped(formatter, unsafe { str::from_utf8_unchecked(&self.bytes[pos..]) })?;
561 formatter.write_str("\"")
562 }
563}
564
565impl fmt::Display for Wtf8 {
566 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
567 let wtf8_bytes = &self.bytes;
568 let mut pos = 0;
569 loop {
570 match self.next_surrogate(pos) {
571 Some((surrogate_pos, _)) => {
572 formatter.write_str(unsafe {
573 str::from_utf8_unchecked(&wtf8_bytes[pos..surrogate_pos])
574 })?;
575 formatter.write_str(UTF8_REPLACEMENT_CHARACTER)?;
576 pos = surrogate_pos + 3;
577 }
578 None => {
579 let s = unsafe { str::from_utf8_unchecked(&wtf8_bytes[pos..]) };
580 if pos == 0 { return s.fmt(formatter) } else { return formatter.write_str(s) }
581 }
582 }
583 }
584 }
585}
586
587impl Wtf8 {
588 #[inline]
592 pub fn from_str(value: &str) -> &Wtf8 {
593 unsafe { Wtf8::from_bytes_unchecked(value.as_bytes()) }
594 }
595
596 #[inline]
601 pub unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 {
602 unsafe { &*(value as *const [u8] as *const Wtf8) }
604 }
605
606 #[inline]
611 unsafe fn from_mut_bytes_unchecked(value: &mut [u8]) -> &mut Wtf8 {
612 unsafe { &mut *(value as *mut [u8] as *mut Wtf8) }
614 }
615
616 #[inline]
618 pub fn len(&self) -> usize {
619 self.bytes.len()
620 }
621
622 #[inline]
623 pub fn is_empty(&self) -> bool {
624 self.bytes.is_empty()
625 }
626
627 #[inline]
634 pub fn ascii_byte_at(&self, position: usize) -> u8 {
635 match self.bytes[position] {
636 ascii_byte @ 0x00..=0x7F => ascii_byte,
637 _ => 0xFF,
638 }
639 }
640
641 #[inline]
643 pub fn code_points(&self) -> Wtf8CodePoints<'_> {
644 Wtf8CodePoints { bytes: self.bytes.iter() }
645 }
646
647 #[inline]
649 pub fn as_bytes(&self) -> &[u8] {
650 &self.bytes
651 }
652
653 #[inline]
659 pub fn as_str(&self) -> Result<&str, str::Utf8Error> {
660 str::from_utf8(&self.bytes)
661 }
662
663 pub fn to_owned(&self) -> Wtf8Buf {
665 Wtf8Buf { bytes: self.bytes.to_vec(), is_known_utf8: false }
666 }
667
668 pub fn to_string_lossy(&self) -> Cow<'_, str> {
675 let surrogate_pos = match self.next_surrogate(0) {
676 None => return Cow::Borrowed(unsafe { str::from_utf8_unchecked(&self.bytes) }),
677 Some((pos, _)) => pos,
678 };
679 let wtf8_bytes = &self.bytes;
680 let mut utf8_bytes = Vec::with_capacity(self.len());
681 utf8_bytes.extend_from_slice(&wtf8_bytes[..surrogate_pos]);
682 utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes());
683 let mut pos = surrogate_pos + 3;
684 loop {
685 match self.next_surrogate(pos) {
686 Some((surrogate_pos, _)) => {
687 utf8_bytes.extend_from_slice(&wtf8_bytes[pos..surrogate_pos]);
688 utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes());
689 pos = surrogate_pos + 3;
690 }
691 None => {
692 utf8_bytes.extend_from_slice(&wtf8_bytes[pos..]);
693 return Cow::Owned(unsafe { String::from_utf8_unchecked(utf8_bytes) });
694 }
695 }
696 }
697 }
698
699 #[inline]
706 pub fn encode_wide(&self) -> EncodeWide<'_> {
707 EncodeWide { code_points: self.code_points(), extra: 0 }
708 }
709
710 #[inline]
711 fn next_surrogate(&self, mut pos: usize) -> Option<(usize, u16)> {
712 let mut iter = self.bytes[pos..].iter();
713 loop {
714 let b = *iter.next()?;
715 if b < 0x80 {
716 pos += 1;
717 } else if b < 0xE0 {
718 iter.next();
719 pos += 2;
720 } else if b == 0xED {
721 match (iter.next(), iter.next()) {
722 (Some(&b2), Some(&b3)) if b2 >= 0xA0 => {
723 return Some((pos, decode_surrogate(b2, b3)));
724 }
725 _ => pos += 3,
726 }
727 } else if b < 0xF0 {
728 iter.next();
729 iter.next();
730 pos += 3;
731 } else {
732 iter.next();
733 iter.next();
734 iter.next();
735 pos += 4;
736 }
737 }
738 }
739
740 #[inline]
741 fn final_lead_surrogate(&self) -> Option<u16> {
742 match self.bytes {
743 [.., 0xED, b2 @ 0xA0..=0xAF, b3] => Some(decode_surrogate(b2, b3)),
744 _ => None,
745 }
746 }
747
748 #[inline]
749 fn initial_trail_surrogate(&self) -> Option<u16> {
750 match self.bytes {
751 [0xED, b2 @ 0xB0..=0xBF, b3, ..] => Some(decode_surrogate(b2, b3)),
752 _ => None,
753 }
754 }
755
756 pub fn clone_into(&self, buf: &mut Wtf8Buf) {
757 buf.is_known_utf8 = false;
758 self.bytes.clone_into(&mut buf.bytes);
759 }
760
761 #[inline]
763 pub fn into_box(&self) -> Box<Wtf8> {
764 let boxed: Box<[u8]> = self.bytes.into();
765 unsafe { mem::transmute(boxed) }
766 }
767
768 pub fn empty_box() -> Box<Wtf8> {
770 let boxed: Box<[u8]> = Default::default();
771 unsafe { mem::transmute(boxed) }
772 }
773
774 #[inline]
775 pub fn into_arc(&self) -> Arc<Wtf8> {
776 let arc: Arc<[u8]> = Arc::from(&self.bytes);
777 unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Wtf8) }
778 }
779
780 #[inline]
781 pub fn into_rc(&self) -> Rc<Wtf8> {
782 let rc: Rc<[u8]> = Rc::from(&self.bytes);
783 unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Wtf8) }
784 }
785
786 #[inline]
787 pub fn make_ascii_lowercase(&mut self) {
788 self.bytes.make_ascii_lowercase()
789 }
790
791 #[inline]
792 pub fn make_ascii_uppercase(&mut self) {
793 self.bytes.make_ascii_uppercase()
794 }
795
796 #[inline]
797 pub fn to_ascii_lowercase(&self) -> Wtf8Buf {
798 Wtf8Buf { bytes: self.bytes.to_ascii_lowercase(), is_known_utf8: false }
799 }
800
801 #[inline]
802 pub fn to_ascii_uppercase(&self) -> Wtf8Buf {
803 Wtf8Buf { bytes: self.bytes.to_ascii_uppercase(), is_known_utf8: false }
804 }
805
806 #[inline]
807 pub fn is_ascii(&self) -> bool {
808 self.bytes.is_ascii()
809 }
810
811 #[inline]
812 pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
813 self.bytes.eq_ignore_ascii_case(&other.bytes)
814 }
815}
816
817impl ops::Index<ops::Range<usize>> for Wtf8 {
824 type Output = Wtf8;
825
826 #[inline]
827 fn index(&self, range: ops::Range<usize>) -> &Wtf8 {
828 if range.start <= range.end
830 && is_code_point_boundary(self, range.start)
831 && is_code_point_boundary(self, range.end)
832 {
833 unsafe { slice_unchecked(self, range.start, range.end) }
834 } else {
835 slice_error_fail(self, range.start, range.end)
836 }
837 }
838}
839
840impl ops::Index<ops::RangeFrom<usize>> for Wtf8 {
847 type Output = Wtf8;
848
849 #[inline]
850 fn index(&self, range: ops::RangeFrom<usize>) -> &Wtf8 {
851 if is_code_point_boundary(self, range.start) {
853 unsafe { slice_unchecked(self, range.start, self.len()) }
854 } else {
855 slice_error_fail(self, range.start, self.len())
856 }
857 }
858}
859
860impl ops::Index<ops::RangeTo<usize>> for Wtf8 {
867 type Output = Wtf8;
868
869 #[inline]
870 fn index(&self, range: ops::RangeTo<usize>) -> &Wtf8 {
871 if is_code_point_boundary(self, range.end) {
873 unsafe { slice_unchecked(self, 0, range.end) }
874 } else {
875 slice_error_fail(self, 0, range.end)
876 }
877 }
878}
879
880impl ops::Index<ops::RangeFull> for Wtf8 {
881 type Output = Wtf8;
882
883 #[inline]
884 fn index(&self, _range: ops::RangeFull) -> &Wtf8 {
885 self
886 }
887}
888
889#[inline]
890fn decode_surrogate(second_byte: u8, third_byte: u8) -> u16 {
891 0xD800 | (second_byte as u16 & 0x3F) << 6 | third_byte as u16 & 0x3F
893}
894
895#[inline]
896fn decode_surrogate_pair(lead: u16, trail: u16) -> char {
897 let code_point = 0x10000 + ((((lead - 0xD800) as u32) << 10) | (trail - 0xDC00) as u32);
898 unsafe { char::from_u32_unchecked(code_point) }
899}
900
901#[inline]
903pub fn is_code_point_boundary(slice: &Wtf8, index: usize) -> bool {
904 if index == 0 {
905 return true;
906 }
907 match slice.bytes.get(index) {
908 None => index == slice.len(),
909 Some(&b) => (b as i8) >= -0x40,
910 }
911}
912
913#[track_caller]
921#[inline]
922pub fn check_utf8_boundary(slice: &Wtf8, index: usize) {
923 if index == 0 {
924 return;
925 }
926 match slice.bytes.get(index) {
927 Some(0xED) => (), Some(&b) if (b as i8) >= -0x40 => return,
929 Some(_) => panic!("byte index {index} is not a codepoint boundary"),
930 None if index == slice.len() => return,
931 None => panic!("byte index {index} is out of bounds"),
932 }
933 if slice.bytes[index + 1] >= 0xA0 {
934 if index >= 3 && slice.bytes[index - 3] == 0xED && slice.bytes[index - 2] >= 0xA0 {
936 panic!("byte index {index} lies between surrogate codepoints");
937 }
938 }
939}
940
941#[inline]
943pub unsafe fn slice_unchecked(s: &Wtf8, begin: usize, end: usize) -> &Wtf8 {
944 unsafe {
946 let len = end - begin;
947 let start = s.as_bytes().as_ptr().add(begin);
948 Wtf8::from_bytes_unchecked(slice::from_raw_parts(start, len))
949 }
950}
951
952#[inline(never)]
954pub fn slice_error_fail(s: &Wtf8, begin: usize, end: usize) -> ! {
955 assert!(begin <= end);
956 panic!("index {begin} and/or {end} in `{s:?}` do not lie on character boundary");
957}
958
959#[derive(Clone)]
963pub struct Wtf8CodePoints<'a> {
964 bytes: slice::Iter<'a, u8>,
965}
966
967impl<'a> Iterator for Wtf8CodePoints<'a> {
968 type Item = CodePoint;
969
970 #[inline]
971 fn next(&mut self) -> Option<CodePoint> {
972 unsafe { next_code_point(&mut self.bytes).map(|c| CodePoint { value: c }) }
974 }
975
976 #[inline]
977 fn size_hint(&self) -> (usize, Option<usize>) {
978 let len = self.bytes.len();
979 (len.saturating_add(3) / 4, Some(len))
980 }
981}
982
983#[stable(feature = "rust1", since = "1.0.0")]
985#[derive(Clone)]
986pub struct EncodeWide<'a> {
987 code_points: Wtf8CodePoints<'a>,
988 extra: u16,
989}
990
991#[stable(feature = "rust1", since = "1.0.0")]
993impl<'a> Iterator for EncodeWide<'a> {
994 type Item = u16;
995
996 #[inline]
997 fn next(&mut self) -> Option<u16> {
998 if self.extra != 0 {
999 let tmp = self.extra;
1000 self.extra = 0;
1001 return Some(tmp);
1002 }
1003
1004 let mut buf = [0; 2];
1005 self.code_points.next().map(|code_point| {
1006 let n = encode_utf16_raw(code_point.value, &mut buf).len();
1007 if n == 2 {
1008 self.extra = buf[1];
1009 }
1010 buf[0]
1011 })
1012 }
1013
1014 #[inline]
1015 fn size_hint(&self) -> (usize, Option<usize>) {
1016 let (low, high) = self.code_points.size_hint();
1017 let ext = (self.extra != 0) as usize;
1018 (low + ext, high.and_then(|n| n.checked_mul(2)).and_then(|n| n.checked_add(ext)))
1022 }
1023}
1024
1025#[stable(feature = "encode_wide_fused_iterator", since = "1.62.0")]
1026impl FusedIterator for EncodeWide<'_> {}
1027
1028impl Hash for CodePoint {
1029 #[inline]
1030 fn hash<H: Hasher>(&self, state: &mut H) {
1031 self.value.hash(state)
1032 }
1033}
1034
1035impl Hash for Wtf8Buf {
1036 #[inline]
1037 fn hash<H: Hasher>(&self, state: &mut H) {
1038 state.write(&self.bytes);
1039 0xfeu8.hash(state)
1040 }
1041}
1042
1043impl Hash for Wtf8 {
1044 #[inline]
1045 fn hash<H: Hasher>(&self, state: &mut H) {
1046 state.write(&self.bytes);
1047 0xfeu8.hash(state)
1048 }
1049}
1050
1051#[unstable(feature = "clone_to_uninit", issue = "126799")]
1052unsafe impl CloneToUninit for Wtf8 {
1053 #[inline]
1054 #[cfg_attr(debug_assertions, track_caller)]
1055 unsafe fn clone_to_uninit(&self, dst: *mut u8) {
1056 unsafe { self.bytes.clone_to_uninit(dst) }
1058 }
1059}