1#[cfg(feature = "alloc")]
28use alloc::borrow::Cow;
29#[cfg(feature = "alloc")]
30use alloc::string::String;
31#[cfg(feature = "alloc")]
32use alloc::vec::Vec;
33
34use super::DecoderResult;
35use super::in_inclusive_range8;
36use super::in_inclusive_range16;
37use super::in_inclusive_range32;
38use super::in_range16;
39use super::in_range32;
40use crate::ascii::*;
41use crate::utf_8::*;
42
43macro_rules! non_fuzz_debug_assert {
44 ($($arg:tt)*) => (if !cfg!(fuzzing) { debug_assert!($($arg)*); })
45}
46
47cfg_if! {
48 if #[cfg(feature = "simd-accel")] {
49 use ::core::intrinsics::likely;
50 use ::core::intrinsics::unlikely;
51 } else {
52 #[inline(always)]
53 fn likely(b: bool) -> bool {
54 b
55 }
56 #[inline(always)]
57 fn unlikely(b: bool) -> bool {
58 b
59 }
60 }
61}
62
63#[must_use]
67#[derive(Debug, PartialEq, Eq)]
68#[repr(C)]
69pub enum Latin1Bidi {
70 Latin1 = 0,
72 LeftToRight = 1,
75 Bidi = 2,
77}
78
79#[inline(always)]
80#[crate::multiversion(targets("x86_64+avx2+bmi1", "x86+avx2+bmi1"))]
81fn is_utf8_latin1_impl(buffer: &[u8]) -> Option<usize> {
82 let mut bytes = buffer;
83 let mut total = 0;
84 loop {
85 if let Some((byte, offset)) = validate_ascii(bytes) {
86 total += offset;
87 if in_inclusive_range8(byte, 0xC2, 0xC3) {
88 let next = offset + 1;
89 if next == bytes.len() {
90 return Some(total);
91 }
92 if bytes[next] & 0xC0 != 0x80 {
93 return Some(total);
94 }
95 bytes = &bytes[offset + 2..];
96 total += 2;
97 } else {
98 return Some(total);
99 }
100 } else {
101 return None;
102 }
103 }
104}
105
106macro_rules! copy_impl {
107 ($name:ident, $stride:ident, $src_unit:ty, $dst_unit:ty) => {
108 #[inline(always)]
109 fn $name(src: &[$src_unit], dst: &mut [$dst_unit]) {
110 let len = core::cmp::min(src.len(), dst.len());
112 let (src_strides, src_tail) = src[..len].as_chunks::<STRIDE>();
113 let (dst_strides, dst_tail) = dst[..len].as_chunks_mut::<STRIDE>();
114 let (src_double_strides, src_single_stride) = src_strides.as_chunks::<2>();
115 let (dst_double_strides, dst_single_stride) = dst_strides.as_chunks_mut::<2>();
116 for (src_double_stride, dst_double_stride) in
117 src_double_strides.iter().zip(dst_double_strides.iter_mut())
118 {
119 $stride(&src_double_stride[0], &mut dst_double_stride[0]);
120 $stride(&src_double_stride[1], &mut dst_double_stride[1]);
121 }
122 for (src_stride, dst_stride) in
123 src_single_stride.iter().zip(dst_single_stride.iter_mut())
124 {
125 $stride(src_stride, dst_stride);
126 }
127 for (src_slot, dst_slot) in src_tail.iter().zip(dst_tail.iter_mut()) {
128 *dst_slot = *src_slot as $dst_unit;
129 }
130 }
131 };
132}
133
134copy_impl!(unpack_latin1, unpack_stride, u8, u16);
135copy_impl!(pack_latin1, pack_stride, u16, u8);
136
137cfg_if! {
138 if #[cfg(all(
139 feature = "simd-accel",
140 target_endian = "little",
141 ))] {
142 use core::simd::u8x16;
143 use core::simd::u16x8;
144
145 use crate::simd_funcs::unpack_stride;
146 use crate::simd_funcs::pack_stride;
147
148 #[crate::multiversion(targets("x86_64+avx2+bmi1", "x86+avx2+bmi1"))]
149 fn is_utf16_bidi_impl(buffer: &[u16]) -> bool {
150 let (half_strides, tail) = buffer.as_chunks::<{STRIDE / 2}>();
151 for half_stride in half_strides {
152 if crate::simd_funcs::is_half_stride_bidi(half_stride) {
153 return true;
154 }
155 }
156 tail.iter().any(|c| is_utf16_code_unit_bidi(*c))
157 }
158
159 #[inline(always)]
160 fn is_str_latin1_bool_impl(buffer: &str) -> bool {
161 let (strides, tail) = buffer.as_bytes().as_chunks::<STRIDE>();
162 for stride in strides {
163 let simd = (*stride).into();
164 if !crate::simd_funcs::simd_is_str_latin1(simd) {
165 return false;
166 }
167 }
168 tail.iter().all(|b| *b < 0xC4)
169 }
170
171 macro_rules! unit_check_impl {
172 ($name:ident, $stride:ident, $unit:ty, $simd:ty, $bound:expr) => {
173 #[inline(always)]
174 fn $name(buffer: &[$unit]) -> bool {
175 if let Some(u) = buffer.first() {
178 if *u >= $bound {
179 return false;
180 }
181 }
182 let (strides, tail) = buffer.as_chunks::<{STRIDE / core::mem::size_of::<$unit>()}>();
183 let (quad_strides, strides_tail) = strides.as_chunks::<4>();
184 for quad_stride in quad_strides {
185 if let Some(reduced) = quad_stride.iter().map(|s| { let simd: $simd = (*s).into(); simd }).reduce(|a, b| a | b) {
186 if !crate::simd_funcs::$stride(reduced) {
187 return false;
188 }
189 } else {
190 debug_assert!(false);
191 }
192 }
193 if let Some(reduced) = strides_tail.iter().map(|s| { let simd: $simd = (*s).into(); simd }).reduce(|a, b| a | b) {
194 if !crate::simd_funcs::$stride(reduced) {
195 return false;
196 }
197 }
198 if let Some(reduced) = tail.iter().copied().reduce(|a, b| a | b) {
199 reduced < $bound
200 } else {
201 true
202 }
203 }
204 };
205 }
206
207 unit_check_impl!(is_ascii_impl, simd_is_ascii, u8, u8x16, 0x80);
208 unit_check_impl!(is_basic_latin_impl, simd_is_basic_latin, u16, u16x8, 0x80);
209 unit_check_impl!(is_utf16_latin1_impl, simd_is_latin1, u16, u16x8, 0x100);
210
211 #[inline(always)]
212 fn check_utf16_for_latin1_and_bidi_impl(buffer: &[u16]) -> Latin1Bidi {
213 let (half_strides, tail) = buffer.as_chunks::<{STRIDE / 2}>();
214 let mut half_stride_iter = half_strides.iter();
215 loop {
216 let Some(s) = half_stride_iter.next() else {
217 let mut iter = tail.iter();
218 loop {
219 let Some(u) = iter.next() else {
220 return Latin1Bidi::Latin1;
221 };
222 if *u < 0x100 {
223 continue;
224 }
225 if is_utf16_code_unit_bidi(*u) {
226 return Latin1Bidi::Bidi;
227 }
228 loop {
229 let Some(u) = iter.next() else {
230 return Latin1Bidi::LeftToRight;
231 };
232 if is_utf16_code_unit_bidi(*u) {
233 return Latin1Bidi::Bidi;
234 }
235 }
236 }
237 };
238 let simd: u16x8 = (*s).into();
239 if crate::simd_funcs::simd_is_latin1(simd) {
240 continue;
241 }
242 if crate::simd_funcs::is_u16x8_bidi(simd) {
243 return Latin1Bidi::Bidi;
244 }
245 loop {
246 let Some(s) = half_stride_iter.next() else {
247 for u in tail {
248 if is_utf16_code_unit_bidi(*u) {
249 return Latin1Bidi::Bidi;
250 }
251 }
252 return Latin1Bidi::LeftToRight;
253 };
254 let simd: u16x8 = (*s).into();
255 if crate::simd_funcs::is_u16x8_bidi(simd) {
256 return Latin1Bidi::Bidi;
257 }
258 }
259 }
260 }
261
262 } else {
263 use crate::ascii::unpack_stride;
264 use crate::ascii::pack_stride;
265
266 fn is_utf16_bidi_impl(buffer: &[u16]) -> bool {
267 buffer.iter().any(|c| is_utf16_code_unit_bidi(*c))
268 }
269
270 #[inline(always)]
271 fn is_str_latin1_bool_impl(buffer: &str) -> bool {
272 is_str_latin1_impl(buffer).is_none()
273 }
274
275 macro_rules! unit_check_impl {
276 ($name:ident, $stride:ident, $unit:ty, $bound:expr) => {
277 #[inline(always)]
278 fn $name(buffer: &[$unit]) -> bool {
279 let (strides, tail) = buffer.as_chunks::<STRIDE>();
280 for stride in strides {
281 if !crate::ascii::$stride(stride) {
282 return false;
283 }
284 }
285 if let Some(reduced) = tail.iter().copied().reduce(|a, b| a | b) {
286 reduced < $bound
287 } else {
288 true
289 }
290 }
291 };
292 }
293
294 unit_check_impl!(is_ascii_impl, is_ascii, u8, 0x80);
295 unit_check_impl!(is_basic_latin_impl, is_basic_latin, u16, 0x80);
296 unit_check_impl!(is_utf16_latin1_impl, is_utf16_latin1, u16, 0x100);
297
298 #[inline(always)]
299 fn check_utf16_for_latin1_and_bidi_impl(buffer: &[u16]) -> Latin1Bidi {
300 let mut iter = buffer.iter();
301 loop {
302 let Some(u) = iter.next() else {
303 return Latin1Bidi::Latin1;
304 };
305 if *u < 0x100 {
306 continue;
307 }
308 if is_utf16_code_unit_bidi(*u) {
309 return Latin1Bidi::Bidi;
310 }
311 loop {
312 let Some(u) = iter.next() else {
313 return Latin1Bidi::LeftToRight;
314 };
315 if is_utf16_code_unit_bidi(*u) {
316 return Latin1Bidi::Bidi;
317 }
318 }
319 }
320 }
321
322 }
323}
324
325pub fn is_ascii(buffer: &[u8]) -> bool {
330 is_ascii_impl(buffer)
331}
332
333#[crate::multiversion(targets("x86_64+avx2+bmi1", "x86+avx2+bmi1"))]
339pub fn is_basic_latin(buffer: &[u16]) -> bool {
340 is_basic_latin_impl(buffer)
341}
342
343pub fn is_utf8_latin1(buffer: &[u8]) -> bool {
349 is_utf8_latin1_impl(buffer).is_none()
350}
351
352pub fn is_str_latin1(buffer: &str) -> bool {
358 is_str_latin1_bool_impl(buffer)
359}
360
361#[crate::multiversion(targets("x86_64+avx2+bmi1", "x86+avx2+bmi1"))]
367pub fn is_utf16_latin1(buffer: &[u16]) -> bool {
368 is_utf16_latin1_impl(buffer)
369}
370
371#[allow(clippy::collapsible_if, clippy::cognitive_complexity)]
388#[inline]
389#[crate::multiversion(targets("x86_64+avx2+bmi1", "x86+avx2+bmi1"))]
390pub fn is_utf8_bidi(buffer: &[u8]) -> bool {
391 let mut src = buffer;
430 'outer: loop {
431 if let Some((mut byte, mut read)) = validate_ascii(src) {
432 if read + 4 <= src.len() {
435 'inner: loop {
436 match byte {
438 0..=0x7F => {
439 read += 1;
441 src = &src[read..];
442 continue 'outer;
443 }
444 0xC2..=0xD5 => {
445 let second = unsafe { *(src.get_unchecked(read + 1)) };
447 if !in_inclusive_range8(second, 0x80, 0xBF) {
448 return true;
449 }
450 read += 2;
451 }
452 0xD6 => {
453 let second = unsafe { *(src.get_unchecked(read + 1)) };
455 if !in_inclusive_range8(second, 0x80, 0xBF) {
456 return true;
457 }
458 if second > 0x8F {
460 return true;
461 }
462 read += 2;
463 }
464 0xE1 | 0xE3..=0xEC | 0xEE => {
466 let second = unsafe { *(src.get_unchecked(read + 1)) };
468 let third = unsafe { *(src.get_unchecked(read + 2)) };
469 if ((UTF8_DATA.table[usize::from(second)]
470 & unsafe {
471 *(UTF8_DATA.table.get_unchecked(byte as usize + 0x80))
472 })
473 | (third >> 6))
474 != 2
475 {
476 return true;
477 }
478 read += 3;
479 }
480 0xE2 => {
481 let second = unsafe { *(src.get_unchecked(read + 1)) };
483 let third = unsafe { *(src.get_unchecked(read + 2)) };
484 if ((UTF8_DATA.table[usize::from(second)]
485 & unsafe {
486 *(UTF8_DATA.table.get_unchecked(byte as usize + 0x80))
487 })
488 | (third >> 6))
489 != 2
490 {
491 return true;
492 }
493 if second == 0x80 {
494 if third == 0x8F || third == 0xAB || third == 0xAE {
495 return true;
496 }
497 } else if second == 0x81 {
498 if third == 0xA7 {
499 return true;
500 }
501 }
502 read += 3;
503 }
504 0xEF => {
505 let second = unsafe { *(src.get_unchecked(read + 1)) };
507 let third = unsafe { *(src.get_unchecked(read + 2)) };
508 if ((UTF8_DATA.table[usize::from(second)]
509 & unsafe {
510 *(UTF8_DATA.table.get_unchecked(byte as usize + 0x80))
511 })
512 | (third >> 6))
513 != 2
514 {
515 return true;
516 }
517 if in_inclusive_range8(second, 0xAC, 0xB7) {
518 if second == 0xAC {
519 if third > 0x9C {
520 return true;
521 }
522 } else {
523 return true;
524 }
525 } else if in_inclusive_range8(second, 0xB9, 0xBB) {
526 if second == 0xB9 {
527 if third > 0xAF {
528 return true;
529 }
530 } else if second == 0xBB {
531 if third != 0xBF {
532 return true;
533 }
534 } else {
535 return true;
536 }
537 }
538 read += 3;
539 }
540 0xE0 => {
541 let second = unsafe { *(src.get_unchecked(read + 1)) };
543 let third = unsafe { *(src.get_unchecked(read + 2)) };
544 if ((UTF8_DATA.table[usize::from(second)]
545 & unsafe {
546 *(UTF8_DATA.table.get_unchecked(byte as usize + 0x80))
547 })
548 | (third >> 6))
549 != 2
550 {
551 return true;
552 }
553 if second < 0xA4 {
555 return true;
556 }
557 read += 3;
558 }
559 0xED => {
560 let second = unsafe { *(src.get_unchecked(read + 1)) };
562 let third = unsafe { *(src.get_unchecked(read + 2)) };
563 if ((UTF8_DATA.table[usize::from(second)]
564 & unsafe {
565 *(UTF8_DATA.table.get_unchecked(byte as usize + 0x80))
566 })
567 | (third >> 6))
568 != 2
569 {
570 return true;
571 }
572 read += 3;
573 }
574 0xF1..=0xF4 => {
575 let second = unsafe { *(src.get_unchecked(read + 1)) };
577 let third = unsafe { *(src.get_unchecked(read + 2)) };
578 let fourth = unsafe { *(src.get_unchecked(read + 3)) };
579 if (u16::from(
580 UTF8_DATA.table[usize::from(second)]
581 & unsafe {
582 *(UTF8_DATA.table.get_unchecked(byte as usize + 0x80))
583 },
584 ) | u16::from(third >> 6)
585 | (u16::from(fourth & 0xC0) << 2))
586 != 0x202
587 {
588 return true;
589 }
590 read += 4;
591 }
592 0xF0 => {
593 let second = unsafe { *(src.get_unchecked(read + 1)) };
595 let third = unsafe { *(src.get_unchecked(read + 2)) };
596 let fourth = unsafe { *(src.get_unchecked(read + 3)) };
597 if (u16::from(
598 UTF8_DATA.table[usize::from(second)]
599 & unsafe {
600 *(UTF8_DATA.table.get_unchecked(byte as usize + 0x80))
601 },
602 ) | u16::from(third >> 6)
603 | (u16::from(fourth & 0xC0) << 2))
604 != 0x202
605 {
606 return true;
607 }
608 if unlikely(second == 0x90 || second == 0x9E) {
609 let third = src[read + 2];
610 if third >= 0xA0 {
611 return true;
612 }
613 }
614 read += 4;
615 }
616 _ => {
617 return true;
619 }
620 }
621 if read + 4 > src.len() {
622 if read == src.len() {
623 return false;
624 }
625 byte = src[read];
626 break 'inner;
627 }
628 byte = src[read];
629 continue 'inner;
630 }
631 }
632 match byte {
637 0..=0x7F => {
638 read += 1;
640 src = &src[read..];
641 continue 'outer;
642 }
643 0xC2..=0xD5 => {
644 let new_read = read + 2;
646 if new_read > src.len() {
647 return true;
648 }
649 let second = unsafe { *(src.get_unchecked(read + 1)) };
650 if !in_inclusive_range8(second, 0x80, 0xBF) {
651 return true;
652 }
653 read = new_read;
654 src = &src[read..];
657 continue 'outer;
658 }
659 0xD6 => {
660 let new_read = read + 2;
662 if new_read > src.len() {
663 return true;
664 }
665 let second = unsafe { *(src.get_unchecked(read + 1)) };
666 if !in_inclusive_range8(second, 0x80, 0xBF) {
667 return true;
668 }
669 if second > 0x8F {
671 return true;
672 }
673 read = new_read;
674 src = &src[read..];
677 continue 'outer;
678 }
679 0xE1 | 0xE3..=0xEC | 0xEE => {
681 let new_read = read + 3;
683 if new_read > src.len() {
684 return true;
685 }
686 let second = unsafe { *(src.get_unchecked(read + 1)) };
687 let third = unsafe { *(src.get_unchecked(read + 2)) };
688 if ((UTF8_DATA.table[usize::from(second)]
689 & unsafe { *(UTF8_DATA.table.get_unchecked(byte as usize + 0x80)) })
690 | (third >> 6))
691 != 2
692 {
693 return true;
694 }
695 }
696 0xE2 => {
697 let new_read = read + 3;
699 if new_read > src.len() {
700 return true;
701 }
702 let second = unsafe { *(src.get_unchecked(read + 1)) };
703 let third = unsafe { *(src.get_unchecked(read + 2)) };
704 if ((UTF8_DATA.table[usize::from(second)]
705 & unsafe { *(UTF8_DATA.table.get_unchecked(byte as usize + 0x80)) })
706 | (third >> 6))
707 != 2
708 {
709 return true;
710 }
711 if second == 0x80 {
712 if third == 0x8F || third == 0xAB || third == 0xAE {
713 return true;
714 }
715 } else if second == 0x81 {
716 if third == 0xA7 {
717 return true;
718 }
719 }
720 }
721 0xEF => {
722 let new_read = read + 3;
724 if new_read > src.len() {
725 return true;
726 }
727 let second = unsafe { *(src.get_unchecked(read + 1)) };
728 let third = unsafe { *(src.get_unchecked(read + 2)) };
729 if ((UTF8_DATA.table[usize::from(second)]
730 & unsafe { *(UTF8_DATA.table.get_unchecked(byte as usize + 0x80)) })
731 | (third >> 6))
732 != 2
733 {
734 return true;
735 }
736 if in_inclusive_range8(second, 0xAC, 0xB7) {
737 if second == 0xAC {
738 if third > 0x9C {
739 return true;
740 }
741 } else {
742 return true;
743 }
744 } else if in_inclusive_range8(second, 0xB9, 0xBB) {
745 if second == 0xB9 {
746 if third > 0xAF {
747 return true;
748 }
749 } else if second == 0xBB {
750 if third != 0xBF {
751 return true;
752 }
753 } else {
754 return true;
755 }
756 }
757 }
758 0xE0 => {
759 let new_read = read + 3;
761 if new_read > src.len() {
762 return true;
763 }
764 let second = unsafe { *(src.get_unchecked(read + 1)) };
765 let third = unsafe { *(src.get_unchecked(read + 2)) };
766 if ((UTF8_DATA.table[usize::from(second)]
767 & unsafe { *(UTF8_DATA.table.get_unchecked(byte as usize + 0x80)) })
768 | (third >> 6))
769 != 2
770 {
771 return true;
772 }
773 if second < 0xA4 {
775 return true;
776 }
777 }
778 0xED => {
779 let new_read = read + 3;
781 if new_read > src.len() {
782 return true;
783 }
784 let second = unsafe { *(src.get_unchecked(read + 1)) };
785 let third = unsafe { *(src.get_unchecked(read + 2)) };
786 if ((UTF8_DATA.table[usize::from(second)]
787 & unsafe { *(UTF8_DATA.table.get_unchecked(byte as usize + 0x80)) })
788 | (third >> 6))
789 != 2
790 {
791 return true;
792 }
793 }
794 _ => {
795 return true;
797 }
798 }
799 return false;
800 } else {
801 return false;
802 }
803 }
804}
805
806#[allow(clippy::collapsible_if)]
819#[inline]
820#[crate::multiversion(targets("x86_64+avx2+bmi1", "x86+avx2+bmi1"))]
821pub fn is_str_bidi(buffer: &str) -> bool {
822 let mut bytes = buffer.as_bytes();
852 'outer: loop {
853 if let Some((mut byte, mut read)) = validate_ascii(bytes) {
860 'inner: loop {
861 if byte < 0xE0 {
863 if byte >= 0x80 {
864 if unlikely(byte >= 0xD6) {
868 if byte == 0xD6 {
869 let second = bytes[read + 1];
870 if second > 0x8F {
871 return true;
872 }
873 } else {
874 return true;
875 }
876 }
877 read += 2;
878 } else {
879 read += 1;
881 bytes = &bytes[read..];
887 continue 'outer;
888 }
889 } else if byte < 0xF0 {
890 if unlikely(!in_inclusive_range8(byte, 0xE3, 0xEE) && byte != 0xE1) {
892 let second = bytes[read + 1];
893 if byte == 0xE0 {
894 if second < 0xA4 {
895 return true;
896 }
897 } else if byte == 0xE2 {
898 let third = bytes[read + 2];
899 if second == 0x80 {
900 if third == 0x8F || third == 0xAB || third == 0xAE {
901 return true;
902 }
903 } else if second == 0x81 {
904 if third == 0xA7 {
905 return true;
906 }
907 }
908 } else {
909 debug_assert_eq!(byte, 0xEF);
910 if in_inclusive_range8(second, 0xAC, 0xB7) {
911 if second == 0xAC {
912 let third = bytes[read + 2];
913 if third > 0x9C {
914 return true;
915 }
916 } else {
917 return true;
918 }
919 } else if in_inclusive_range8(second, 0xB9, 0xBB) {
920 if second == 0xB9 {
921 let third = bytes[read + 2];
922 if third > 0xAF {
923 return true;
924 }
925 } else if second == 0xBB {
926 let third = bytes[read + 2];
927 if third != 0xBF {
928 return true;
929 }
930 } else {
931 return true;
932 }
933 }
934 }
935 }
936 read += 3;
937 } else {
938 let second = bytes[read + 1];
940 if unlikely(byte == 0xF0 && (second == 0x90 || second == 0x9E)) {
941 let third = bytes[read + 2];
942 if third >= 0xA0 {
943 return true;
944 }
945 }
946 read += 4;
947 }
948 if read >= bytes.len() {
952 return false;
953 }
954 byte = bytes[read];
955 continue 'inner;
956 }
957 } else {
958 return false;
959 }
960 }
961}
962
963pub fn is_utf16_bidi(buffer: &[u16]) -> bool {
981 is_utf16_bidi_impl(buffer)
982}
983
984#[inline(always)]
996pub fn is_char_bidi(c: char) -> bool {
997 let code_point = u32::from(c);
1017 if code_point < 0x0590 {
1018 return false;
1020 }
1021 if in_range32(code_point, 0x0900, 0xFB1D) {
1022 if in_inclusive_range32(code_point, 0x200F, 0x2067) {
1024 return code_point == 0x200F
1026 || code_point == 0x202B
1027 || code_point == 0x202E
1028 || code_point == 0x2067;
1029 }
1030 return false;
1031 }
1032 if code_point > 0x1EFFF {
1033 return false;
1035 }
1036 if in_range32(code_point, 0x11000, 0x1E800) {
1037 return false;
1039 }
1040 if in_range32(code_point, 0xFEFF, 0x10800) {
1041 return false;
1044 }
1045 if in_range32(code_point, 0xFE00, 0xFE70) {
1046 return false;
1048 }
1049 true
1050}
1051
1052#[inline(always)]
1071pub fn is_utf16_code_unit_bidi(u: u16) -> bool {
1072 if u < 0x0590 {
1073 return false;
1075 }
1076 if in_range16(u, 0x0900, 0xD802) {
1077 if in_inclusive_range16(u, 0x200F, 0x2067) {
1079 return u == 0x200F || u == 0x202B || u == 0x202E || u == 0x2067;
1081 }
1082 return false;
1083 }
1084 if in_range16(u, 0xD83C, 0xFB1D) {
1085 return false;
1088 }
1089 if in_range16(u, 0xD804, 0xD83A) {
1090 return false;
1092 }
1093 if u > 0xFEFE {
1094 return false;
1096 }
1097 if in_range16(u, 0xFE00, 0xFE70) {
1098 return false;
1100 }
1101 true
1102}
1103
1104pub fn check_utf8_for_latin1_and_bidi(buffer: &[u8]) -> Latin1Bidi {
1113 if let Some(offset) = is_utf8_latin1_impl(buffer) {
1114 if is_utf8_bidi(&buffer[offset..]) {
1115 Latin1Bidi::Bidi
1116 } else {
1117 Latin1Bidi::LeftToRight
1118 }
1119 } else {
1120 Latin1Bidi::Latin1
1121 }
1122}
1123
1124pub fn check_str_for_latin1_and_bidi(buffer: &str) -> Latin1Bidi {
1133 if let Some(offset) = is_str_latin1_impl(buffer) {
1136 if is_str_bidi(&buffer[offset..]) {
1137 Latin1Bidi::Bidi
1138 } else {
1139 Latin1Bidi::LeftToRight
1140 }
1141 } else {
1142 Latin1Bidi::Latin1
1143 }
1144}
1145
1146pub fn check_utf16_for_latin1_and_bidi(buffer: &[u16]) -> Latin1Bidi {
1155 check_utf16_for_latin1_and_bidi_impl(buffer)
1156}
1157
1158#[crate::multiversion(targets("x86_64+avx2+bmi1", "x86+avx2+bmi1"))]
1170pub fn convert_utf8_to_utf16(src: &[u8], dst: &mut [u16]) -> usize {
1171 assert!(dst.len() > src.len());
1174 let mut decoder = Utf8Decoder::new_inner();
1175 let mut total_read = 0usize;
1176 let mut total_written = 0usize;
1177 loop {
1178 let (result, read, written) =
1179 decoder.decode_to_utf16_raw(&src[total_read..], &mut dst[total_written..], true);
1180 total_read += read;
1181 total_written += written;
1182 match result {
1183 DecoderResult::InputEmpty => {
1184 return total_written;
1185 }
1186 DecoderResult::OutputFull => {
1187 unreachable!("The assert at the top of the function should have caught this.");
1188 }
1189 DecoderResult::Malformed(_, _) => {
1190 dst[total_written] = 0xFFFD;
1193 total_written += 1;
1194 }
1195 }
1196 }
1197}
1198
1199#[crate::multiversion(targets("x86_64+avx2+bmi1", "x86+avx2+bmi1"))]
1210pub fn convert_str_to_utf16(src: &str, dst: &mut [u16]) -> usize {
1211 assert!(
1212 dst.len() >= src.len(),
1213 "Destination must not be shorter than the source."
1214 );
1215 let bytes = src.as_bytes();
1216 let mut read = 0;
1217 let mut written = 0;
1218 'outer: loop {
1219 let mut byte = {
1220 let src_remaining = &bytes[read..];
1221 let dst_remaining = &mut dst[written..];
1222 let length = src_remaining.len();
1223 match ascii_to_basic_latin(src_remaining, dst_remaining) {
1224 None => {
1225 written += length;
1226 return written;
1227 }
1228 Some((non_ascii, consumed)) => {
1229 read += consumed;
1230 written += consumed;
1231 non_ascii
1232 }
1233 }
1234 };
1235 'inner: loop {
1236 if byte < 0xE0 {
1238 if byte >= 0x80 {
1239 let second = unsafe { *(bytes.get_unchecked(read + 1)) };
1241 let point = ((u16::from(byte) & 0x1F) << 6) | (u16::from(second) & 0x3F);
1242 unsafe { *(dst.get_unchecked_mut(written)) = point };
1243 read += 2;
1244 written += 1;
1245 } else {
1246 unsafe { *(dst.get_unchecked_mut(written)) = u16::from(byte) };
1248 read += 1;
1249 written += 1;
1250 continue 'outer;
1256 }
1257 } else if byte < 0xF0 {
1258 let second = unsafe { *(bytes.get_unchecked(read + 1)) };
1260 let third = unsafe { *(bytes.get_unchecked(read + 2)) };
1261 let point = ((u16::from(byte) & 0xF) << 12)
1262 | ((u16::from(second) & 0x3F) << 6)
1263 | (u16::from(third) & 0x3F);
1264 unsafe { *(dst.get_unchecked_mut(written)) = point };
1265 read += 3;
1266 written += 1;
1267 } else {
1268 let second = unsafe { *(bytes.get_unchecked(read + 1)) };
1270 let third = unsafe { *(bytes.get_unchecked(read + 2)) };
1271 let fourth = unsafe { *(bytes.get_unchecked(read + 3)) };
1272 let point = ((u32::from(byte) & 0x7) << 18)
1273 | ((u32::from(second) & 0x3F) << 12)
1274 | ((u32::from(third) & 0x3F) << 6)
1275 | (u32::from(fourth) & 0x3F);
1276 unsafe { *(dst.get_unchecked_mut(written)) = (0xD7C0 + (point >> 10)) as u16 };
1277 unsafe {
1278 *(dst.get_unchecked_mut(written + 1)) = (0xDC00 + (point & 0x3FF)) as u16
1279 };
1280 read += 4;
1281 written += 2;
1282 }
1283 if read >= src.len() {
1287 return written;
1288 }
1289 byte = bytes[read];
1290 continue 'inner;
1291 }
1292 }
1293}
1294
1295pub fn convert_utf8_to_utf16_without_replacement(src: &[u8], dst: &mut [u16]) -> Option<usize> {
1308 assert!(
1309 dst.len() >= src.len(),
1310 "Destination must not be shorter than the source."
1311 );
1312 let (read, written) = convert_utf8_to_utf16_up_to_invalid(src, dst);
1313 if read == src.len() {
1314 return Some(written);
1315 }
1316 None
1317}
1318
1319#[inline(always)]
1347pub fn convert_utf16_to_utf8_partial(src: &[u16], dst: &mut [u8]) -> (usize, usize) {
1348 let (read, written) = convert_utf16_to_utf8_partial_inner(src, dst);
1358 if likely(read == src.len()) {
1359 return (read, written);
1360 }
1361 let (tail_read, tail_written) =
1362 convert_utf16_to_utf8_partial_tail(&src[read..], &mut dst[written..]);
1363 (read + tail_read, written + tail_written)
1364}
1365
1366#[inline(always)]
1384pub fn convert_utf16_to_utf8(src: &[u16], dst: &mut [u8]) -> usize {
1385 assert!(dst.len() >= src.len() * 3);
1386 let (read, written) = convert_utf16_to_utf8_partial(src, dst);
1387 debug_assert_eq!(read, src.len());
1388 written
1389}
1390
1391pub fn convert_utf16_to_str_partial(src: &[u16], dst: &mut str) -> (usize, usize) {
1405 let mut bytes = scopeguard::guard(unsafe { dst.as_bytes_mut() }, |bytes| {
1417 bytes.iter_mut().for_each(|b| *b = 0)
1418 });
1419 let (read, written) = convert_utf16_to_utf8_partial(src, &mut bytes);
1420 let len = bytes.len();
1421 let mut trail = written;
1422 while trail < len && ((bytes[trail] & 0xC0) == 0x80) {
1423 bytes[trail] = 0;
1424 trail += 1;
1425 }
1426 let _ = scopeguard::ScopeGuard::<&mut [u8], _>::into_inner(bytes);
1428 (read, written)
1429}
1430
1431#[inline(always)]
1444pub fn convert_utf16_to_str(src: &[u16], dst: &mut str) -> usize {
1445 assert!(dst.len() >= src.len() * 3);
1446 let (read, written) = convert_utf16_to_str_partial(src, dst);
1447 debug_assert_eq!(read, src.len());
1448 written
1449}
1450
1451#[crate::multiversion(targets("x86_64+avx2+bmi1", "x86+avx2+bmi1"))]
1463pub fn convert_latin1_to_utf16(src: &[u8], dst: &mut [u16]) {
1464 assert!(
1465 dst.len() >= src.len(),
1466 "Destination must not be shorter than the source."
1467 );
1468 unpack_latin1(src, dst);
1469}
1470
1471pub fn convert_latin1_to_utf8_partial(src: &[u8], dst: &mut [u8]) -> (usize, usize) {
1485 let src_len = src.len();
1486 let dst_len = dst.len();
1487 let mut total_read = 0usize;
1488 let mut total_written = 0usize;
1489 loop {
1490 let src_left = src_len - total_read;
1492 let dst_left = dst_len - total_written;
1493 let min_left = ::core::cmp::min(src_left, dst_left);
1494 if let Some((non_ascii, consumed)) =
1495 { ascii_to_ascii(&src[total_read..], &mut dst[total_written..]) }
1496 {
1497 total_read += consumed;
1498 total_written += consumed;
1499 if total_written.checked_add(2).unwrap() > dst_len {
1500 return (total_read, total_written);
1501 }
1502
1503 total_read += 1; dst[total_written] = (non_ascii >> 6) | 0xC0;
1506 total_written += 1;
1507 dst[total_written] = (non_ascii & 0x3F) | 0x80;
1508 total_written += 1;
1509 continue;
1510 }
1511 return (total_read + min_left, total_written + min_left);
1512 }
1513}
1514
1515#[inline]
1534pub fn convert_latin1_to_utf8(src: &[u8], dst: &mut [u8]) -> usize {
1535 assert!(
1536 dst.len() >= src.len() * 2,
1537 "Destination must not be shorter than the source times two."
1538 );
1539 let (read, written) = convert_latin1_to_utf8_partial(src, dst);
1540 debug_assert_eq!(read, src.len());
1541 written
1542}
1543
1544#[inline]
1553pub fn convert_latin1_to_str_partial(src: &[u8], dst: &mut str) -> (usize, usize) {
1554 let bytes: &mut [u8] = unsafe { dst.as_bytes_mut() };
1555 let (read, written) = convert_latin1_to_utf8_partial(src, bytes);
1556 let len = bytes.len();
1557 let mut trail = written;
1558 let max = ::core::cmp::min(len, trail + MAX_STRIDE_SIZE);
1559 while trail < max {
1560 bytes[trail] = 0;
1561 trail += 1;
1562 }
1563 while trail < len && ((bytes[trail] & 0xC0) == 0x80) {
1564 bytes[trail] = 0;
1565 trail += 1;
1566 }
1567 (read, written)
1568}
1569
1570#[inline]
1583pub fn convert_latin1_to_str(src: &[u8], dst: &mut str) -> usize {
1584 assert!(
1585 dst.len() >= src.len() * 2,
1586 "Destination must not be shorter than the source times two."
1587 );
1588 let (read, written) = convert_latin1_to_str_partial(src, dst);
1589 debug_assert_eq!(read, src.len());
1590 written
1591}
1592
1593pub fn convert_utf8_to_latin1_lossy(src: &[u8], dst: &mut [u8]) -> usize {
1617 assert!(
1618 dst.len() >= src.len(),
1619 "Destination must not be shorter than the source."
1620 );
1621 non_fuzz_debug_assert!(is_utf8_latin1(src));
1622 let src_len = src.len();
1623 let mut total_read = 0usize;
1624 let mut total_written = 0usize;
1625 loop {
1626 let src_left = src_len - total_read;
1628 if let Some((non_ascii, consumed)) =
1629 { ascii_to_ascii(&src[total_read..], &mut dst[total_written..]) }
1630 {
1631 total_read += consumed + 1;
1632 total_written += consumed;
1633
1634 if total_read == src_len {
1635 return total_written;
1636 }
1637
1638 let trail = src[total_read];
1639 total_read += 1;
1640
1641 dst[total_written] = ((non_ascii & 0x1F) << 6) | (trail & 0x3F);
1642 total_written += 1;
1643 continue;
1644 }
1645 return total_written + src_left;
1646 }
1647}
1648
1649pub fn convert_utf16_to_latin1_lossy(src: &[u16], dst: &mut [u8]) {
1673 assert!(
1674 dst.len() >= src.len(),
1675 "Destination must not be shorter than the source."
1676 );
1677 pack_latin1(src, dst);
1679}
1680
1681#[cfg(feature = "alloc")]
1689pub fn decode_latin1<'a>(bytes: &'a [u8]) -> Cow<'a, str> {
1690 let up_to = ascii_valid_up_to(bytes);
1691 if up_to >= bytes.len() {
1693 debug_assert_eq!(up_to, bytes.len());
1694 let s: &str = unsafe { ::core::str::from_utf8_unchecked(bytes) };
1697 return Cow::Borrowed(s);
1698 }
1699 let (head, tail) = bytes.split_at(up_to);
1700 let capacity = head.len() + tail.len() * 2;
1701 let mut vec = Vec::with_capacity(capacity);
1702 vec.extend_from_slice(head);
1703 let old_len = vec.len();
1704 let spare_capacity = crate::minimally_init(vec.spare_capacity_mut());
1705 debug_assert_eq!(old_len, up_to);
1706 let written = convert_latin1_to_utf8(tail, spare_capacity);
1707 debug_assert!(written <= spare_capacity.len());
1708 let new_len = old_len + written;
1709 assert!(new_len <= vec.capacity());
1710 unsafe {
1719 vec.set_len(new_len);
1720 }
1721 Cow::Owned(unsafe { String::from_utf8_unchecked(vec) })
1725}
1726
1727#[cfg(feature = "alloc")]
1744pub fn encode_latin1_lossy<'a>(string: &'a str) -> Cow<'a, [u8]> {
1745 let bytes = string.as_bytes();
1746 let up_to = ascii_valid_up_to(bytes);
1747 if up_to >= bytes.len() {
1749 debug_assert_eq!(up_to, bytes.len());
1750 return Cow::Borrowed(bytes);
1751 }
1752 let (head, tail) = bytes.split_at(up_to);
1753 let capacity = bytes.len();
1754 let mut vec = Vec::with_capacity(capacity);
1755 vec.extend_from_slice(head);
1756 let old_len = vec.len();
1757 let spare_capacity = crate::minimally_init(vec.spare_capacity_mut());
1758 debug_assert_eq!(old_len, up_to);
1759 let written = convert_utf8_to_latin1_lossy(tail, spare_capacity);
1760 debug_assert!(written <= spare_capacity.len());
1761 let new_len = old_len + written;
1762 assert!(new_len <= vec.capacity());
1763 unsafe {
1770 vec.set_len(new_len);
1771 }
1772 Cow::Owned(vec)
1773}
1774
1775cfg_if! {
1776 if #[cfg(all(
1777 feature = "simd-accel",
1778 target_endian = "little",
1779 ))] {
1780 pub(crate) use crate::simd_funcs::validate_bmp_stride;
1781 pub(crate) use crate::simd_funcs::validate_latin1_str_stride;
1782
1783 #[inline(always)]
1784 #[crate::multiversion(targets("x86_64+avx2+bmi1", "x86+avx2+bmi1"))]
1785 fn is_str_latin1_impl(buffer: &str) -> Option<usize> {
1786 let mut consumed = 0;
1787 let (strides, tail) = buffer.as_bytes().as_chunks::<STRIDE>();
1788 for stride in strides.iter() {
1789 if let Some(pos) = validate_latin1_str_stride(stride) {
1790 return Some(consumed + pos);
1791 }
1792 consumed += STRIDE;
1793 }
1794 for slot in tail.iter() {
1795 if *slot > 0xC3 {
1796 return Some(consumed);
1797 }
1798 consumed += 1;
1799 }
1800 None
1801 }
1802 } else {
1803 #[inline(always)]
1804 pub(crate) fn validate_bmp_stride(stride: &[u16; STRIDE]) -> Option<usize> {
1805 if (stride[0] & 0xF800 != 0xD800)
1806 && (stride[1] & 0xF800 != 0xD800)
1807 && (stride[2] & 0xF800 != 0xD800)
1808 && (stride[3] & 0xF800 != 0xD800)
1809 && (stride[4] & 0xF800 != 0xD800)
1810 && (stride[5] & 0xF800 != 0xD800)
1811 && (stride[6] & 0xF800 != 0xD800)
1812 && (stride[7] & 0xF800 != 0xD800)
1813 && (stride[8] & 0xF800 != 0xD800)
1814 && (stride[9] & 0xF800 != 0xD800)
1815 && (stride[10] & 0xF800 != 0xD800)
1816 && (stride[11] & 0xF800 != 0xD800)
1817 && (stride[12] & 0xF800 != 0xD800)
1818 && (stride[13] & 0xF800 != 0xD800)
1819 && (stride[14] & 0xF800 != 0xD800)
1820 && (stride[15] & 0xF800 != 0xD800)
1821 {
1822 return None;
1823 }
1824 for (i, c) in stride.iter().enumerate() {
1825 if c & 0xF800 == 0xD800 {
1826 return Some(i);
1827 }
1828 }
1829 debug_assert!(false);
1830 None
1831 }
1832
1833 #[inline(always)]
1834 fn is_str_latin1_impl(buffer: &str) -> Option<usize> {
1835 let mut bytes = buffer.as_bytes();
1836 let mut total = 0;
1837 loop {
1838 if let Some((byte, offset)) = validate_ascii(bytes) {
1839 total += offset;
1840 if byte > 0xC3 {
1841 return Some(total);
1842 }
1843 bytes = &bytes[offset + 2..];
1844 total += 2;
1845 } else {
1846 return None;
1847 }
1848 }
1849 }
1850 }
1851}
1852
1853#[crate::multiversion(targets("x86_64+avx2+bmi1", "x86+avx2+bmi1"))]
1856pub fn utf16_valid_up_to(buffer: &[u16]) -> usize {
1857 let mut consumed = 0usize;
1858 'outer: loop {
1859 let (strides, tail) = &buffer[consumed..].as_chunks::<STRIDE>();
1860 #[allow(clippy::never_loop)]
1862 'bmp: loop {
1863 for stride in strides.iter() {
1864 if let Some(pos) = validate_bmp_stride(stride) {
1865 consumed += pos;
1866 break 'bmp;
1867 }
1868 consumed += STRIDE;
1869 }
1870 for slot in tail.iter() {
1871 if *slot & 0xF800 == 0xD800 {
1872 break 'bmp;
1873 }
1874 consumed += 1;
1875 }
1876 debug_assert_eq!(consumed, buffer.len());
1877 return consumed;
1878 }
1879 let mut unit = buffer[consumed];
1881 let mut unit_minus_surrogate_start = unit.wrapping_sub(0xD800);
1882 debug_assert!(unit_minus_surrogate_start <= (0xDFFF - 0xD800));
1883 'surrogate: loop {
1884 if unit_minus_surrogate_start > (0xDBFF - 0xD800) {
1885 return consumed;
1887 }
1888 let next = consumed + 1;
1890 if next == buffer.len() {
1891 return consumed;
1893 }
1894 let second = buffer[next];
1895 let second_minus_low_surrogate_start = second.wrapping_sub(0xDC00);
1896 if second_minus_low_surrogate_start > (0xDFFF - 0xDC00) {
1897 return consumed;
1900 }
1901 consumed = next + 1;
1903 loop {
1907 if consumed == buffer.len() {
1908 return consumed;
1910 }
1911 unit = buffer[consumed];
1912 unit_minus_surrogate_start = unit.wrapping_sub(0xD800);
1913 if unit_minus_surrogate_start <= (0xDFFF - 0xD800) {
1914 continue 'surrogate;
1915 }
1916 consumed += 1;
1918 if unit == 0x0020 {
1920 continue;
1921 }
1922 continue 'outer;
1923 }
1924 }
1925 }
1926}
1927
1928pub fn utf8_latin1_up_to(buffer: &[u8]) -> usize {
1932 is_utf8_latin1_impl(buffer).unwrap_or(buffer.len())
1933}
1934
1935pub fn str_latin1_up_to(buffer: &str) -> usize {
1938 is_str_latin1_impl(buffer).unwrap_or(buffer.len())
1939}
1940
1941#[inline]
1943pub fn ensure_utf16_validity(buffer: &mut [u16]) {
1944 let mut offset = 0;
1945 loop {
1946 offset += utf16_valid_up_to(&buffer[offset..]);
1947 if offset == buffer.len() {
1948 return;
1949 }
1950 buffer[offset] = 0xFFFD;
1951 offset += 1;
1952 }
1953}
1954
1955pub fn copy_ascii_to_ascii(src: &[u8], dst: &mut [u8]) -> usize {
1967 assert!(
1968 dst.len() >= src.len(),
1969 "Destination must not be shorter than the source."
1970 );
1971 if let Some((_, consumed)) = { ascii_to_ascii(src, dst) } {
1972 consumed
1973 } else {
1974 src.len()
1975 }
1976}
1977
1978#[crate::multiversion(targets("x86_64+avx2+bmi1", "x86+avx2+bmi1"))]
1991pub fn copy_ascii_to_basic_latin(src: &[u8], dst: &mut [u16]) -> usize {
1992 assert!(
1993 dst.len() >= src.len(),
1994 "Destination must not be shorter than the source."
1995 );
1996 if let Some((_, consumed)) = { ascii_to_basic_latin(src, dst) } {
1997 consumed
1998 } else {
1999 src.len()
2000 }
2001}
2002
2003#[crate::multiversion(targets("x86_64+avx2+bmi1", "x86+avx2+bmi1"))]
2016pub fn copy_basic_latin_to_ascii(src: &[u16], dst: &mut [u8]) -> usize {
2017 assert!(
2018 dst.len() >= src.len(),
2019 "Destination must not be shorter than the source."
2020 );
2021 if let Some((_, consumed)) = { basic_latin_to_ascii(src, dst) } {
2022 consumed
2023 } else {
2024 src.len()
2025 }
2026}
2027
2028#[cfg(all(test, feature = "alloc"))]
2032mod tests {
2033 use super::*;
2034
2035 #[test]
2036 fn test_is_ascii_success() {
2037 let mut src: Vec<u8> = Vec::with_capacity(128);
2038 src.resize(128, 0);
2039 for i in 0..src.len() {
2040 src[i] = i as u8;
2041 }
2042 for i in 0..src.len() {
2043 assert!(is_ascii(&src[i..]));
2044 }
2045 }
2046
2047 #[test]
2048 fn test_is_ascii_fail() {
2049 let mut src: Vec<u8> = Vec::with_capacity(128);
2050 src.resize(128, 0);
2051 for i in 0..src.len() {
2052 src[i] = i as u8;
2053 }
2054 for i in 0..src.len() {
2055 let tail = &mut src[i..];
2056 for j in 0..tail.len() {
2057 tail[j] = 0xA0;
2058 assert!(!is_ascii(tail));
2059 }
2060 }
2061 }
2062
2063 #[test]
2064 fn test_is_basic_latin_success() {
2065 let mut src: Vec<u16> = Vec::with_capacity(128);
2066 src.resize(128, 0);
2067 for i in 0..src.len() {
2068 src[i] = i as u16;
2069 }
2070 for i in 0..src.len() {
2071 assert!(is_basic_latin(&src[i..]));
2072 }
2073 }
2074
2075 #[test]
2076 fn test_is_basic_latin_fail() {
2077 let mut src: Vec<u16> = Vec::with_capacity(128);
2078 src.resize(128, 0);
2079 for i in 0..src.len() {
2080 src[i] = i as u16;
2081 }
2082 for i in 0..src.len() {
2083 let tail = &mut src[i..];
2084 for j in 0..tail.len() {
2085 tail[j] = 0xA0;
2086 assert!(!is_basic_latin(tail));
2087 }
2088 }
2089 }
2090
2091 #[test]
2092 fn test_is_utf16_latin1_success() {
2093 let mut src: Vec<u16> = Vec::with_capacity(256);
2094 src.resize(256, 0);
2095 for i in 0..src.len() {
2096 src[i] = i as u16;
2097 }
2098 for i in 0..src.len() {
2099 assert!(is_utf16_latin1(&src[i..]));
2100 assert_eq!(
2101 check_utf16_for_latin1_and_bidi(&src[i..]),
2102 Latin1Bidi::Latin1
2103 );
2104 }
2105 }
2106
2107 #[test]
2108 fn test_is_utf16_latin1_fail() {
2109 let len = if cfg!(miri) { 64 } else { 256 }; let mut src: Vec<u16> = Vec::with_capacity(len);
2111 src.resize(len, 0);
2112 for i in 0..src.len() {
2113 src[i] = i as u16;
2114 }
2115 for i in 0..src.len() {
2116 let tail = &mut src[i..];
2117 for j in 0..tail.len() {
2118 tail[j] = 0x100 + j as u16;
2119 assert!(!is_utf16_latin1(tail));
2120 assert_ne!(check_utf16_for_latin1_and_bidi(tail), Latin1Bidi::Latin1);
2121 }
2122 }
2123 }
2124
2125 #[test]
2126 fn test_is_str_latin1_success() {
2127 let len = if cfg!(miri) { 64 } else { 256 }; let mut src: Vec<u16> = Vec::with_capacity(len);
2129 src.resize(len, 0);
2130 for i in 0..src.len() {
2131 src[i] = i as u16;
2132 }
2133 for i in 0..src.len() {
2134 let s = String::from_utf16(&src[i..]).unwrap();
2135 assert!(is_str_latin1(&s[..]));
2136 assert_eq!(check_str_for_latin1_and_bidi(&s[..]), Latin1Bidi::Latin1);
2137 }
2138 }
2139
2140 #[test]
2141 fn test_is_str_latin1_fail() {
2142 let len = if cfg!(miri) { 32 } else { 256 }; let mut src: Vec<u16> = Vec::with_capacity(len);
2144 src.resize(len, 0);
2145 for i in 0..src.len() {
2146 src[i] = i as u16;
2147 }
2148 for i in 0..src.len() {
2149 let tail = &mut src[i..];
2150 for j in 0..tail.len() {
2151 tail[j] = 0x100 + j as u16;
2152 let s = String::from_utf16(tail).unwrap();
2153 assert!(!is_str_latin1(&s[..]));
2154 assert_ne!(check_str_for_latin1_and_bidi(&s[..]), Latin1Bidi::Latin1);
2155 }
2156 }
2157 }
2158
2159 #[test]
2160 fn test_is_utf8_latin1_success() {
2161 let len = if cfg!(miri) { 64 } else { 256 }; let mut src: Vec<u16> = Vec::with_capacity(len);
2163 src.resize(len, 0);
2164 for i in 0..src.len() {
2165 src[i] = i as u16;
2166 }
2167 for i in 0..src.len() {
2168 let s = String::from_utf16(&src[i..]).unwrap();
2169 assert!(is_utf8_latin1(s.as_bytes()));
2170 assert_eq!(
2171 check_utf8_for_latin1_and_bidi(s.as_bytes()),
2172 Latin1Bidi::Latin1
2173 );
2174 }
2175 }
2176
2177 #[test]
2178 fn test_is_utf8_latin1_fail() {
2179 let len = if cfg!(miri) { 32 } else { 256 }; let mut src: Vec<u16> = Vec::with_capacity(len);
2181 src.resize(len, 0);
2182 for i in 0..src.len() {
2183 src[i] = i as u16;
2184 }
2185 for i in 0..src.len() {
2186 let tail = &mut src[i..];
2187 for j in 0..tail.len() {
2188 tail[j] = 0x100 + j as u16;
2189 let s = String::from_utf16(tail).unwrap();
2190 assert!(!is_utf8_latin1(s.as_bytes()));
2191 assert_ne!(
2192 check_utf8_for_latin1_and_bidi(s.as_bytes()),
2193 Latin1Bidi::Latin1
2194 );
2195 }
2196 }
2197 }
2198
2199 #[test]
2200 fn test_is_utf8_latin1_invalid() {
2201 assert!(!is_utf8_latin1(b"\xC3"));
2202 assert!(!is_utf8_latin1(b"a\xC3"));
2203 assert!(!is_utf8_latin1(b"\xFF"));
2204 assert!(!is_utf8_latin1(b"a\xFF"));
2205 assert!(!is_utf8_latin1(b"\xC3\xFF"));
2206 assert!(!is_utf8_latin1(b"a\xC3\xFF"));
2207 }
2208
2209 #[test]
2210 fn test_convert_utf8_to_utf16() {
2211 let src = "abcdefghijklmnopqrstu\u{1F4A9}v\u{2603}w\u{00B6}xyzz";
2212 let mut dst: Vec<u16> = Vec::with_capacity(src.len() + 1);
2213 dst.resize(src.len() + 1, 0);
2214 let len = convert_utf8_to_utf16(src.as_bytes(), &mut dst[..]);
2215 dst.truncate(len);
2216 let reference: Vec<u16> = src.encode_utf16().collect();
2217 assert_eq!(dst, reference);
2218 }
2219
2220 #[test]
2221 fn test_convert_str_to_utf16() {
2222 let src = "abcdefghijklmnopqrstu\u{1F4A9}v\u{2603}w\u{00B6}xyzz";
2223 let mut dst: Vec<u16> = Vec::with_capacity(src.len());
2224 dst.resize(src.len(), 0);
2225 let len = convert_str_to_utf16(src, &mut dst[..]);
2226 dst.truncate(len);
2227 let reference: Vec<u16> = src.encode_utf16().collect();
2228 assert_eq!(dst, reference);
2229 }
2230
2231 #[test]
2232 fn test_convert_utf16_to_utf8_partial() {
2233 let reference = "abcdefghijklmnopqrstu\u{1F4A9}v\u{2603}w\u{00B6}xyzz";
2234 let src: Vec<u16> = reference.encode_utf16().collect();
2235 let mut dst: Vec<u8> = Vec::with_capacity(src.len() * 3 + 1);
2236 dst.resize(src.len() * 3 + 1, 0);
2237 let (read, written) = convert_utf16_to_utf8_partial(&src[..], &mut dst[..24]);
2238 let len = written + convert_utf16_to_utf8(&src[read..], &mut dst[written..]);
2239 dst.truncate(len);
2240 assert_eq!(dst, reference.as_bytes());
2241 }
2242
2243 #[test]
2244 fn test_convert_utf16_to_utf8() {
2245 let reference = "abcdefghijklmnopqrstu\u{1F4A9}v\u{2603}w\u{00B6}xyzz";
2246 let src: Vec<u16> = reference.encode_utf16().collect();
2247 let mut dst: Vec<u8> = Vec::with_capacity(src.len() * 3 + 1);
2248 dst.resize(src.len() * 3 + 1, 0);
2249 let len = convert_utf16_to_utf8(&src[..], &mut dst[..]);
2250 dst.truncate(len);
2251 assert_eq!(dst, reference.as_bytes());
2252 }
2253
2254 #[test]
2255 fn test_convert_latin1_to_utf16() {
2256 let mut src: Vec<u8> = Vec::with_capacity(256);
2257 src.resize(256, 0);
2258 let mut reference: Vec<u16> = Vec::with_capacity(256);
2259 reference.resize(256, 0);
2260 for i in 0..256 {
2261 src[i] = i as u8;
2262 reference[i] = i as u16;
2263 }
2264 let mut dst: Vec<u16> = Vec::with_capacity(src.len());
2265 dst.resize(src.len(), 0);
2266 convert_latin1_to_utf16(&src[..], &mut dst[..]);
2267 assert_eq!(dst, reference);
2268 }
2269
2270 #[test]
2271 fn test_convert_latin1_to_utf8_partial() {
2272 let mut dst = [0u8, 2];
2273 let (read, written) = convert_latin1_to_utf8_partial(b"a\xFF", &mut dst[..]);
2274 assert_eq!(read, 1);
2275 assert_eq!(written, 1);
2276 }
2277
2278 #[test]
2279 fn test_convert_latin1_to_utf8() {
2280 let mut src: Vec<u8> = Vec::with_capacity(256);
2281 src.resize(256, 0);
2282 let mut reference: Vec<u16> = Vec::with_capacity(256);
2283 reference.resize(256, 0);
2284 for i in 0..256 {
2285 src[i] = i as u8;
2286 reference[i] = i as u16;
2287 }
2288 let s = String::from_utf16(&reference[..]).unwrap();
2289 let mut dst: Vec<u8> = Vec::with_capacity(src.len() * 2);
2290 dst.resize(src.len() * 2, 0);
2291 let len = convert_latin1_to_utf8(&src[..], &mut dst[..]);
2292 dst.truncate(len);
2293 assert_eq!(&dst[..], s.as_bytes());
2294 }
2295
2296 #[test]
2297 fn test_convert_utf8_to_latin1_lossy() {
2298 let mut reference: Vec<u8> = Vec::with_capacity(256);
2299 reference.resize(256, 0);
2300 let mut src16: Vec<u16> = Vec::with_capacity(256);
2301 src16.resize(256, 0);
2302 for i in 0..256 {
2303 src16[i] = i as u16;
2304 reference[i] = i as u8;
2305 }
2306 let src = String::from_utf16(&src16[..]).unwrap();
2307 let mut dst: Vec<u8> = Vec::with_capacity(src.len());
2308 dst.resize(src.len(), 0);
2309 let len = convert_utf8_to_latin1_lossy(src.as_bytes(), &mut dst[..]);
2310 dst.truncate(len);
2311 assert_eq!(dst, reference);
2312 }
2313
2314 #[cfg(all(debug_assertions, not(fuzzing)))]
2315 #[test]
2316 #[should_panic]
2317 fn test_convert_utf8_to_latin1_lossy_panics() {
2318 let mut dst = [0u8; 16];
2319 let _ = convert_utf8_to_latin1_lossy("\u{100}".as_bytes(), &mut dst[..]);
2320 }
2321
2322 #[test]
2323 fn test_convert_utf16_to_latin1_lossy() {
2324 let mut src: Vec<u16> = Vec::with_capacity(256);
2325 src.resize(256, 0);
2326 let mut reference: Vec<u8> = Vec::with_capacity(256);
2327 reference.resize(256, 0);
2328 for i in 0..256 {
2329 src[i] = i as u16;
2330 reference[i] = i as u8;
2331 }
2332 let mut dst: Vec<u8> = Vec::with_capacity(src.len());
2333 dst.resize(src.len(), 0);
2334 convert_utf16_to_latin1_lossy(&src[..], &mut dst[..]);
2335 assert_eq!(dst, reference);
2336 }
2337
2338 #[test]
2339 fn test_convert_utf16_to_latin1_lossy_panics() {
2341 let mut dst = [0u8; 16];
2342 let _ = convert_utf16_to_latin1_lossy(&[0x0100u16], &mut dst[..]);
2343 }
2344
2345 #[test]
2346 fn test_utf16_valid_up_to() {
2347 let valid = vec![
2348 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0x2603u16,
2349 0xD83Du16, 0xDCA9u16, 0x00B6u16,
2350 ];
2351 assert_eq!(utf16_valid_up_to(&valid[..]), 16);
2352 let lone_high = vec![
2353 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16,
2354 0x2603u16, 0xD83Du16, 0x00B6u16,
2355 ];
2356 assert_eq!(utf16_valid_up_to(&lone_high[..]), 14);
2357 let lone_low = vec![
2358 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16,
2359 0x2603u16, 0xDCA9u16, 0x00B6u16,
2360 ];
2361 assert_eq!(utf16_valid_up_to(&lone_low[..]), 14);
2362 let lone_high_at_end = vec![
2363 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16,
2364 0x2603u16, 0x00B6u16, 0xD83Du16,
2365 ];
2366 assert_eq!(utf16_valid_up_to(&lone_high_at_end[..]), 15);
2367 }
2368
2369 #[test]
2370 fn test_ensure_utf16_validity() {
2371 let mut src = vec![
2372 0u16, 0xD83Du16, 0u16, 0u16, 0u16, 0xD83Du16, 0xDCA9u16, 0u16, 0u16, 0u16, 0u16, 0u16,
2373 0u16, 0xDCA9u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16,
2374 0u16, 0u16, 0u16, 0u16, 0u16, 0u16,
2375 ];
2376 let reference = vec![
2377 0u16, 0xFFFDu16, 0u16, 0u16, 0u16, 0xD83Du16, 0xDCA9u16, 0u16, 0u16, 0u16, 0u16, 0u16,
2378 0u16, 0xFFFDu16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16, 0u16,
2379 0u16, 0u16, 0u16, 0u16, 0u16, 0u16,
2380 ];
2381 ensure_utf16_validity(&mut src[..]);
2382 assert_eq!(src, reference);
2383 }
2384
2385 #[test]
2386 fn test_is_char_bidi() {
2387 assert!(!is_char_bidi('a'));
2388 assert!(!is_char_bidi('\u{03B1}'));
2389 assert!(!is_char_bidi('\u{3041}'));
2390 assert!(!is_char_bidi('\u{1F4A9}'));
2391 assert!(!is_char_bidi('\u{FE00}'));
2392 assert!(!is_char_bidi('\u{202C}'));
2393 assert!(!is_char_bidi('\u{FEFF}'));
2394 assert!(is_char_bidi('\u{0590}'));
2395 assert!(is_char_bidi('\u{08FF}'));
2396 assert!(is_char_bidi('\u{061C}'));
2397 assert!(is_char_bidi('\u{FB50}'));
2398 assert!(is_char_bidi('\u{FDFF}'));
2399 assert!(is_char_bidi('\u{FE70}'));
2400 assert!(is_char_bidi('\u{FEFE}'));
2401 assert!(is_char_bidi('\u{200F}'));
2402 assert!(is_char_bidi('\u{202B}'));
2403 assert!(is_char_bidi('\u{202E}'));
2404 assert!(is_char_bidi('\u{2067}'));
2405 assert!(is_char_bidi('\u{10800}'));
2406 assert!(is_char_bidi('\u{10FFF}'));
2407 assert!(is_char_bidi('\u{1E800}'));
2408 assert!(is_char_bidi('\u{1EFFF}'));
2409 }
2410
2411 #[test]
2412 fn test_is_utf16_code_unit_bidi() {
2413 assert!(!is_utf16_code_unit_bidi(0x0062));
2414 assert!(!is_utf16_code_unit_bidi(0x03B1));
2415 assert!(!is_utf16_code_unit_bidi(0x3041));
2416 assert!(!is_utf16_code_unit_bidi(0xD801));
2417 assert!(!is_utf16_code_unit_bidi(0xFE00));
2418 assert!(!is_utf16_code_unit_bidi(0x202C));
2419 assert!(!is_utf16_code_unit_bidi(0xFEFF));
2420 assert!(is_utf16_code_unit_bidi(0x0590));
2421 assert!(is_utf16_code_unit_bidi(0x08FF));
2422 assert!(is_utf16_code_unit_bidi(0x061C));
2423 assert!(is_utf16_code_unit_bidi(0xFB1D));
2424 assert!(is_utf16_code_unit_bidi(0xFB50));
2425 assert!(is_utf16_code_unit_bidi(0xFDFF));
2426 assert!(is_utf16_code_unit_bidi(0xFE70));
2427 assert!(is_utf16_code_unit_bidi(0xFEFE));
2428 assert!(is_utf16_code_unit_bidi(0x200F));
2429 assert!(is_utf16_code_unit_bidi(0x202B));
2430 assert!(is_utf16_code_unit_bidi(0x202E));
2431 assert!(is_utf16_code_unit_bidi(0x2067));
2432 assert!(is_utf16_code_unit_bidi(0xD802));
2433 assert!(is_utf16_code_unit_bidi(0xD803));
2434 assert!(is_utf16_code_unit_bidi(0xD83A));
2435 assert!(is_utf16_code_unit_bidi(0xD83B));
2436 }
2437
2438 #[test]
2439 fn test_is_str_bidi() {
2440 assert!(!is_str_bidi("abcdefghijklmnopaabcdefghijklmnop"));
2441 assert!(!is_str_bidi("abcdefghijklmnop\u{03B1}abcdefghijklmnop"));
2442 assert!(!is_str_bidi("abcdefghijklmnop\u{3041}abcdefghijklmnop"));
2443 assert!(!is_str_bidi("abcdefghijklmnop\u{1F4A9}abcdefghijklmnop"));
2444 assert!(!is_str_bidi("abcdefghijklmnop\u{FE00}abcdefghijklmnop"));
2445 assert!(!is_str_bidi("abcdefghijklmnop\u{202C}abcdefghijklmnop"));
2446 assert!(!is_str_bidi("abcdefghijklmnop\u{FEFF}abcdefghijklmnop"));
2447 assert!(is_str_bidi("abcdefghijklmnop\u{0590}abcdefghijklmnop"));
2448 assert!(is_str_bidi("abcdefghijklmnop\u{08FF}abcdefghijklmnop"));
2449 assert!(is_str_bidi("abcdefghijklmnop\u{061C}abcdefghijklmnop"));
2450 assert!(is_str_bidi("abcdefghijklmnop\u{FB50}abcdefghijklmnop"));
2451 assert!(is_str_bidi("abcdefghijklmnop\u{FDFF}abcdefghijklmnop"));
2452 assert!(is_str_bidi("abcdefghijklmnop\u{FE70}abcdefghijklmnop"));
2453 assert!(is_str_bidi("abcdefghijklmnop\u{FEFE}abcdefghijklmnop"));
2454 assert!(is_str_bidi("abcdefghijklmnop\u{200F}abcdefghijklmnop"));
2455 assert!(is_str_bidi("abcdefghijklmnop\u{202B}abcdefghijklmnop"));
2456 assert!(is_str_bidi("abcdefghijklmnop\u{202E}abcdefghijklmnop"));
2457 assert!(is_str_bidi("abcdefghijklmnop\u{2067}abcdefghijklmnop"));
2458 assert!(is_str_bidi("abcdefghijklmnop\u{10800}abcdefghijklmnop"));
2459 assert!(is_str_bidi("abcdefghijklmnop\u{10FFF}abcdefghijklmnop"));
2460 assert!(is_str_bidi("abcdefghijklmnop\u{1E800}abcdefghijklmnop"));
2461 assert!(is_str_bidi("abcdefghijklmnop\u{1EFFF}abcdefghijklmnop"));
2462 }
2463
2464 #[test]
2465 fn test_is_utf8_bidi() {
2466 assert!(!is_utf8_bidi(
2467 "abcdefghijklmnopaabcdefghijklmnop".as_bytes()
2468 ));
2469 assert!(!is_utf8_bidi(
2470 "abcdefghijklmnop\u{03B1}abcdefghijklmnop".as_bytes()
2471 ));
2472 assert!(!is_utf8_bidi(
2473 "abcdefghijklmnop\u{3041}abcdefghijklmnop".as_bytes()
2474 ));
2475 assert!(!is_utf8_bidi(
2476 "abcdefghijklmnop\u{1F4A9}abcdefghijklmnop".as_bytes()
2477 ));
2478 assert!(!is_utf8_bidi(
2479 "abcdefghijklmnop\u{FE00}abcdefghijklmnop".as_bytes()
2480 ));
2481 assert!(!is_utf8_bidi(
2482 "abcdefghijklmnop\u{202C}abcdefghijklmnop".as_bytes()
2483 ));
2484 assert!(!is_utf8_bidi(
2485 "abcdefghijklmnop\u{FEFF}abcdefghijklmnop".as_bytes()
2486 ));
2487 assert!(is_utf8_bidi(
2488 "abcdefghijklmnop\u{0590}abcdefghijklmnop".as_bytes()
2489 ));
2490 assert!(is_utf8_bidi(
2491 "abcdefghijklmnop\u{08FF}abcdefghijklmnop".as_bytes()
2492 ));
2493 assert!(is_utf8_bidi(
2494 "abcdefghijklmnop\u{061C}abcdefghijklmnop".as_bytes()
2495 ));
2496 assert!(is_utf8_bidi(
2497 "abcdefghijklmnop\u{FB50}abcdefghijklmnop".as_bytes()
2498 ));
2499 assert!(is_utf8_bidi(
2500 "abcdefghijklmnop\u{FDFF}abcdefghijklmnop".as_bytes()
2501 ));
2502 assert!(is_utf8_bidi(
2503 "abcdefghijklmnop\u{FE70}abcdefghijklmnop".as_bytes()
2504 ));
2505 assert!(is_utf8_bidi(
2506 "abcdefghijklmnop\u{FEFE}abcdefghijklmnop".as_bytes()
2507 ));
2508 assert!(is_utf8_bidi(
2509 "abcdefghijklmnop\u{200F}abcdefghijklmnop".as_bytes()
2510 ));
2511 assert!(is_utf8_bidi(
2512 "abcdefghijklmnop\u{202B}abcdefghijklmnop".as_bytes()
2513 ));
2514 assert!(is_utf8_bidi(
2515 "abcdefghijklmnop\u{202E}abcdefghijklmnop".as_bytes()
2516 ));
2517 assert!(is_utf8_bidi(
2518 "abcdefghijklmnop\u{2067}abcdefghijklmnop".as_bytes()
2519 ));
2520 assert!(is_utf8_bidi(
2521 "abcdefghijklmnop\u{10800}abcdefghijklmnop".as_bytes()
2522 ));
2523 assert!(is_utf8_bidi(
2524 "abcdefghijklmnop\u{10FFF}abcdefghijklmnop".as_bytes()
2525 ));
2526 assert!(is_utf8_bidi(
2527 "abcdefghijklmnop\u{1E800}abcdefghijklmnop".as_bytes()
2528 ));
2529 assert!(is_utf8_bidi(
2530 "abcdefghijklmnop\u{1EFFF}abcdefghijklmnop".as_bytes()
2531 ));
2532 }
2533
2534 #[test]
2535 fn test_is_utf16_bidi() {
2536 assert!(!is_utf16_bidi(&[
2537 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x0062, 0x62, 0x63, 0x64, 0x65, 0x66,
2538 0x67, 0x68, 0x69,
2539 ]));
2540 assert!(!is_utf16_bidi(&[
2541 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x03B1, 0x62, 0x63, 0x64, 0x65, 0x66,
2542 0x67, 0x68, 0x69,
2543 ]));
2544 assert!(!is_utf16_bidi(&[
2545 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x3041, 0x62, 0x63, 0x64, 0x65, 0x66,
2546 0x67, 0x68, 0x69,
2547 ]));
2548 assert!(!is_utf16_bidi(&[
2549 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xD801, 0x62, 0x63, 0x64, 0x65, 0x66,
2550 0x67, 0x68, 0x69,
2551 ]));
2552 assert!(!is_utf16_bidi(&[
2553 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xFE00, 0x62, 0x63, 0x64, 0x65, 0x66,
2554 0x67, 0x68, 0x69,
2555 ]));
2556 assert!(!is_utf16_bidi(&[
2557 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x202C, 0x62, 0x63, 0x64, 0x65, 0x66,
2558 0x67, 0x68, 0x69,
2559 ]));
2560 assert!(!is_utf16_bidi(&[
2561 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xFEFF, 0x62, 0x63, 0x64, 0x65, 0x66,
2562 0x67, 0x68, 0x69,
2563 ]));
2564 assert!(is_utf16_bidi(&[
2565 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x0590, 0x62, 0x63, 0x64, 0x65, 0x66,
2566 0x67, 0x68, 0x69,
2567 ]));
2568 assert!(is_utf16_bidi(&[
2569 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x08FF, 0x62, 0x63, 0x64, 0x65, 0x66,
2570 0x67, 0x68, 0x69,
2571 ]));
2572 assert!(is_utf16_bidi(&[
2573 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x061C, 0x62, 0x63, 0x64, 0x65, 0x66,
2574 0x67, 0x68, 0x69,
2575 ]));
2576 assert!(is_utf16_bidi(&[
2577 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xFB1D, 0x62, 0x63, 0x64, 0x65, 0x66,
2578 0x67, 0x68, 0x69,
2579 ]));
2580 assert!(is_utf16_bidi(&[
2581 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xFB50, 0x62, 0x63, 0x64, 0x65, 0x66,
2582 0x67, 0x68, 0x69,
2583 ]));
2584 assert!(is_utf16_bidi(&[
2585 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xFDFF, 0x62, 0x63, 0x64, 0x65, 0x66,
2586 0x67, 0x68, 0x69,
2587 ]));
2588 assert!(is_utf16_bidi(&[
2589 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xFE70, 0x62, 0x63, 0x64, 0x65, 0x66,
2590 0x67, 0x68, 0x69,
2591 ]));
2592 assert!(is_utf16_bidi(&[
2593 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xFEFE, 0x62, 0x63, 0x64, 0x65, 0x66,
2594 0x67, 0x68, 0x69,
2595 ]));
2596 assert!(is_utf16_bidi(&[
2597 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x200F, 0x62, 0x63, 0x64, 0x65, 0x66,
2598 0x67, 0x68, 0x69,
2599 ]));
2600 assert!(is_utf16_bidi(&[
2601 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x202B, 0x62, 0x63, 0x64, 0x65, 0x66,
2602 0x67, 0x68, 0x69,
2603 ]));
2604 assert!(is_utf16_bidi(&[
2605 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x202E, 0x62, 0x63, 0x64, 0x65, 0x66,
2606 0x67, 0x68, 0x69,
2607 ]));
2608 assert!(is_utf16_bidi(&[
2609 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x2067, 0x62, 0x63, 0x64, 0x65, 0x66,
2610 0x67, 0x68, 0x69,
2611 ]));
2612 assert!(is_utf16_bidi(&[
2613 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xD802, 0x62, 0x63, 0x64, 0x65, 0x66,
2614 0x67, 0x68, 0x69,
2615 ]));
2616 assert!(is_utf16_bidi(&[
2617 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xD803, 0x62, 0x63, 0x64, 0x65, 0x66,
2618 0x67, 0x68, 0x69,
2619 ]));
2620 assert!(is_utf16_bidi(&[
2621 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xD83A, 0x62, 0x63, 0x64, 0x65, 0x66,
2622 0x67, 0x68, 0x69,
2623 ]));
2624 assert!(is_utf16_bidi(&[
2625 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xD83B, 0x62, 0x63, 0x64, 0x65, 0x66,
2626 0x67, 0x68, 0x69,
2627 ]));
2628
2629 assert!(is_utf16_bidi(&[
2630 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x0590, 0x3041, 0x62, 0x63, 0x64, 0x65,
2631 0x66, 0x67, 0x68, 0x69,
2632 ]));
2633 }
2634
2635 #[test]
2636 fn test_check_str_for_latin1_and_bidi() {
2637 assert_ne!(
2638 check_str_for_latin1_and_bidi("abcdefghijklmnopaabcdefghijklmnop"),
2639 Latin1Bidi::Bidi
2640 );
2641 assert_ne!(
2642 check_str_for_latin1_and_bidi("abcdefghijklmnop\u{03B1}abcdefghijklmnop"),
2643 Latin1Bidi::Bidi
2644 );
2645 assert_ne!(
2646 check_str_for_latin1_and_bidi("abcdefghijklmnop\u{3041}abcdefghijklmnop"),
2647 Latin1Bidi::Bidi
2648 );
2649 assert_ne!(
2650 check_str_for_latin1_and_bidi("abcdefghijklmnop\u{1F4A9}abcdefghijklmnop"),
2651 Latin1Bidi::Bidi
2652 );
2653 assert_ne!(
2654 check_str_for_latin1_and_bidi("abcdefghijklmnop\u{FE00}abcdefghijklmnop"),
2655 Latin1Bidi::Bidi
2656 );
2657 assert_ne!(
2658 check_str_for_latin1_and_bidi("abcdefghijklmnop\u{202C}abcdefghijklmnop"),
2659 Latin1Bidi::Bidi
2660 );
2661 assert_ne!(
2662 check_str_for_latin1_and_bidi("abcdefghijklmnop\u{FEFF}abcdefghijklmnop"),
2663 Latin1Bidi::Bidi
2664 );
2665 assert_eq!(
2666 check_str_for_latin1_and_bidi("abcdefghijklmnop\u{0590}abcdefghijklmnop"),
2667 Latin1Bidi::Bidi
2668 );
2669 assert_eq!(
2670 check_str_for_latin1_and_bidi("abcdefghijklmnop\u{08FF}abcdefghijklmnop"),
2671 Latin1Bidi::Bidi
2672 );
2673 assert_eq!(
2674 check_str_for_latin1_and_bidi("abcdefghijklmnop\u{061C}abcdefghijklmnop"),
2675 Latin1Bidi::Bidi
2676 );
2677 assert_eq!(
2678 check_str_for_latin1_and_bidi("abcdefghijklmnop\u{FB50}abcdefghijklmnop"),
2679 Latin1Bidi::Bidi
2680 );
2681 assert_eq!(
2682 check_str_for_latin1_and_bidi("abcdefghijklmnop\u{FDFF}abcdefghijklmnop"),
2683 Latin1Bidi::Bidi
2684 );
2685 assert_eq!(
2686 check_str_for_latin1_and_bidi("abcdefghijklmnop\u{FE70}abcdefghijklmnop"),
2687 Latin1Bidi::Bidi
2688 );
2689 assert_eq!(
2690 check_str_for_latin1_and_bidi("abcdefghijklmnop\u{FEFE}abcdefghijklmnop"),
2691 Latin1Bidi::Bidi
2692 );
2693 assert_eq!(
2694 check_str_for_latin1_and_bidi("abcdefghijklmnop\u{200F}abcdefghijklmnop"),
2695 Latin1Bidi::Bidi
2696 );
2697 assert_eq!(
2698 check_str_for_latin1_and_bidi("abcdefghijklmnop\u{202B}abcdefghijklmnop"),
2699 Latin1Bidi::Bidi
2700 );
2701 assert_eq!(
2702 check_str_for_latin1_and_bidi("abcdefghijklmnop\u{202E}abcdefghijklmnop"),
2703 Latin1Bidi::Bidi
2704 );
2705 assert_eq!(
2706 check_str_for_latin1_and_bidi("abcdefghijklmnop\u{2067}abcdefghijklmnop"),
2707 Latin1Bidi::Bidi
2708 );
2709 assert_eq!(
2710 check_str_for_latin1_and_bidi("abcdefghijklmnop\u{10800}abcdefghijklmnop"),
2711 Latin1Bidi::Bidi
2712 );
2713 assert_eq!(
2714 check_str_for_latin1_and_bidi("abcdefghijklmnop\u{10FFF}abcdefghijklmnop"),
2715 Latin1Bidi::Bidi
2716 );
2717 assert_eq!(
2718 check_str_for_latin1_and_bidi("abcdefghijklmnop\u{1E800}abcdefghijklmnop"),
2719 Latin1Bidi::Bidi
2720 );
2721 assert_eq!(
2722 check_str_for_latin1_and_bidi("abcdefghijklmnop\u{1EFFF}abcdefghijklmnop"),
2723 Latin1Bidi::Bidi
2724 );
2725 }
2726
2727 #[test]
2728 fn test_check_utf8_for_latin1_and_bidi() {
2729 assert_ne!(
2730 check_utf8_for_latin1_and_bidi("abcdefghijklmnopaabcdefghijklmnop".as_bytes()),
2731 Latin1Bidi::Bidi
2732 );
2733 assert_ne!(
2734 check_utf8_for_latin1_and_bidi("abcdefghijklmnop\u{03B1}abcdefghijklmnop".as_bytes()),
2735 Latin1Bidi::Bidi
2736 );
2737 assert_ne!(
2738 check_utf8_for_latin1_and_bidi("abcdefghijklmnop\u{3041}abcdefghijklmnop".as_bytes()),
2739 Latin1Bidi::Bidi
2740 );
2741 assert_ne!(
2742 check_utf8_for_latin1_and_bidi("abcdefghijklmnop\u{1F4A9}abcdefghijklmnop".as_bytes()),
2743 Latin1Bidi::Bidi
2744 );
2745 assert_ne!(
2746 check_utf8_for_latin1_and_bidi("abcdefghijklmnop\u{FE00}abcdefghijklmnop".as_bytes()),
2747 Latin1Bidi::Bidi
2748 );
2749 assert_ne!(
2750 check_utf8_for_latin1_and_bidi("abcdefghijklmnop\u{202C}abcdefghijklmnop".as_bytes()),
2751 Latin1Bidi::Bidi
2752 );
2753 assert_ne!(
2754 check_utf8_for_latin1_and_bidi("abcdefghijklmnop\u{FEFF}abcdefghijklmnop".as_bytes()),
2755 Latin1Bidi::Bidi
2756 );
2757 assert_eq!(
2758 check_utf8_for_latin1_and_bidi("abcdefghijklmnop\u{0590}abcdefghijklmnop".as_bytes()),
2759 Latin1Bidi::Bidi
2760 );
2761 assert_eq!(
2762 check_utf8_for_latin1_and_bidi("abcdefghijklmnop\u{08FF}abcdefghijklmnop".as_bytes()),
2763 Latin1Bidi::Bidi
2764 );
2765 assert_eq!(
2766 check_utf8_for_latin1_and_bidi("abcdefghijklmnop\u{061C}abcdefghijklmnop".as_bytes()),
2767 Latin1Bidi::Bidi
2768 );
2769 assert_eq!(
2770 check_utf8_for_latin1_and_bidi("abcdefghijklmnop\u{FB50}abcdefghijklmnop".as_bytes()),
2771 Latin1Bidi::Bidi
2772 );
2773 assert_eq!(
2774 check_utf8_for_latin1_and_bidi("abcdefghijklmnop\u{FDFF}abcdefghijklmnop".as_bytes()),
2775 Latin1Bidi::Bidi
2776 );
2777 assert_eq!(
2778 check_utf8_for_latin1_and_bidi("abcdefghijklmnop\u{FE70}abcdefghijklmnop".as_bytes()),
2779 Latin1Bidi::Bidi
2780 );
2781 assert_eq!(
2782 check_utf8_for_latin1_and_bidi("abcdefghijklmnop\u{FEFE}abcdefghijklmnop".as_bytes()),
2783 Latin1Bidi::Bidi
2784 );
2785 assert_eq!(
2786 check_utf8_for_latin1_and_bidi("abcdefghijklmnop\u{200F}abcdefghijklmnop".as_bytes()),
2787 Latin1Bidi::Bidi
2788 );
2789 assert_eq!(
2790 check_utf8_for_latin1_and_bidi("abcdefghijklmnop\u{202B}abcdefghijklmnop".as_bytes()),
2791 Latin1Bidi::Bidi
2792 );
2793 assert_eq!(
2794 check_utf8_for_latin1_and_bidi("abcdefghijklmnop\u{202E}abcdefghijklmnop".as_bytes()),
2795 Latin1Bidi::Bidi
2796 );
2797 assert_eq!(
2798 check_utf8_for_latin1_and_bidi("abcdefghijklmnop\u{2067}abcdefghijklmnop".as_bytes()),
2799 Latin1Bidi::Bidi
2800 );
2801 assert_eq!(
2802 check_utf8_for_latin1_and_bidi("abcdefghijklmnop\u{10800}abcdefghijklmnop".as_bytes()),
2803 Latin1Bidi::Bidi
2804 );
2805 assert_eq!(
2806 check_utf8_for_latin1_and_bidi("abcdefghijklmnop\u{10FFF}abcdefghijklmnop".as_bytes()),
2807 Latin1Bidi::Bidi
2808 );
2809 assert_eq!(
2810 check_utf8_for_latin1_and_bidi("abcdefghijklmnop\u{1E800}abcdefghijklmnop".as_bytes()),
2811 Latin1Bidi::Bidi
2812 );
2813 assert_eq!(
2814 check_utf8_for_latin1_and_bidi("abcdefghijklmnop\u{1EFFF}abcdefghijklmnop".as_bytes()),
2815 Latin1Bidi::Bidi
2816 );
2817 }
2818
2819 #[test]
2820 fn test_check_utf16_for_latin1_and_bidi() {
2821 assert_ne!(
2822 check_utf16_for_latin1_and_bidi(&[
2823 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x0062, 0x62, 0x63, 0x64, 0x65,
2824 0x66, 0x67, 0x68, 0x69,
2825 ]),
2826 Latin1Bidi::Bidi
2827 );
2828 assert_ne!(
2829 check_utf16_for_latin1_and_bidi(&[
2830 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x03B1, 0x62, 0x63, 0x64, 0x65,
2831 0x66, 0x67, 0x68, 0x69,
2832 ]),
2833 Latin1Bidi::Bidi
2834 );
2835 assert_ne!(
2836 check_utf16_for_latin1_and_bidi(&[
2837 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x3041, 0x62, 0x63, 0x64, 0x65,
2838 0x66, 0x67, 0x68, 0x69,
2839 ]),
2840 Latin1Bidi::Bidi
2841 );
2842 assert_ne!(
2843 check_utf16_for_latin1_and_bidi(&[
2844 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xD801, 0x62, 0x63, 0x64, 0x65,
2845 0x66, 0x67, 0x68, 0x69,
2846 ]),
2847 Latin1Bidi::Bidi
2848 );
2849 assert_ne!(
2850 check_utf16_for_latin1_and_bidi(&[
2851 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xFE00, 0x62, 0x63, 0x64, 0x65,
2852 0x66, 0x67, 0x68, 0x69,
2853 ]),
2854 Latin1Bidi::Bidi
2855 );
2856 assert_ne!(
2857 check_utf16_for_latin1_and_bidi(&[
2858 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x202C, 0x62, 0x63, 0x64, 0x65,
2859 0x66, 0x67, 0x68, 0x69,
2860 ]),
2861 Latin1Bidi::Bidi
2862 );
2863 assert_ne!(
2864 check_utf16_for_latin1_and_bidi(&[
2865 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xFEFF, 0x62, 0x63, 0x64, 0x65,
2866 0x66, 0x67, 0x68, 0x69,
2867 ]),
2868 Latin1Bidi::Bidi
2869 );
2870 assert_eq!(
2871 check_utf16_for_latin1_and_bidi(&[
2872 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x0590, 0x62, 0x63, 0x64, 0x65,
2873 0x66, 0x67, 0x68, 0x69,
2874 ]),
2875 Latin1Bidi::Bidi
2876 );
2877 assert_eq!(
2878 check_utf16_for_latin1_and_bidi(&[
2879 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x08FF, 0x62, 0x63, 0x64, 0x65,
2880 0x66, 0x67, 0x68, 0x69,
2881 ]),
2882 Latin1Bidi::Bidi
2883 );
2884 assert_eq!(
2885 check_utf16_for_latin1_and_bidi(&[
2886 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x061C, 0x62, 0x63, 0x64, 0x65,
2887 0x66, 0x67, 0x68, 0x69,
2888 ]),
2889 Latin1Bidi::Bidi
2890 );
2891 assert_eq!(
2892 check_utf16_for_latin1_and_bidi(&[
2893 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xFB1D, 0x62, 0x63, 0x64, 0x65,
2894 0x66, 0x67, 0x68, 0x69,
2895 ]),
2896 Latin1Bidi::Bidi
2897 );
2898 assert_eq!(
2899 check_utf16_for_latin1_and_bidi(&[
2900 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xFB50, 0x62, 0x63, 0x64, 0x65,
2901 0x66, 0x67, 0x68, 0x69,
2902 ]),
2903 Latin1Bidi::Bidi
2904 );
2905 assert_eq!(
2906 check_utf16_for_latin1_and_bidi(&[
2907 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xFDFF, 0x62, 0x63, 0x64, 0x65,
2908 0x66, 0x67, 0x68, 0x69,
2909 ]),
2910 Latin1Bidi::Bidi
2911 );
2912 assert_eq!(
2913 check_utf16_for_latin1_and_bidi(&[
2914 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xFE70, 0x62, 0x63, 0x64, 0x65,
2915 0x66, 0x67, 0x68, 0x69,
2916 ]),
2917 Latin1Bidi::Bidi
2918 );
2919 assert_eq!(
2920 check_utf16_for_latin1_and_bidi(&[
2921 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xFEFE, 0x62, 0x63, 0x64, 0x65,
2922 0x66, 0x67, 0x68, 0x69,
2923 ]),
2924 Latin1Bidi::Bidi
2925 );
2926 assert_eq!(
2927 check_utf16_for_latin1_and_bidi(&[
2928 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x200F, 0x62, 0x63, 0x64, 0x65,
2929 0x66, 0x67, 0x68, 0x69,
2930 ]),
2931 Latin1Bidi::Bidi
2932 );
2933 assert_eq!(
2934 check_utf16_for_latin1_and_bidi(&[
2935 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x202B, 0x62, 0x63, 0x64, 0x65,
2936 0x66, 0x67, 0x68, 0x69,
2937 ]),
2938 Latin1Bidi::Bidi
2939 );
2940 assert_eq!(
2941 check_utf16_for_latin1_and_bidi(&[
2942 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x202E, 0x62, 0x63, 0x64, 0x65,
2943 0x66, 0x67, 0x68, 0x69,
2944 ]),
2945 Latin1Bidi::Bidi
2946 );
2947 assert_eq!(
2948 check_utf16_for_latin1_and_bidi(&[
2949 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x2067, 0x62, 0x63, 0x64, 0x65,
2950 0x66, 0x67, 0x68, 0x69,
2951 ]),
2952 Latin1Bidi::Bidi
2953 );
2954 assert_eq!(
2955 check_utf16_for_latin1_and_bidi(&[
2956 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xD802, 0x62, 0x63, 0x64, 0x65,
2957 0x66, 0x67, 0x68, 0x69,
2958 ]),
2959 Latin1Bidi::Bidi
2960 );
2961 assert_eq!(
2962 check_utf16_for_latin1_and_bidi(&[
2963 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xD803, 0x62, 0x63, 0x64, 0x65,
2964 0x66, 0x67, 0x68, 0x69,
2965 ]),
2966 Latin1Bidi::Bidi
2967 );
2968 assert_eq!(
2969 check_utf16_for_latin1_and_bidi(&[
2970 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xD83A, 0x62, 0x63, 0x64, 0x65,
2971 0x66, 0x67, 0x68, 0x69,
2972 ]),
2973 Latin1Bidi::Bidi
2974 );
2975 assert_eq!(
2976 check_utf16_for_latin1_and_bidi(&[
2977 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xD83B, 0x62, 0x63, 0x64, 0x65,
2978 0x66, 0x67, 0x68, 0x69,
2979 ]),
2980 Latin1Bidi::Bidi
2981 );
2982
2983 assert_eq!(
2984 check_utf16_for_latin1_and_bidi(&[
2985 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x0590, 0x3041, 0x62, 0x63, 0x64,
2986 0x65, 0x66, 0x67, 0x68, 0x69,
2987 ]),
2988 Latin1Bidi::Bidi
2989 );
2990 }
2991
2992 #[inline(always)]
2993 pub fn reference_is_char_bidi(c: char) -> bool {
2994 match c {
2995 '\u{0590}'..='\u{08FF}'
2996 | '\u{FB1D}'..='\u{FDFF}'
2997 | '\u{FE70}'..='\u{FEFE}'
2998 | '\u{10800}'..='\u{10FFF}'
2999 | '\u{1E800}'..='\u{1EFFF}'
3000 | '\u{200F}'
3001 | '\u{202B}'
3002 | '\u{202E}'
3003 | '\u{2067}' => true,
3004 _ => false,
3005 }
3006 }
3007
3008 #[inline(always)]
3009 pub fn reference_is_utf16_code_unit_bidi(u: u16) -> bool {
3010 match u {
3011 0x0590..=0x08FF
3012 | 0xFB1D..=0xFDFF
3013 | 0xFE70..=0xFEFE
3014 | 0xD802
3015 | 0xD803
3016 | 0xD83A
3017 | 0xD83B
3018 | 0x200F
3019 | 0x202B
3020 | 0x202E
3021 | 0x2067 => true,
3022 _ => false,
3023 }
3024 }
3025
3026 #[test]
3027 #[cfg_attr(miri, ignore)] fn test_is_char_bidi_thoroughly() {
3029 for i in 0..0xD800u32 {
3030 let c: char = ::core::char::from_u32(i).unwrap();
3031 assert_eq!(is_char_bidi(c), reference_is_char_bidi(c));
3032 }
3033 for i in 0xE000..0x110000u32 {
3034 let c: char = ::core::char::from_u32(i).unwrap();
3035 assert_eq!(is_char_bidi(c), reference_is_char_bidi(c));
3036 }
3037 }
3038
3039 #[test]
3040 #[cfg_attr(miri, ignore)] fn test_is_utf16_code_unit_bidi_thoroughly() {
3042 for i in 0..0x10000u32 {
3043 let u = i as u16;
3044 assert_eq!(
3045 is_utf16_code_unit_bidi(u),
3046 reference_is_utf16_code_unit_bidi(u)
3047 );
3048 }
3049 }
3050
3051 #[test]
3052 #[cfg_attr(miri, ignore)] fn test_is_str_bidi_thoroughly() {
3054 let mut buf = [0; 4];
3055 for i in 0..0xD800u32 {
3056 let c: char = ::core::char::from_u32(i).unwrap();
3057 assert_eq!(
3058 is_str_bidi(c.encode_utf8(&mut buf[..])),
3059 reference_is_char_bidi(c)
3060 );
3061 }
3062 for i in 0xE000..0x110000u32 {
3063 let c: char = ::core::char::from_u32(i).unwrap();
3064 assert_eq!(
3065 is_str_bidi(c.encode_utf8(&mut buf[..])),
3066 reference_is_char_bidi(c)
3067 );
3068 }
3069 }
3070
3071 #[test]
3072 #[cfg_attr(miri, ignore)] fn test_is_utf8_bidi_thoroughly() {
3074 let mut buf = [0; 8];
3075 for i in 0..0xD800u32 {
3076 let c: char = ::core::char::from_u32(i).unwrap();
3077 let expect = reference_is_char_bidi(c);
3078 {
3079 let len = {
3080 let bytes = c.encode_utf8(&mut buf[..]).as_bytes();
3081 assert_eq!(is_utf8_bidi(bytes), expect);
3082 bytes.len()
3083 };
3084 {
3085 let tail = &mut buf[len..];
3086 for b in tail.iter_mut() {
3087 *b = 0;
3088 }
3089 }
3090 }
3091 assert_eq!(is_utf8_bidi(&buf[..]), expect);
3092 }
3093 for i in 0xE000..0x110000u32 {
3094 let c: char = ::core::char::from_u32(i).unwrap();
3095 let expect = reference_is_char_bidi(c);
3096 {
3097 let len = {
3098 let bytes = c.encode_utf8(&mut buf[..]).as_bytes();
3099 assert_eq!(is_utf8_bidi(bytes), expect);
3100 bytes.len()
3101 };
3102 {
3103 let tail = &mut buf[len..];
3104 for b in tail.iter_mut() {
3105 *b = 0;
3106 }
3107 }
3108 }
3109 assert_eq!(is_utf8_bidi(&buf[..]), expect);
3110 }
3111 }
3112
3113 #[test]
3114 #[cfg_attr(miri, ignore)] fn test_is_utf16_bidi_thoroughly() {
3116 let mut buf = [0; 32];
3117 for i in 0..0x10000u32 {
3118 let u = i as u16;
3119 buf[15] = u;
3120 assert_eq!(
3121 is_utf16_bidi(&buf[..]),
3122 reference_is_utf16_code_unit_bidi(u)
3123 );
3124 }
3125 }
3126
3127 #[test]
3128 fn test_is_utf8_bidi_edge_cases() {
3129 assert!(!is_utf8_bidi(b"\xD5\xBF\x61"));
3130 assert!(!is_utf8_bidi(b"\xD6\x80\x61"));
3131 assert!(!is_utf8_bidi(b"abc"));
3132 assert!(is_utf8_bidi(b"\xD5\xBF\xC2"));
3133 assert!(is_utf8_bidi(b"\xD6\x80\xC2"));
3134 assert!(is_utf8_bidi(b"ab\xC2"));
3135 }
3136
3137 #[test]
3138 fn test_decode_latin1() {
3139 match decode_latin1(b"ab") {
3140 Cow::Borrowed(s) => {
3141 assert_eq!(s, "ab");
3142 }
3143 Cow::Owned(_) => {
3144 unreachable!("Should have borrowed");
3145 }
3146 }
3147 assert_eq!(decode_latin1(b"a\xE4"), "a\u{E4}");
3148 }
3149
3150 #[test]
3151 fn test_encode_latin1_lossy() {
3152 match encode_latin1_lossy("ab") {
3153 Cow::Borrowed(s) => {
3154 assert_eq!(s, b"ab");
3155 }
3156 Cow::Owned(_) => {
3157 unreachable!("Should have borrowed");
3158 }
3159 }
3160 assert_eq!(encode_latin1_lossy("a\u{E4}"), &(b"a\xE4")[..]);
3161 }
3162
3163 #[test]
3164 fn test_convert_utf8_to_utf16_without_replacement() {
3165 let mut buf = [0u16; 5];
3166 assert_eq!(
3167 convert_utf8_to_utf16_without_replacement(b"ab", &mut buf[..2]),
3168 Some(2)
3169 );
3170 assert_eq!(buf[0], u16::from(b'a'));
3171 assert_eq!(buf[1], u16::from(b'b'));
3172 assert_eq!(buf[2], 0);
3173 assert_eq!(
3174 convert_utf8_to_utf16_without_replacement(b"\xC3\xA4c", &mut buf[..3]),
3175 Some(2)
3176 );
3177 assert_eq!(buf[0], 0xE4);
3178 assert_eq!(buf[1], u16::from(b'c'));
3179 assert_eq!(buf[2], 0);
3180 assert_eq!(
3181 convert_utf8_to_utf16_without_replacement(b"\xE2\x98\x83", &mut buf[..3]),
3182 Some(1)
3183 );
3184 assert_eq!(buf[0], 0x2603);
3185 assert_eq!(buf[1], u16::from(b'c'));
3186 assert_eq!(buf[2], 0);
3187 assert_eq!(
3188 convert_utf8_to_utf16_without_replacement(b"\xE2\x98\x83d", &mut buf[..4]),
3189 Some(2)
3190 );
3191 assert_eq!(buf[0], 0x2603);
3192 assert_eq!(buf[1], u16::from(b'd'));
3193 assert_eq!(buf[2], 0);
3194 assert_eq!(
3195 convert_utf8_to_utf16_without_replacement(b"\xE2\x98\x83\xC3\xA4", &mut buf[..5]),
3196 Some(2)
3197 );
3198 assert_eq!(buf[0], 0x2603);
3199 assert_eq!(buf[1], 0xE4);
3200 assert_eq!(buf[2], 0);
3201 assert_eq!(
3202 convert_utf8_to_utf16_without_replacement(b"\xF0\x9F\x93\x8E", &mut buf[..4]),
3203 Some(2)
3204 );
3205 assert_eq!(buf[0], 0xD83D);
3206 assert_eq!(buf[1], 0xDCCE);
3207 assert_eq!(buf[2], 0);
3208 assert_eq!(
3209 convert_utf8_to_utf16_without_replacement(b"\xF0\x9F\x93\x8Ee", &mut buf[..5]),
3210 Some(3)
3211 );
3212 assert_eq!(buf[0], 0xD83D);
3213 assert_eq!(buf[1], 0xDCCE);
3214 assert_eq!(buf[2], u16::from(b'e'));
3215 assert_eq!(
3216 convert_utf8_to_utf16_without_replacement(b"\xF0\x9F\x93", &mut buf[..5]),
3217 None
3218 );
3219 }
3220}