1use std::char::ParseCharError;
2use std::cmp::Ordering;
3use std::fmt;
4use std::fmt::{Debug, Display, Formatter, Write};
5use std::hash::{Hash, Hasher};
6use std::iter::{FusedIterator, Once, once};
7use std::ops::Range;
8use std::str::FromStr;
9
10use crate::validations::{TAG_CONT, TAG_FOUR_B, TAG_THREE_B, TAG_TWO_B};
11
12#[derive(Copy, Clone, PartialEq, Eq)]
16#[repr(C)]
17pub struct JavaCodePoint {
18 #[cfg(target_endian = "little")]
19 lower: u16,
20 upper: SeventeenValues,
21 #[cfg(target_endian = "big")]
22 lower: u16,
23}
24
25#[repr(u16)]
26#[derive(Copy, Clone, PartialEq, Eq)]
27#[allow(unused)]
28enum SeventeenValues {
29 V0,
30 V1,
31 V2,
32 V3,
33 V4,
34 V5,
35 V6,
36 V7,
37 V8,
38 V9,
39 V10,
40 V11,
41 V12,
42 V13,
43 V14,
44 V15,
45 V16,
46}
47
48impl JavaCodePoint {
49 pub const MAX: JavaCodePoint = JavaCodePoint::from_char(char::MAX);
50 pub const REPLACEMENT_CHARACTER: JavaCodePoint =
51 JavaCodePoint::from_char(char::REPLACEMENT_CHARACTER);
52
53 #[inline]
63 #[must_use]
64 pub const fn from_u32(i: u32) -> Option<JavaCodePoint> {
65 if i <= 0x10ffff {
66 unsafe { Some(Self::from_u32_unchecked(i)) }
67 } else {
68 None
69 }
70 }
71
72 #[inline]
76 #[must_use]
77 pub const unsafe fn from_u32_unchecked(i: u32) -> JavaCodePoint {
78 unsafe {
79 std::mem::transmute(i)
81 }
82 }
83
84 #[inline]
86 #[must_use]
87 pub const fn from_char(char: char) -> JavaCodePoint {
88 unsafe {
89 JavaCodePoint::from_u32_unchecked(char as u32)
91 }
92 }
93
94 #[inline]
102 #[must_use]
103 pub const fn as_u32(self) -> u32 {
104 unsafe {
105 let result = std::mem::transmute::<Self, u32>(self);
107
108 if result > 0x10ffff {
109 std::hint::unreachable_unchecked();
113 }
114
115 result
116 }
117 }
118
119 #[inline]
127 #[must_use]
128 pub const fn as_char(self) -> Option<char> {
129 char::from_u32(self.as_u32())
130 }
131
132 #[inline]
136 #[must_use]
137 pub unsafe fn as_char_unchecked(self) -> char {
138 unsafe {
139 char::from_u32_unchecked(self.as_u32())
141 }
142 }
143
144 #[inline]
168 pub fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] {
169 if let Some(char) = self.as_char() {
170 char.encode_utf16(dst)
171 } else {
172 dst[0] = self.as_u32() as u16;
173 &mut dst[..1]
174 }
175 }
176
177 #[inline]
202 pub fn encode_semi_utf8(self, dst: &mut [u8]) -> &mut [u8] {
203 let len = self.len_utf8();
204 let code = self.as_u32();
205 match (len, &mut dst[..]) {
206 (1, [a, ..]) => {
207 *a = code as u8;
208 }
209 (2, [a, b, ..]) => {
210 *a = ((code >> 6) & 0x1f) as u8 | TAG_TWO_B;
211 *b = (code & 0x3f) as u8 | TAG_CONT;
212 }
213 (3, [a, b, c, ..]) => {
214 *a = ((code >> 12) & 0x0f) as u8 | TAG_THREE_B;
215 *b = ((code >> 6) & 0x3f) as u8 | TAG_CONT;
216 *c = (code & 0x3f) as u8 | TAG_CONT;
217 }
218 (4, [a, b, c, d, ..]) => {
219 *a = ((code >> 18) & 0x07) as u8 | TAG_FOUR_B;
220 *b = ((code >> 12) & 0x3f) as u8 | TAG_CONT;
221 *c = ((code >> 6) & 0x3f) as u8 | TAG_CONT;
222 *d = (code & 0x3f) as u8 | TAG_CONT;
223 }
224 _ => panic!(
225 "encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}",
226 len,
227 code,
228 dst.len()
229 ),
230 }
231 &mut dst[..len]
232 }
233
234 #[inline]
236 pub fn eq_ignore_ascii_case(&self, other: &JavaCodePoint) -> bool {
237 match (self.as_char(), other.as_char()) {
238 (Some(char1), Some(char2)) => char1.eq_ignore_ascii_case(&char2),
239 (None, None) => self == other,
240 _ => false,
241 }
242 }
243
244 #[inline]
265 #[must_use]
266 pub fn escape_debug(self) -> CharEscapeIter {
267 self.escape_debug_ext(EscapeDebugExtArgs::ESCAPE_ALL)
268 }
269
270 #[inline]
271 #[must_use]
272 pub(crate) fn escape_debug_ext(self, args: EscapeDebugExtArgs) -> CharEscapeIter {
273 const NULL: u32 = '\0' as u32;
274 const TAB: u32 = '\t' as u32;
275 const CARRIAGE_RETURN: u32 = '\r' as u32;
276 const LINE_FEED: u32 = '\n' as u32;
277 const SINGLE_QUOTE: u32 = '\'' as u32;
278 const DOUBLE_QUOTE: u32 = '"' as u32;
279 const BACKSLASH: u32 = '\\' as u32;
280
281 unsafe {
282 match self.as_u32() {
284 NULL => CharEscapeIter::new(*b"\\0"),
285 TAB => CharEscapeIter::new(*b"\\t"),
286 CARRIAGE_RETURN => CharEscapeIter::new(*b"\\r"),
287 LINE_FEED => CharEscapeIter::new(*b"\\n"),
288 SINGLE_QUOTE if args.escape_single_quote => CharEscapeIter::new(*b"\\'"),
289 DOUBLE_QUOTE if args.escape_double_quote => CharEscapeIter::new(*b"\\\""),
290 BACKSLASH => CharEscapeIter::new(*b"\\\\"),
291 _ if self.is_printable() => {
292 CharEscapeIter::printable(self.as_char_unchecked())
294 }
295 _ => self.escape_unicode(),
296 }
297 }
298 }
299
300 #[inline]
301 fn is_printable(self) -> bool {
302 let Some(char) = self.as_char() else {
303 return false;
304 };
305 if matches!(char, '\\' | '\'' | '"') {
306 return true;
307 }
308 char.escape_debug().next() != Some('\\')
309 }
310
311 #[inline]
332 #[must_use]
333 pub fn escape_default(self) -> CharEscapeIter {
334 const TAB: u32 = '\t' as u32;
335 const CARRIAGE_RETURN: u32 = '\r' as u32;
336 const LINE_FEED: u32 = '\n' as u32;
337 const SINGLE_QUOTE: u32 = '\'' as u32;
338 const DOUBLE_QUOTE: u32 = '"' as u32;
339 const BACKSLASH: u32 = '\\' as u32;
340
341 unsafe {
342 match self.as_u32() {
344 TAB => CharEscapeIter::new(*b"\\t"),
345 CARRIAGE_RETURN => CharEscapeIter::new(*b"\\r"),
346 LINE_FEED => CharEscapeIter::new(*b"\\n"),
347 SINGLE_QUOTE => CharEscapeIter::new(*b"\\'"),
348 DOUBLE_QUOTE => CharEscapeIter::new(*b"\\\""),
349 BACKSLASH => CharEscapeIter::new(*b"\\\\"),
350 0x20..=0x7e => CharEscapeIter::new([self.as_u32() as u8]),
351 _ => self.escape_unicode(),
352 }
353 }
354 }
355
356 #[inline]
373 #[must_use]
374 pub fn escape_unicode(self) -> CharEscapeIter {
375 let x = self.as_u32();
376
377 let mut arr = [0; 10];
378 arr[0] = b'\\';
379 arr[1] = b'u';
380 arr[2] = b'{';
381
382 let number_len = if x == 0 {
383 1
384 } else {
385 ((x.ilog2() >> 2) + 1) as usize
386 };
387 arr[3 + number_len] = b'}';
388 for hexit in 0..number_len {
389 arr[2 + number_len - hexit] = b"0123456789abcdef"[((x >> (hexit << 2)) & 15) as usize];
390 }
391
392 CharEscapeIter {
393 inner: EscapeIterInner::Escaped(EscapeIterEscaped {
394 bytes: arr,
395 range: 0..number_len + 4,
396 }),
397 }
398 }
399
400 #[inline]
402 #[must_use]
403 pub fn is_alphabetic(self) -> bool {
404 self.as_char().is_some_and(|char| char.is_alphabetic())
405 }
406
407 #[inline]
409 #[must_use]
410 pub fn is_alphanumeric(self) -> bool {
411 self.as_char().is_some_and(|char| char.is_alphanumeric())
412 }
413
414 #[inline]
416 #[must_use]
417 pub fn is_ascii(self) -> bool {
418 self.as_u32() <= 0x7f
419 }
420
421 #[inline]
423 #[must_use]
424 pub const fn is_ascii_alphabetic(self) -> bool {
425 self.is_ascii_lowercase() || self.is_ascii_uppercase()
426 }
427
428 #[inline]
430 #[must_use]
431 pub const fn is_ascii_alphanumeric(self) -> bool {
432 self.is_ascii_alphabetic() || self.is_ascii_digit()
433 }
434
435 #[inline]
437 #[must_use]
438 pub const fn is_ascii_control(self) -> bool {
439 matches!(self.as_u32(), 0..=0x1f | 0x7f)
440 }
441
442 #[inline]
444 #[must_use]
445 pub const fn is_ascii_digit(self) -> bool {
446 const ZERO: u32 = '0' as u32;
447 const NINE: u32 = '9' as u32;
448 matches!(self.as_u32(), ZERO..=NINE)
449 }
450
451 #[inline]
453 #[must_use]
454 pub const fn is_ascii_graphic(self) -> bool {
455 matches!(self.as_u32(), 0x21..=0x7e)
456 }
457
458 #[inline]
460 #[must_use]
461 pub const fn is_ascii_hexdigit(self) -> bool {
462 const LOWER_A: u32 = 'a' as u32;
463 const LOWER_F: u32 = 'f' as u32;
464 const UPPER_A: u32 = 'A' as u32;
465 const UPPER_F: u32 = 'F' as u32;
466 self.is_ascii_digit() || matches!(self.as_u32(), (LOWER_A..=LOWER_F) | (UPPER_A..=UPPER_F))
467 }
468
469 #[inline]
471 #[must_use]
472 pub const fn is_ascii_lowercase(self) -> bool {
473 const A: u32 = 'a' as u32;
474 const Z: u32 = 'z' as u32;
475 matches!(self.as_u32(), A..=Z)
476 }
477
478 #[inline]
480 #[must_use]
481 pub const fn is_ascii_octdigit(self) -> bool {
482 const ZERO: u32 = '0' as u32;
483 const SEVEN: u32 = '7' as u32;
484 matches!(self.as_u32(), ZERO..=SEVEN)
485 }
486
487 #[inline]
489 #[must_use]
490 pub const fn is_ascii_punctuation(self) -> bool {
491 matches!(
492 self.as_u32(),
493 (0x21..=0x2f) | (0x3a..=0x40) | (0x5b..=0x60) | (0x7b..=0x7e)
494 )
495 }
496
497 #[inline]
499 #[must_use]
500 pub const fn is_ascii_uppercase(self) -> bool {
501 const A: u32 = 'A' as u32;
502 const Z: u32 = 'Z' as u32;
503 matches!(self.as_u32(), A..=Z)
504 }
505
506 #[inline]
508 #[must_use]
509 pub const fn is_ascii_whitespace(self) -> bool {
510 const SPACE: u32 = ' ' as u32;
511 const HORIZONTAL_TAB: u32 = '\t' as u32;
512 const LINE_FEED: u32 = '\n' as u32;
513 const FORM_FEED: u32 = 0xc;
514 const CARRIAGE_RETURN: u32 = '\r' as u32;
515 matches!(
516 self.as_u32(),
517 SPACE | HORIZONTAL_TAB | LINE_FEED | FORM_FEED | CARRIAGE_RETURN
518 )
519 }
520
521 #[inline]
523 #[must_use]
524 pub fn is_control(self) -> bool {
525 self.as_char().is_some_and(|char| char.is_control())
526 }
527
528 #[inline]
530 #[must_use]
531 pub fn is_digit(self, radix: u32) -> bool {
532 self.to_digit(radix).is_some()
533 }
534
535 #[inline]
537 #[must_use]
538 pub fn is_lowercase(self) -> bool {
539 self.as_char().is_some_and(|char| char.is_lowercase())
540 }
541
542 #[inline]
544 #[must_use]
545 pub fn is_numeric(self) -> bool {
546 self.as_char().is_some_and(|char| char.is_numeric())
547 }
548
549 #[inline]
551 #[must_use]
552 pub fn is_uppercase(self) -> bool {
553 self.as_char().is_some_and(|char| char.is_uppercase())
554 }
555
556 #[inline]
558 #[must_use]
559 pub fn is_whitespace(self) -> bool {
560 self.as_char().is_some_and(|char| char.is_whitespace())
561 }
562
563 #[inline]
577 #[must_use]
578 pub const fn len_utf16(self) -> usize {
579 if let Some(char) = self.as_char() {
580 char.len_utf16()
581 } else {
582 1 }
584 }
585
586 #[inline]
607 #[must_use]
608 pub const fn len_utf8(self) -> usize {
609 if let Some(char) = self.as_char() {
610 char.len_utf8()
611 } else {
612 3 }
614 }
615
616 #[inline]
618 pub fn make_ascii_lowercase(&mut self) {
619 *self = self.to_ascii_lowercase();
620 }
621
622 #[inline]
624 pub fn make_ascii_uppercase(&mut self) {
625 *self = self.to_ascii_uppercase();
626 }
627
628 #[inline]
640 #[must_use]
641 pub const fn to_ascii_lowercase(self) -> JavaCodePoint {
642 if self.is_ascii_uppercase() {
643 unsafe {
644 Self::from_u32_unchecked(self.as_u32() + 32)
646 }
647 } else {
648 self
649 }
650 }
651
652 #[inline]
664 #[must_use]
665 pub const fn to_ascii_uppercase(self) -> JavaCodePoint {
666 if self.is_ascii_lowercase() {
667 unsafe {
668 Self::from_u32_unchecked(self.as_u32() - 32)
670 }
671 } else {
672 self
673 }
674 }
675
676 #[inline]
678 #[must_use]
679 pub const fn to_digit(self, radix: u32) -> Option<u32> {
680 if let Some(char) = self.as_char() {
681 char.to_digit(radix)
682 } else {
683 None
684 }
685 }
686
687 #[inline]
689 #[must_use]
690 pub fn to_lowercase(self) -> ToLowercase {
691 match self.as_char() {
692 Some(char) => ToLowercase::char(char.to_lowercase()),
693 None => ToLowercase::invalid(self),
694 }
695 }
696
697 #[inline]
699 #[must_use]
700 pub fn to_uppercase(self) -> ToUppercase {
701 match self.as_char() {
702 Some(char) => ToUppercase::char(char.to_uppercase()),
703 None => ToUppercase::invalid(self),
704 }
705 }
706}
707
708impl Debug for JavaCodePoint {
709 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
710 f.write_char('\'')?;
711 for c in self.escape_debug_ext(EscapeDebugExtArgs {
712 escape_single_quote: true,
713 escape_double_quote: false,
714 }) {
715 f.write_char(c)?;
716 }
717 f.write_char('\'')
718 }
719}
720
721impl Default for JavaCodePoint {
722 #[inline]
723 fn default() -> Self {
724 JavaCodePoint::from_char('\0')
725 }
726}
727
728impl Display for JavaCodePoint {
729 #[inline]
730 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
731 Display::fmt(&self.as_char().unwrap_or(char::REPLACEMENT_CHARACTER), f)
732 }
733}
734
735impl From<JavaCodePoint> for u32 {
736 #[inline]
737 fn from(value: JavaCodePoint) -> Self {
738 value.as_u32()
739 }
740}
741
742impl From<u8> for JavaCodePoint {
743 #[inline]
744 fn from(value: u8) -> Self {
745 JavaCodePoint::from_char(char::from(value))
746 }
747}
748
749impl FromStr for JavaCodePoint {
750 type Err = ParseCharError;
751
752 #[inline]
753 fn from_str(s: &str) -> Result<Self, Self::Err> {
754 char::from_str(s).map(JavaCodePoint::from_char)
755 }
756}
757
758impl Hash for JavaCodePoint {
759 #[inline]
760 fn hash<H: Hasher>(&self, state: &mut H) {
761 self.as_u32().hash(state)
762 }
763}
764
765impl Ord for JavaCodePoint {
766 #[inline]
767 fn cmp(&self, other: &Self) -> Ordering {
768 self.as_u32().cmp(&other.as_u32())
769 }
770}
771
772impl PartialOrd for JavaCodePoint {
773 #[inline]
774 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
775 Some(self.cmp(other))
776 }
777}
778
779impl PartialOrd<char> for JavaCodePoint {
780 #[inline]
781 fn partial_cmp(&self, other: &char) -> Option<Ordering> {
782 self.partial_cmp(&JavaCodePoint::from_char(*other))
783 }
784}
785
786impl PartialOrd<JavaCodePoint> for char {
787 #[inline]
788 fn partial_cmp(&self, other: &JavaCodePoint) -> Option<Ordering> {
789 JavaCodePoint::from_char(*self).partial_cmp(other)
790 }
791}
792
793impl PartialEq<char> for JavaCodePoint {
794 #[inline]
795 fn eq(&self, other: &char) -> bool {
796 self == &JavaCodePoint::from_char(*other)
797 }
798}
799
800impl PartialEq<JavaCodePoint> for char {
801 #[inline]
802 fn eq(&self, other: &JavaCodePoint) -> bool {
803 &JavaCodePoint::from_char(*self) == other
804 }
805}
806
807pub(crate) struct EscapeDebugExtArgs {
808 pub(crate) escape_single_quote: bool,
809 pub(crate) escape_double_quote: bool,
810}
811
812impl EscapeDebugExtArgs {
813 pub(crate) const ESCAPE_ALL: Self = Self {
814 escape_single_quote: true,
815 escape_double_quote: true,
816 };
817}
818
819#[derive(Clone, Debug)]
820pub struct CharEscapeIter {
821 inner: EscapeIterInner,
822}
823
824#[derive(Clone, Debug)]
825enum EscapeIterInner {
826 Printable(Once<char>),
827 Escaped(EscapeIterEscaped),
828}
829
830impl Display for EscapeIterInner {
831 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
832 match self {
833 EscapeIterInner::Printable(char) => char.clone().try_for_each(|ch| f.write_char(ch)),
834 EscapeIterInner::Escaped(escaped) => Display::fmt(escaped, f),
835 }
836 }
837}
838
839impl CharEscapeIter {
840 #[inline]
841 fn printable(char: char) -> Self {
842 CharEscapeIter {
843 inner: EscapeIterInner::Printable(once(char)),
844 }
845 }
846
847 #[inline]
850 unsafe fn new<const N: usize>(bytes: [u8; N]) -> Self {
851 assert!(N <= 10, "Too many bytes in escape iter");
852 let mut ten_bytes = [0; 10];
853 ten_bytes[..N].copy_from_slice(&bytes);
854 CharEscapeIter {
855 inner: EscapeIterInner::Escaped(EscapeIterEscaped {
856 bytes: ten_bytes,
857 range: 0..N,
858 }),
859 }
860 }
861}
862
863impl Iterator for CharEscapeIter {
864 type Item = char;
865
866 #[inline]
867 fn next(&mut self) -> Option<Self::Item> {
868 match &mut self.inner {
869 EscapeIterInner::Printable(printable) => printable.next(),
870 EscapeIterInner::Escaped(escaped) => escaped.next(),
871 }
872 }
873
874 #[inline]
875 fn size_hint(&self) -> (usize, Option<usize>) {
876 match &self.inner {
877 EscapeIterInner::Printable(printable) => printable.size_hint(),
878 EscapeIterInner::Escaped(escaped) => escaped.size_hint(),
879 }
880 }
881}
882
883impl ExactSizeIterator for CharEscapeIter {
884 #[inline]
885 fn len(&self) -> usize {
886 match &self.inner {
887 EscapeIterInner::Printable(printable) => printable.len(),
888 EscapeIterInner::Escaped(escaped) => escaped.len(),
889 }
890 }
891}
892
893impl FusedIterator for CharEscapeIter {}
894
895impl Display for CharEscapeIter {
896 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
897 Display::fmt(&self.inner, f)
898 }
899}
900
901#[derive(Clone, Debug)]
902struct EscapeIterEscaped {
903 bytes: [u8; 10],
905 range: Range<usize>,
907}
908
909impl Iterator for EscapeIterEscaped {
910 type Item = char;
911
912 #[inline]
913 fn next(&mut self) -> Option<Self::Item> {
914 self.range.next().map(|index| unsafe {
915 char::from(*self.bytes.get_unchecked(index))
917 })
918 }
919
920 #[inline]
921 fn size_hint(&self) -> (usize, Option<usize>) {
922 self.range.size_hint()
923 }
924
925 #[inline]
926 fn count(self) -> usize {
927 self.range.len()
928 }
929}
930
931impl ExactSizeIterator for EscapeIterEscaped {
932 #[inline]
933 fn len(&self) -> usize {
934 self.range.len()
935 }
936}
937
938impl FusedIterator for EscapeIterEscaped {}
939
940impl Display for EscapeIterEscaped {
941 #[inline]
942 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
943 let str = unsafe {
944 std::str::from_utf8_unchecked(self.bytes.get_unchecked(self.range.clone()))
946 };
947 f.write_str(str)
948 }
949}
950
951pub type ToLowercase = CharIterDelegate<std::char::ToLowercase>;
952pub type ToUppercase = CharIterDelegate<std::char::ToUppercase>;
953
954#[derive(Debug, Clone)]
955pub struct CharIterDelegate<I>(CharIterDelegateInner<I>);
956
957impl<I> CharIterDelegate<I> {
958 #[inline]
959 fn char(iter: I) -> CharIterDelegate<I> {
960 CharIterDelegate(CharIterDelegateInner::Char(iter))
961 }
962
963 #[inline]
964 fn invalid(code_point: JavaCodePoint) -> CharIterDelegate<I> {
965 CharIterDelegate(CharIterDelegateInner::Invalid(Some(code_point).into_iter()))
966 }
967}
968
969#[derive(Debug, Clone)]
970enum CharIterDelegateInner<I> {
971 Char(I),
972 Invalid(std::option::IntoIter<JavaCodePoint>),
973}
974
975impl<I> Iterator for CharIterDelegate<I>
976where
977 I: Iterator<Item = char>,
978{
979 type Item = JavaCodePoint;
980
981 #[inline]
982 fn next(&mut self) -> Option<Self::Item> {
983 match &mut self.0 {
984 CharIterDelegateInner::Char(char_iter) => {
985 char_iter.next().map(JavaCodePoint::from_char)
986 }
987 CharIterDelegateInner::Invalid(code_point) => code_point.next(),
988 }
989 }
990
991 #[inline]
992 fn size_hint(&self) -> (usize, Option<usize>) {
993 match &self.0 {
994 CharIterDelegateInner::Char(char_iter) => char_iter.size_hint(),
995 CharIterDelegateInner::Invalid(code_point) => code_point.size_hint(),
996 }
997 }
998}
999
1000impl<I> DoubleEndedIterator for CharIterDelegate<I>
1001where
1002 I: Iterator<Item = char> + DoubleEndedIterator,
1003{
1004 #[inline]
1005 fn next_back(&mut self) -> Option<Self::Item> {
1006 match &mut self.0 {
1007 CharIterDelegateInner::Char(char_iter) => {
1008 char_iter.next_back().map(JavaCodePoint::from_char)
1009 }
1010 CharIterDelegateInner::Invalid(code_point) => code_point.next_back(),
1011 }
1012 }
1013}
1014
1015impl<I> ExactSizeIterator for CharIterDelegate<I> where I: Iterator<Item = char> + ExactSizeIterator {}
1016
1017impl<I> FusedIterator for CharIterDelegate<I> where I: Iterator<Item = char> + FusedIterator {}