1use crate::pointer::{
3 self, get_byte_at_index, get_byte_slice_of, is_valid_utf8_str_of,
4};
5use crate::{ByteType, Error, Result};
6
7#[inline]
29pub fn get_rune_cutoff_at_index<'g>(
30 ptr: *const u8,
31 length: usize,
32 index: usize,
33) -> Result<usize> {
34 let ptr = pointer::copy(ptr, length)?;
35
36 if index > length {
37 return Err(Error::InvalidIndex(index, get_byte_slice_of(ptr, 0, length)));
38 }
39 if length == 0 {
40 return Ok(index + length);
41 }
42 let index = index;
43 let cutoff = index + 1;
44 let byte = get_byte_at_index(ptr, index);
45 let ty = ByteType::from(byte);
46 let max = if ty.is_ascii() {
47 return Ok(cutoff);
48 } else if ty.is_continuation() {
49 return Err(unexpected_continuation_byte_at_index_error(ptr, length, index));
50 } else {
51 ty.len()
52 };
53 let mut cutoff = index + max;
54 let mut max = index + max;
55 let charmax = index + 6; if cutoff <= max && max < length {
57 while max < charmax && cutoff <= max && max < length {
58 let next_byte = get_byte_at_index(ptr, max);
59 let next_ty = ByteType::from(next_byte);
60 let tcutoff = cutoff + next_ty.len();
61 if let Some((count, cty)) = continuation_bytes_location(ptr, length, cutoff)
62 {
63 let tcutoff = cutoff + count;
64 if is_valid_utf8_str_of(ptr, index, tcutoff - index) {
65 cutoff = tcutoff;
66 break;
67 } else {
68 max += cty.len();
69 }
70 } else if next_ty.has_rune_delta() {
71 if next_ty.len() < 4 {
72 if let Some((_count_, _cty_)) =
73 continuation_bytes_location(ptr, length, cutoff - index)
74 {
75 cutoff += next_ty.len();
76 }
77 break;
78 } else if let Some((count, cty)) =
79 continuation_bytes_location(ptr, length, tcutoff)
80 {
81 let tcutoff = cutoff + count + cty.len();
82 cutoff = tcutoff;
83 break;
84 } else {
85 let delta = tcutoff - cutoff;
86 match delta {
87 4 => {
88 let mut next_chunk = [0u8; 4];
89 let next_bytes = get_byte_slice_of(
90 ptr,
91 index + delta,
92 cutoff - index + delta,
93 );
94 next_chunk.copy_from_slice(&next_bytes[0..4]);
95 match next_chunk {
96 [0xF0, 0x9F, 0x8F, 0xBB]
97 | [0xF0, 0x9F, 0x8F, 0xBC]
98 | [0xF0, 0x9F, 0x8F, 0xBD]
99 | [0xF0, 0x9F, 0x8F, 0xBE]
100 | [0xF0, 0x9F, 0x8F, 0xBF] => {
101 cutoff += delta;
102 break;
103 },
104 _ => {},
105 }
106 },
107 _ => {},
108 }
109
110 break;
111 }
112 } else if next_ty.is_ascii() {
113 break;
114 } else {
115 }
116 cutoff += 1;
117 }
118 }
119 return Ok(cutoff);
120}
121#[inline]
134pub fn split_at_first_rune<'g>(ptr: *const u8, length: usize) -> usize {
135 get_rune_cutoff_at_index(ptr, length, 0).expect("should not fail at index 0")
136}
137
138#[inline]
174pub fn continuation_bytes_location<'g>(
175 ptr: *const u8,
176 length: usize,
177 index: usize,
178) -> Option<(usize, ByteType)> {
179 let shift: usize = (0xE2u8.leading_ones() & 0xEFu8.leading_ones()) as usize;
180 if index + (shift - 1) < length {
181 let zwj0 = get_byte_at_index(ptr, index);
182 let zwj1 = get_byte_at_index(ptr, index + 1);
183 let zwj2 = get_byte_at_index(ptr, index + 2);
184 let next_rune_byte = get_byte_at_index(ptr, index + shift);
185 let ty = if index + shift < length {
186 ByteType::from(next_rune_byte)
187 } else {
188 ByteType::None
189 };
190 let tuple = (zwj0, zwj1, zwj2);
191 match tuple {
192 (0xE2, 0x80, 0x8D) => {
193 let count = shift + ty.len();
194 Some((count, ty))
195 },
196 (0xEF, 0xB8, 0x8F) => {
197 let mut count = 0xEFu8.leading_ones() as usize;
198 if let Some((next_count, _ty_)) =
199 continuation_bytes_location(ptr, length, index + shift)
200 {
201 count += next_count
202 }
203
204 Some((count, ty))
205 },
206 _ => None,
207 }
208 } else {
209 None
210 }
211}
212
213#[inline]
214pub(crate) fn previous_valid_cutoff<'e>(
215 ptr: *const u8,
216 length: usize,
217 index: usize,
218) -> Option<usize> {
219 let ptr = pointer::copy(ptr, length).unwrap();
220 if index == 0 && index == length {
221 return None;
222 }
223 let mut previous_index = index;
224 let mut byte = get_byte_at_index(ptr, previous_index);
225 #[allow(unused_assignments)]
226 let mut ty = ByteType::from(byte);
227
228 while previous_index > 0 {
229 ty = ByteType::from(byte);
230 if !ty.has_rune_delta() {
231 previous_index -= 1;
232 byte = get_byte_at_index(ptr, previous_index);
233 } else {
234 break;
235 }
236 }
237 if previous_index == length {
238 None
239 } else {
240 byte = get_byte_at_index(ptr, previous_index);
241 if let Some((count, cty)) =
242 continuation_bytes_location(ptr, length, previous_index)
243 {
244 if previous_index >= cty.len() {
245 if is_valid_utf8_str_of(ptr, previous_index - cty.len(), count) {
246 previous_index -= cty.len();
247 Some(previous_index)
248 } else {
249 previous_index -= 1;
250 previous_valid_cutoff(ptr, length, previous_index)
251 }
252 } else {
253 if previous_index > 0 && previous_index <= cty.len() {
254 previous_index -= 1;
255 return previous_valid_cutoff(ptr, length, previous_index);
256 }
257
258 Some(previous_index)
259 }
260 } else if ByteType::from(byte).has_rune_delta() {
261 let cty = ByteType::from(byte);
262 if is_valid_utf8_str_of(ptr, previous_index, length - previous_index) {
263 return Some(previous_index);
264 } else if previous_index >= cty.len() {
265 previous_index -= 1;
266 return previous_valid_cutoff(ptr, length, previous_index);
267 } else {
268 Some(previous_index)
269 }
270 } else if previous_index == 0 {
271 None
272 } else {
273 Some(previous_index)
274 }
275 }
276}
277
278#[inline]
279pub(crate) fn next_valid_cutoff<'e>(
280 ptr: *const u8,
281 length: usize,
282 index: usize,
283) -> Option<usize> {
284 if length == 0 {
285 return None;
286 }
287 if index >= length {
288 return None;
289 }
290 let ptr = pointer::copy(ptr, length).unwrap();
291 let mut next_index = index;
292
293 while next_index < length {
294 if let Some((count, _ty_)) =
295 continuation_bytes_location(ptr, length, next_index)
296 {
297 next_index += count;
298 break;
299 } else if let Some((count, _ty_)) =
300 continuation_bytes_location(ptr, length, next_index + 1)
301 {
302 next_index += count + 1;
303 break;
304 } else {
305 let byte = get_byte_at_index(ptr, next_index);
306 let ty = ByteType::from(byte);
307 if ty.has_rune_delta() {
308 break;
309 } else if ty.is_continuation() {
310 next_index += 1;
311 } else {
312 break;
313 }
314 }
315 }
316 if next_index == length {
317 None
318 } else {
319 Some(next_index)
320 }
321}
322
323pub(crate) fn unexpected_continuation_byte_at_index_error<'e>(
324 ptr: *const u8,
325 length: usize,
326 index: usize,
327) -> Error<'e> {
328 let byte = get_byte_at_index(ptr, index);
329 let previous_index = previous_valid_cutoff(ptr, length, index);
330 let next_index = next_valid_cutoff(ptr, length, index);
331 let slice = get_byte_slice_of(ptr, index, length);
332 Error::UnexpectedContinuationByte(byte, index, previous_index, next_index, slice)
333}
334
335#[cfg(test)]
336mod test_split_at_first_rune {
337 use crate::pointer::{self};
338 use crate::{split_at_first_rune, Result};
339
340 #[test]
341 fn test_split_at_first_rune_4_bytes() -> Result<()> {
342 let (ptr, length) = pointer::from_slice("πsmiley".as_bytes())?;
344 let cutoff = split_at_first_rune(ptr, length);
345 assert_eq!(cutoff, 4);
346 assert_eq!(length, 10);
347
348 Ok(())
349 }
350
351 #[test]
352 fn test_split_at_first_rune_6_bytes() -> Result<()> {
353 let (ptr, length) = pointer::from_slice("β οΈskull".as_bytes())?;
355 let cutoff = split_at_first_rune(ptr, length);
356 assert_eq!(length, 11);
357 assert_eq!(cutoff, 6);
358
359 Ok(())
360 }
361
362 #[test]
363 fn test_split_at_first_ascii() -> Result<()> {
364 let (ptr, length) = pointer::from_slice("abcdefghijklmnopqrstu".as_bytes())?;
365 let cutoff = split_at_first_rune(ptr, length);
366 assert_eq!(cutoff, 1);
367 assert_eq!(length, 21);
368
369 Ok(())
370 }
371
372 #[test]
373 fn test_split_at_first_nonascii_single_byte_character() -> Result<()> {
374 let (ptr, length) = pointer::from_slice("Γ£o".as_bytes())?;
375 let cutoff = split_at_first_rune(ptr, length);
376 assert_eq!(cutoff, 2);
377 assert_eq!(length, 3);
378
379 Ok(())
380 }
381
382 #[test]
383 fn test_split_at_first_rune_single_heart() -> Result<()> {
384 let (ptr, length) = pointer::from_slice("β€οΈ".as_bytes())?;
385 let cutoff = split_at_first_rune(ptr, length);
386 assert_eq!(cutoff, 6);
387 assert_eq!(length, 6);
388 Ok(())
389 }
390
391 #[test]
392 fn test_split_at_first_rune_two_to_vec() -> Result<()> {
393 let (ptr, length) = pointer::from_slice("β€οΈπ¦
".as_bytes())?;
394 let cutoff = split_at_first_rune(ptr, length);
395 assert_eq!(cutoff, 6);
396 assert_eq!(length, 10);
397 Ok(())
398 }
399}
400
401#[cfg(test)]
402mod test_get_rune_cutoff_at_index {
403 use crate::pointer::{self};
404 use crate::{assert_get_rune_cutoff_at_index, get_rune_cutoff_at_index, Result};
405 #[test]
406 fn test_get_rune_cutoff_at_first_index_single_rune() -> Result<()> {
407 let (ptr, length) = pointer::from_slice("β€οΈ".as_bytes())?;
408 assert_get_rune_cutoff_at_index!(ptr, length, 6, 0, 6, "β€οΈ");
409 Ok(())
410 }
411
412 #[test]
413 fn test_get_rune_cutoff_empty() -> Result<()> {
414 let (ptr, length) = pointer::from_slice("".as_bytes())?;
415 assert_get_rune_cutoff_at_index!(ptr, length, 0, 0, 0, "");
416 Ok(())
417 }
418
419 #[test]
420 fn test_get_rune_cutoff_at_various_indexes_4_bytes() -> Result<()> {
421 let (ptr, length) = pointer::from_slice("smileyπsmiley".as_bytes())?;
423 assert_get_rune_cutoff_at_index!(ptr, length, 16, 6, 10, "π");
424
425 Ok(())
426 }
427
428 #[test]
429 fn test_get_rune_cutoff_at_various_indexes_6_bytes() -> Result<()> {
430 let (ptr, length) = pointer::from_slice("skullβ οΈskull".as_bytes())?;
432 assert_get_rune_cutoff_at_index!(ptr, length, 16, 5, 11, "β οΈ");
433
434 Ok(())
435 }
436
437 #[test]
438 fn test_get_rune_cutoff_at_various_indexes_ascii() -> Result<()> {
439 let (ptr, length) = pointer::from_slice("abcdefghijklmnopqrstu".as_bytes())?;
440 assert_get_rune_cutoff_at_index!(ptr, length, 21, 7, 8, "h");
441
442 Ok(())
443 }
444
445 #[test]
446 fn test_get_rune_cutoff_at_various_indexes_non_ascii() -> Result<()> {
447 let (ptr, length) = pointer::from_slice("falcΓ£oπ¦
".as_bytes())?;
451 assert_get_rune_cutoff_at_index!(ptr, length, 11, 4, 6, "Γ£");
452 assert_get_rune_cutoff_at_index!(ptr, length, 11, 6, 7, "o");
453 assert_get_rune_cutoff_at_index!(ptr, length, 11, 7, 11, "π¦
");
454 Ok(())
455 }
456
457 #[test]
458 fn test_get_rune_cutoff_at_first_index() -> Result<()> {
459 let (ptr, length) = pointer::from_slice("β€οΈπ¦
".as_bytes())?;
460 assert_get_rune_cutoff_at_index!(ptr, length, 10, 0, 6, "β€οΈ");
461 assert_get_rune_cutoff_at_index!(ptr, length, 10, 6, 10, "π¦
");
462 Ok(())
463 }
464
465 #[test]
466 fn test_get_rune_cutoff_unexpected_continuation_byte() -> Result<()> {
467 let (ptr, _) = pointer::from_slice("β€οΈπ¦
".as_bytes())?;
468 let cutoff = get_rune_cutoff_at_index(ptr, 10, 4);
469
470 assert!(cutoff.is_err());
471 let err = cutoff.err().unwrap();
472 assert_eq!(err.previous_valid_cutoff(), Some(0));
473 assert_eq!(err.next_valid_cutoff(), Some(6));
474 Ok(())
475 }
476
477 #[test]
478 fn test_get_rune_cutoff_at_various_indexes_94_bytes() -> Result<()> {
479 let (ptr, length) = pointer::from_slice("π©π»βπππΏπ§π½βππ¨βππΆοΈπΉππ₯β€οΈβπ₯β€οΈβπ©Ή".as_bytes())?;
494 assert_get_rune_cutoff_at_index!(ptr, length, 94, 0, 15, "π©π»βπ");
495 assert_get_rune_cutoff_at_index!(ptr, length, 94, 15, 23, "ππΏ");
496 assert_get_rune_cutoff_at_index!(ptr, length, 94, 23, 38, "π§π½βπ");
497 assert_get_rune_cutoff_at_index!(ptr, length, 94, 38, 49, "π¨βπ");
498 assert_get_rune_cutoff_at_index!(ptr, length, 94, 49, 56, "πΆοΈ");
499 assert_get_rune_cutoff_at_index!(ptr, length, 94, 56, 60, "πΉ");
500 assert_get_rune_cutoff_at_index!(ptr, length, 94, 60, 64, "π");
501 assert_get_rune_cutoff_at_index!(ptr, length, 94, 64, 68, "π₯");
502 assert_get_rune_cutoff_at_index!(ptr, length, 94, 68, 81, "β€οΈβπ₯");
503 assert_get_rune_cutoff_at_index!(ptr, length, 94, 81, 94, "β€οΈβπ©Ή");
504
505 Ok(())
506 }
507 #[macro_export]
508 macro_rules! assert_get_rune_cutoff_at_index {
509 (
510 $ptr:expr,
511 $length:expr,
512 $expected_length:literal,
513 $index:literal,
514 $cutoff:literal,
515 $expected:literal
516 $(,)?
517 ) => {{
518 use debug_et_diagnostics::{ansi, fore, from_bytes, indent};
519 use crate::{get_byte_slice_of, format_bytes, RuneParts};
520
521 let slice = get_byte_slice_of($ptr, 0, $length)
524 .iter()
525 .map(Clone::clone)
526 .map(|c| fore(c.to_string(), from_bytes(&[c]).into()))
527 .collect::<Vec<String>>()
528 .join(", ");
529 let cutoff = get_rune_cutoff_at_index($ptr, $length, $index)?;
530 let count = $cutoff - $index;
531 assert_eq!(
532 $length,
533 $expected_length,
534 "{}",
535 [
536 fore("expected length to be", 231),
537 fore(format!("{}", $expected_length), 196),
538 ]
539 .join(" ")
540 );
541 assert_eq!(
542 cutoff,
543 $cutoff,
544 "{}",
545 [
546 fore("expected cutoff", 231),
547 fore(format!("{}", cutoff), 220),
548 fore("to be", 231),
549 fore(format!("{}", $cutoff), 196),
550 fore("so as to match rune:", 231),
551 ansi(format!("{}", $expected), 16, 231),
552 format_expected_rune($expected),
553 fore("instead of:", 231),
554 ansi(format!("{}", {
555 let slice = get_byte_slice_of($ptr, $index, cutoff);
556 let string = std::str::from_utf8(slice)
557 .map(|c| ansi(format!("{c}"), 16, 231))
558 .unwrap_or_else(|e| {
559 let slice = get_byte_slice_of($ptr, $index, e.valid_up_to());
560 std::str::from_utf8(slice).map(String::from).unwrap_or_default()
561 });
562 string
563 }), 16, 231),
564 {
565 format!(
566 "\n{}\n",
567 [
568 String::new(),
569 fore(".i.e.:", 231),
570 fore(
571 indent!(format!(
572 "get_byte_slice_of(ptr, {}, {})",
573 $index, $cutoff
574 )),
575 231,
576 ),
577 fore("is:", 231),
578 format_bytes(get_byte_slice_of($ptr, $index, count), None),
579 ]
580 .iter()
581 .map(|c| format!(" {c}"))
582 .collect::<Vec<String>>()
583 .join("\n")
584 )
585 }
586 ]
587 .join(" ")
588 );
589
590 let index = $index;
591 let length = $length - index;
592 let actual = match RuneParts::from_raw_parts($ptr, $length)
593 .rune_at_index($index) {
594 Ok(actual) => actual.as_str().to_string(),
595 Err(error) => {
596 panic!("{}:{} RuneParts::from_raw_parts({:#?}, {})\n{error}", file!(), line!(), $ptr, $length);
597 }
598 };
599
600 let expected = $expected.to_string();
601 assert_eq!(
602 actual,
603 expected.to_string(),
604 "{}",
605 ansi(
606 [
607 String::new(),
608 [
609 fore("expected", 82),
610 fore("rune as string", 231),
611 fore(format!("{expected}"), 82),
612 ]
613 .join(" "),
614 [
615 fore("actual", 196),
616 fore("rune as string", 231),
617 fore(format!("{actual}"), 196),
618 ]
619 .join(" "),
620 [
621 fore("from slice ", 220),
622 fore("[", 231),
623 format!("{slice}"),
624 fore("]", 231),
625 [
626 String::new(),
627 fore(format!("index={index}"), 82),
628 fore(format!("cutoff={cutoff}"), 202),
629 fore(format!("length={length}"), 74),
630 ]
631 .join(" "),
632 ]
633 .join(""),
634 fore(format!("expected cutoff={}", $cutoff), 196),
635 ]
636 .join("\n"),
637 231,
638 16
639 ),
640 );
641 }};
642}
643
644 fn format_expected_rune(c: &str) -> String {
645 use debug_et_diagnostics::color::byte_hex;
646 format!(
647 "\"{c}\" => [{}]",
648 c.as_bytes()
649 .iter()
650 .map(Clone::clone)
651 .map(byte_hex)
652 .collect::<Vec<String>>()
653 .join(", "),
654 )
655 }
656}
657
658#[cfg(test)]
659mod test_continuation_bytes_location {
660 use crate::pointer::{self};
661 use crate::{continuation_bytes_location, Result};
662 #[test]
663 fn test_continuation_byte_0x200d() -> Result<()> {
664 let (ptr, length) = pointer::from_display("π©π»βπ")?;
665
666 assert_eq!(
667 "π©π»βπ".as_bytes().to_vec(),
668 vec![
669 0xF0, 0x9F, 0x91, 0xA9, 0xF0, 0x9F, 0x8F, 0xBB, 0xE2, 0x80, 0x8D, 0xF0,
670 0x9F, 0x9A, 0x92
671 ]
672 );
673 let location = continuation_bytes_location(ptr, length, 8);
674
675 assert_eq!(location.is_some(), true);
676 let (count, ty) = location.unwrap();
677 assert_eq!(ty.len(), 4);
678 assert_eq!(ty.byte(), 0xF0);
679 assert_eq!(count, 7);
680
681 Ok(())
682 }
683 #[test]
684 fn test_continuation_byte_0xfe0f() -> Result<()> {
685 let (ptr, length) = pointer::from_display("β€οΈβπ₯")?;
686 assert_eq!(
687 "β€οΈβπ₯".as_bytes().to_vec(),
688 vec![
689 0xE2, 0x9D, 0xA4, 0xEF, 0xB8, 0x8F, 0xE2, 0x80, 0x8D, 0xF0, 0x9F, 0x94,
690 0xA5
691 ]
692 );
693 let location = continuation_bytes_location(ptr, length, 3);
694
695 assert_eq!(location.is_some(), true);
696 let (count, ty) = location.unwrap();
697 assert_eq!(ty.len(), 3);
698 assert_eq!(ty.byte(), 0xE2);
699 assert_eq!(count, 10);
700
701 Ok(())
702 }
703}
704
705#[cfg(test)]
706mod test_next_valid_cutoff {
707
708 use crate::heuristic::next_valid_cutoff;
709 use crate::pointer::{self};
710 use crate::{
711 assert_none_next_valid_cutoff, assert_some_next_valid_cutoff, Result, RuneParts,
712 };
713 #[test]
714 fn test_next_valid_cutoff_parts() -> Result<()> {
715 let (ptr, length) = pointer::from_slice("πππ»ππΌππ½ππΎππΏ".as_bytes())?;
716 assert_some_next_valid_cutoff!(ptr, length, 44, 0, 0, "π");
717 assert_some_next_valid_cutoff!(ptr, length, 44, 1, 4, "ππ»");
718 assert_some_next_valid_cutoff!(ptr, length, 44, 2, 4, "ππ»");
719 assert_some_next_valid_cutoff!(ptr, length, 44, 3, 4, "ππ»");
720 assert_some_next_valid_cutoff!(ptr, length, 44, 4, 4, "ππ»");
721
722 assert_some_next_valid_cutoff!(ptr, length, 44, 5, 8, "π»");
723 assert_some_next_valid_cutoff!(ptr, length, 44, 6, 8, "π»");
724 assert_some_next_valid_cutoff!(ptr, length, 44, 7, 8, "π»");
725 assert_some_next_valid_cutoff!(ptr, length, 44, 8, 8, "π»");
726 assert_some_next_valid_cutoff!(ptr, length, 44, 9, 12, "ππΌ");
727 assert_some_next_valid_cutoff!(ptr, length, 44, 10, 12, "ππΌ");
728 assert_some_next_valid_cutoff!(ptr, length, 44, 11, 12, "ππΌ");
729 assert_some_next_valid_cutoff!(ptr, length, 44, 12, 12, "ππΌ");
730
731 assert_some_next_valid_cutoff!(ptr, length, 44, 13, 16, "πΌ");
732 assert_some_next_valid_cutoff!(ptr, length, 44, 14, 16, "πΌ");
733 assert_some_next_valid_cutoff!(ptr, length, 44, 15, 16, "πΌ");
734 assert_some_next_valid_cutoff!(ptr, length, 44, 16, 16, "πΌ");
735 assert_some_next_valid_cutoff!(ptr, length, 44, 17, 20, "ππ½");
736 assert_some_next_valid_cutoff!(ptr, length, 44, 18, 20, "ππ½");
737 assert_some_next_valid_cutoff!(ptr, length, 44, 19, 20, "ππ½");
738 assert_some_next_valid_cutoff!(ptr, length, 44, 20, 20, "ππ½");
739
740 assert_some_next_valid_cutoff!(ptr, length, 44, 21, 24, "π½");
741 assert_some_next_valid_cutoff!(ptr, length, 44, 22, 24, "π½");
742 assert_some_next_valid_cutoff!(ptr, length, 44, 23, 24, "π½");
743 assert_some_next_valid_cutoff!(ptr, length, 44, 24, 24, "π½");
744 assert_some_next_valid_cutoff!(ptr, length, 44, 25, 28, "ππΎ");
745 assert_some_next_valid_cutoff!(ptr, length, 44, 26, 28, "ππΎ");
746 assert_some_next_valid_cutoff!(ptr, length, 44, 27, 28, "ππΎ");
747 assert_some_next_valid_cutoff!(ptr, length, 44, 28, 28, "ππΎ");
748
749 assert_some_next_valid_cutoff!(ptr, length, 44, 29, 32, "πΎ");
750 assert_some_next_valid_cutoff!(ptr, length, 44, 30, 32, "πΎ");
751 assert_some_next_valid_cutoff!(ptr, length, 44, 31, 32, "πΎ");
752 assert_some_next_valid_cutoff!(ptr, length, 44, 32, 32, "πΎ");
753 assert_some_next_valid_cutoff!(ptr, length, 44, 33, 36, "ππΏ");
754 assert_some_next_valid_cutoff!(ptr, length, 44, 34, 36, "ππΏ");
755 assert_some_next_valid_cutoff!(ptr, length, 44, 35, 36, "ππΏ");
756 assert_some_next_valid_cutoff!(ptr, length, 44, 36, 36, "ππΏ");
757
758 assert_some_next_valid_cutoff!(ptr, length, 44, 37, 40, "πΏ");
759 assert_some_next_valid_cutoff!(ptr, length, 44, 38, 40, "πΏ");
760 assert_some_next_valid_cutoff!(ptr, length, 44, 39, 40, "πΏ");
761 assert_some_next_valid_cutoff!(ptr, length, 44, 40, 40, "πΏ");
762 assert_none_next_valid_cutoff!(ptr, length, 44, 41);
763 assert_none_next_valid_cutoff!(ptr, length, 44, 42);
764 assert_none_next_valid_cutoff!(ptr, length, 44, 43);
765 assert_none_next_valid_cutoff!(ptr, length, 44, 44);
766 assert_none_next_valid_cutoff!(ptr, length, 44, 45);
767 Ok(())
768 }
769
770 #[test]
771 fn test_next_valid_cutoff_at_first_index_single_rune() -> Result<()> {
772 let (ptr, length) = pointer::from_slice("β€οΈ".as_bytes())?;
773 assert_some_next_valid_cutoff!(ptr, length, 6, 0, 0, "β€οΈ");
774 Ok(())
775 }
776
777 #[test]
778 fn test_next_valid_cutoff_empty() -> Result<()> {
779 let (ptr, length) = pointer::from_slice("".as_bytes())?;
780 assert_none_next_valid_cutoff!(ptr, length, 0, 0);
781
782 Ok(())
783 }
784
785 #[test]
786 fn test_next_valid_cutoff_at_various_indexes_6_bytes() -> Result<()> {
787 let (ptr, length) = pointer::from_slice("skullβ οΈskull".as_bytes())?;
788 assert_some_next_valid_cutoff!(ptr, length, 16, 0, 0, "s");
789 assert_some_next_valid_cutoff!(ptr, length, 16, 4, 4, "l");
790 assert_some_next_valid_cutoff!(ptr, length, 16, 5, 5, "β οΈ");
791 Ok(())
792 }
793
794 #[test]
795 fn test_next_valid_cutoff_at_various_indexes_4_bytes() -> Result<()> {
796 let (ptr, length) = pointer::from_slice("smileyπsmiley".as_bytes())?;
797 assert_some_next_valid_cutoff!(ptr, length, 16, 5, 5, "y");
798 assert_some_next_valid_cutoff!(ptr, length, 16, 6, 6, "π");
799 Ok(())
800 }
801
802 #[test]
803 fn test_next_valid_cutoff_at_various_indexes_ascii() -> Result<()> {
804 let (ptr, length) = pointer::from_slice("abcdefghijklmnopqrstu".as_bytes())?;
805 assert_some_next_valid_cutoff!(ptr, length, 21, 7, 7, "h");
806
807 Ok(())
808 }
809
810 #[test]
811 fn test_next_valid_cutoff_at_various_indexes_non_ascii() -> Result<()> {
812 let (ptr, length) = pointer::from_slice("falcΓ£oπ¦
".as_bytes())?;
813 assert_some_next_valid_cutoff!(ptr, length, 11, 4, 4, "Γ£");
814 assert_some_next_valid_cutoff!(ptr, length, 11, 5, 6, "o");
815 assert_some_next_valid_cutoff!(ptr, length, 11, 6, 6, "o");
816 assert_some_next_valid_cutoff!(ptr, length, 11, 7, 7, "π¦
");
817 assert_none_next_valid_cutoff!(ptr, length, 11, 8);
818 Ok(())
819 }
820
821 #[test]
822 fn test_next_valid_cutoff_at_first_index() -> Result<()> {
823 let (ptr, length) = pointer::from_slice("β€οΈπ¦
".as_bytes())?;
824 assert_some_next_valid_cutoff!(ptr, length, 10, 0, 0, "β€οΈ");
825 assert_some_next_valid_cutoff!(ptr, length, 10, 1, 6, "π¦
");
826 assert_some_next_valid_cutoff!(ptr, length, 10, 2, 6, "π¦
");
827 assert_some_next_valid_cutoff!(ptr, length, 10, 3, 6, "π¦
");
828 assert_some_next_valid_cutoff!(ptr, length, 10, 4, 6, "π¦
");
829 assert_some_next_valid_cutoff!(ptr, length, 10, 5, 6, "π¦
");
830 assert_some_next_valid_cutoff!(ptr, length, 10, 6, 6, "π¦
");
831 assert_none_next_valid_cutoff!(ptr, length, 10, 7);
832
833 Ok(())
834 }
835
836 #[test]
837 fn test_next_valid_cutoff_at_various_indexes_94_bytes() -> Result<()> {
838 let (ptr, length) = pointer::from_slice("π©π»βπππΏπ§π½βππ¨βππΆοΈπΉππ₯β€οΈβπ₯β€οΈβπ©Ή".as_bytes())?;
839 assert_some_next_valid_cutoff!(ptr, length, 94, 0, 0, "π©π»βπ");
840 assert_some_next_valid_cutoff!(ptr, length, 94, 1, 4, "π»\u{200d}π");
841 assert_some_next_valid_cutoff!(ptr, length, 94, 2, 4, "π»\u{200d}π");
842 assert_some_next_valid_cutoff!(ptr, length, 94, 3, 4, "π»\u{200d}π");
843 assert_some_next_valid_cutoff!(ptr, length, 94, 4, 4, "π»\u{200d}π");
844 assert_some_next_valid_cutoff!(ptr, length, 94, 5, 15, "ππΏ");
845 assert_some_next_valid_cutoff!(ptr, length, 94, 15, 15, "ππΏ");
846 assert_some_next_valid_cutoff!(ptr, length, 94, 16, 19, "πΏ");
847 assert_some_next_valid_cutoff!(ptr, length, 94, 17, 19, "πΏ");
848 assert_some_next_valid_cutoff!(ptr, length, 94, 18, 19, "πΏ");
849 assert_some_next_valid_cutoff!(ptr, length, 94, 19, 19, "πΏ");
850 assert_some_next_valid_cutoff!(ptr, length, 94, 20, 23, "π§π½βπ");
851 assert_some_next_valid_cutoff!(ptr, length, 94, 21, 23, "π§π½βπ");
852 assert_some_next_valid_cutoff!(ptr, length, 94, 22, 23, "π§π½βπ");
853 assert_some_next_valid_cutoff!(ptr, length, 94, 23, 23, "π§π½βπ");
854
855 assert_some_next_valid_cutoff!(ptr, length, 94, 24, 27, "π½\u{200d}π");
856 assert_some_next_valid_cutoff!(ptr, length, 94, 25, 27, "π½\u{200d}π");
857 assert_some_next_valid_cutoff!(ptr, length, 94, 26, 27, "π½\u{200d}π");
858 assert_some_next_valid_cutoff!(ptr, length, 94, 27, 27, "π½\u{200d}π");
859 assert_some_next_valid_cutoff!(ptr, length, 94, 28, 38, "π¨\u{200d}π");
860 assert_some_next_valid_cutoff!(ptr, length, 94, 29, 38, "π¨\u{200d}π");
861 assert_some_next_valid_cutoff!(ptr, length, 94, 30, 38, "π¨\u{200d}π");
862 assert_some_next_valid_cutoff!(ptr, length, 94, 31, 38, "π¨\u{200d}π");
863 assert_some_next_valid_cutoff!(ptr, length, 94, 32, 34, "ππ¨\u{200d}π");
864 assert_some_next_valid_cutoff!(ptr, length, 94, 33, 34, "ππ¨\u{200d}π");
865 assert_some_next_valid_cutoff!(ptr, length, 94, 34, 34, "ππ¨\u{200d}π");
866 assert_some_next_valid_cutoff!(ptr, length, 94, 35, 38, "π¨\u{200d}π");
867 assert_some_next_valid_cutoff!(ptr, length, 94, 36, 38, "π¨\u{200d}π");
868 assert_some_next_valid_cutoff!(ptr, length, 94, 37, 38, "π¨\u{200d}π");
869 assert_some_next_valid_cutoff!(ptr, length, 94, 38, 38, "π¨βπ");
870 assert_some_next_valid_cutoff!(ptr, length, 94, 39, 49, "πΆοΈ");
871 assert_some_next_valid_cutoff!(ptr, length, 94, 40, 49, "πΆοΈ");
872 assert_some_next_valid_cutoff!(ptr, length, 94, 41, 49, "πΆοΈ");
873 assert_some_next_valid_cutoff!(ptr, length, 94, 42, 49, "πΆοΈ");
874 assert_some_next_valid_cutoff!(ptr, length, 94, 43, 45, "ππΆοΈ");
875 assert_some_next_valid_cutoff!(ptr, length, 94, 44, 45, "ππΆοΈ");
876 assert_some_next_valid_cutoff!(ptr, length, 94, 45, 45, "ππΆοΈ");
877 assert_some_next_valid_cutoff!(ptr, length, 94, 46, 49, "πΆοΈ");
878 assert_some_next_valid_cutoff!(ptr, length, 94, 47, 49, "πΆοΈ");
879 assert_some_next_valid_cutoff!(ptr, length, 94, 48, 49, "πΆοΈ");
880 assert_some_next_valid_cutoff!(ptr, length, 94, 49, 49, "πΆοΈ");
881 assert_some_next_valid_cutoff!(ptr, length, 94, 49, 49, "πΆοΈ");
882 assert_some_next_valid_cutoff!(ptr, length, 94, 50, 56, "πΉ");
883 assert_some_next_valid_cutoff!(ptr, length, 94, 51, 56, "πΉ");
884 assert_some_next_valid_cutoff!(ptr, length, 94, 52, 56, "πΉ");
885 assert_some_next_valid_cutoff!(ptr, length, 94, 53, 56, "πΉ");
886 assert_some_next_valid_cutoff!(ptr, length, 94, 54, 56, "πΉ");
887 assert_some_next_valid_cutoff!(ptr, length, 94, 55, 56, "πΉ");
888 assert_some_next_valid_cutoff!(ptr, length, 94, 56, 56, "πΉ");
889 assert_some_next_valid_cutoff!(ptr, length, 94, 57, 60, "π");
890 assert_some_next_valid_cutoff!(ptr, length, 94, 58, 60, "π");
891 assert_some_next_valid_cutoff!(ptr, length, 94, 59, 60, "π");
892 assert_some_next_valid_cutoff!(ptr, length, 94, 60, 60, "π");
893 assert_some_next_valid_cutoff!(ptr, length, 94, 61, 64, "π₯");
894 assert_some_next_valid_cutoff!(ptr, length, 94, 62, 64, "π₯");
895 assert_some_next_valid_cutoff!(ptr, length, 94, 63, 64, "π₯");
896 assert_some_next_valid_cutoff!(ptr, length, 94, 64, 64, "π₯");
897 assert_some_next_valid_cutoff!(ptr, length, 94, 65, 68, "β€οΈβπ₯");
898 assert_some_next_valid_cutoff!(ptr, length, 94, 66, 68, "β€οΈβπ₯");
899 assert_some_next_valid_cutoff!(ptr, length, 94, 67, 68, "β€οΈβπ₯");
900 assert_some_next_valid_cutoff!(ptr, length, 94, 68, 68, "β€οΈβπ₯");
901 assert_some_next_valid_cutoff!(ptr, length, 94, 69, 81, "β€οΈβπ©Ή");
902 assert_some_next_valid_cutoff!(ptr, length, 94, 70, 81, "β€οΈβπ©Ή");
903 assert_some_next_valid_cutoff!(ptr, length, 94, 71, 81, "β€οΈβπ©Ή");
904 assert_some_next_valid_cutoff!(ptr, length, 94, 72, 81, "β€οΈβπ©Ή");
905 assert_some_next_valid_cutoff!(ptr, length, 94, 73, 81, "β€οΈβπ©Ή");
906 assert_some_next_valid_cutoff!(ptr, length, 94, 74, 81, "β€οΈβπ©Ή");
907 assert_some_next_valid_cutoff!(ptr, length, 94, 75, 77, "π₯");
908 assert_some_next_valid_cutoff!(ptr, length, 94, 76, 77, "π₯");
909 assert_some_next_valid_cutoff!(ptr, length, 94, 77, 77, "π₯");
910 assert_some_next_valid_cutoff!(ptr, length, 94, 78, 81, "β€οΈβπ©Ή");
911 assert_some_next_valid_cutoff!(ptr, length, 94, 79, 81, "β€οΈβπ©Ή");
912 assert_some_next_valid_cutoff!(ptr, length, 94, 80, 81, "β€οΈβπ©Ή");
913 assert_some_next_valid_cutoff!(ptr, length, 94, 81, 81, "β€οΈβπ©Ή");
914 assert_none_next_valid_cutoff!(ptr, length, 94, 82);
915 assert_none_next_valid_cutoff!(ptr, length, 94, 83);
916 assert_none_next_valid_cutoff!(ptr, length, 94, 84);
917 assert_none_next_valid_cutoff!(ptr, length, 94, 85);
918 assert_none_next_valid_cutoff!(ptr, length, 94, 86);
919 assert_none_next_valid_cutoff!(ptr, length, 94, 87);
920 assert_some_next_valid_cutoff!(ptr, length, 94, 88, 90, "π©Ή");
921 assert_some_next_valid_cutoff!(ptr, length, 94, 89, 90, "π©Ή");
922 assert_some_next_valid_cutoff!(ptr, length, 94, 90, 90, "π©Ή");
923 assert_none_next_valid_cutoff!(ptr, length, 94, 91);
924 assert_none_next_valid_cutoff!(ptr, length, 94, 92);
925 assert_none_next_valid_cutoff!(ptr, length, 94, 93);
926 assert_none_next_valid_cutoff!(ptr, length, 94, 94);
927
928 Ok(())
929 }
930
931 #[macro_export]
932 macro_rules! assert_some_next_valid_cutoff {
933 (
934 $ptr:expr,
935 $length:expr,
936 $expected_length:literal,
937 $invalid_index:literal,
938 $expected_valid_index:literal,
939 $expected_rune_str:literal
940 $(,)?
941 ) => {{
942 assert_eq!($length, $expected_length, "expected length to be {} rather than {}", $expected_length, $length);
945 let result = next_valid_cutoff($ptr, $length, $invalid_index);
946 assert!(result.is_some(), "expected next_valid_cutoff at {} to not be None", $invalid_index);
947 let actual = result.unwrap();
948 assert_eq!(actual, $expected_valid_index, "expected next_valid_cutoff to be {} rather than {}", $expected_valid_index, actual);
949 let parts = RuneParts::from_raw_parts($ptr, $length);
950 let result = parts.rune_at_index(actual);
951 assert!(result.is_ok(), "expected valid Rune at index to be {} but got error: {}", $expected_valid_index, result.err().map(|err|err.to_string()).unwrap_or_default());
952 let rune = result.unwrap();
953 assert_eq!(rune.as_str(), $expected_rune_str,
954 "expected rune at index {} to match \"{}\" rather than \"{}\"",
955 actual, $expected_rune_str, rune.as_str());
956 }};
957}
958
959 #[macro_export]
960 macro_rules! assert_none_next_valid_cutoff {
961 (
962 $ptr:expr,
963 $length:expr,
964 $expected_length:literal,
965 $invalid_index:literal $(,)?
966 ) => {{
967 assert_eq!(
969 $length, $expected_length,
970 "expected length to be {} rather than {}",
971 $expected_length, $length
972 );
973 let result = next_valid_cutoff($ptr, $length, $invalid_index);
974 assert!(
975 result.is_none(),
976 "expected next_valid_cutoff at {} to not be None but is actually {:#?}",
977 $invalid_index,
978 result
979 );
980 }};
981 }
982}
983
984#[cfg(test)]
985mod test_previous_valid_cutoff {
986 use crate::heuristic::previous_valid_cutoff;
987 use crate::pointer::{self};
988 use crate::{
989 assert_none_previous_valid_cutoff, assert_some_previous_valid_cutoff, Result,
990 RuneParts,
991 };
992
993 #[test]
994 fn test_previous_valid_cutoff_parts() -> Result<()> {
995 let (ptr, length) = pointer::from_slice("πππ»ππΌππ½ππΎππΏ".as_bytes())?;
996 assert_some_previous_valid_cutoff!(ptr, length, 44, 0, 0, "π");
997 assert_some_previous_valid_cutoff!(ptr, length, 44, 1, 0, "π");
998 assert_some_previous_valid_cutoff!(ptr, length, 44, 5, 4, "ππ»");
999 assert_some_previous_valid_cutoff!(ptr, length, 44, 13, 12, "ππΌ");
1000 assert_some_previous_valid_cutoff!(ptr, length, 44, 21, 20, "ππ½");
1001 assert_some_previous_valid_cutoff!(ptr, length, 44, 29, 28, "ππΎ");
1002 assert_some_previous_valid_cutoff!(ptr, length, 44, 37, 36, "ππΏ");
1003 Ok(())
1004 }
1005 #[test]
1006 fn test_previous_valid_cutoff_at_first_index_single_rune() -> Result<()> {
1007 let (ptr, length) = pointer::from_slice("β€οΈ".as_bytes())?;
1008 assert_some_previous_valid_cutoff!(ptr, length, 6, 0, 0, "β€οΈ");
1009 Ok(())
1010 }
1011
1012 #[test]
1013 fn test_previous_valid_cutoff_empty() -> Result<()> {
1014 let (ptr, length) = pointer::from_slice("".as_bytes())?;
1015 assert_none_previous_valid_cutoff!(ptr, length, 0, 0);
1016
1017 Ok(())
1018 }
1019
1020 #[test]
1021 fn test_previous_valid_cutoff_at_various_indexes_6_bytes() -> Result<()> {
1022 let (ptr, length) = pointer::from_slice("skullβ οΈskull".as_bytes())?;
1023 assert_none_previous_valid_cutoff!(ptr, length, 16, 0);
1024 assert_none_previous_valid_cutoff!(ptr, length, 16, 1);
1025 assert_none_previous_valid_cutoff!(ptr, length, 16, 2);
1026 assert_none_previous_valid_cutoff!(ptr, length, 16, 3);
1027 assert_none_previous_valid_cutoff!(ptr, length, 16, 4);
1028 assert_some_previous_valid_cutoff!(ptr, length, 16, 5, 5, "β οΈ");
1029 assert_some_previous_valid_cutoff!(ptr, length, 16, 6, 5, "β οΈ");
1030 assert_some_previous_valid_cutoff!(ptr, length, 16, 7, 5, "β οΈ");
1031 assert_some_previous_valid_cutoff!(ptr, length, 16, 8, 5, "β οΈ");
1032 assert_some_previous_valid_cutoff!(ptr, length, 16, 9, 5, "β οΈ");
1033 assert_some_previous_valid_cutoff!(ptr, length, 16, 10, 5, "β οΈ");
1034 assert_some_previous_valid_cutoff!(ptr, length, 16, 11, 5, "β οΈ");
1035 assert_some_previous_valid_cutoff!(ptr, length, 16, 12, 5, "β οΈ");
1036 assert_some_previous_valid_cutoff!(ptr, length, 16, 13, 5, "β οΈ");
1037 assert_some_previous_valid_cutoff!(ptr, length, 16, 14, 5, "β οΈ");
1038 assert_some_previous_valid_cutoff!(ptr, length, 16, 15, 5, "β οΈ");
1039 assert_some_previous_valid_cutoff!(ptr, length, 16, 16, 5, "β οΈ");
1040 Ok(())
1041 }
1042
1043 #[test]
1044 fn test_previous_valid_cutoff_at_various_indexes_4_bytes() -> Result<()> {
1045 let (ptr, length) = pointer::from_slice("smileyπsmiley".as_bytes())?;
1046 assert_none_previous_valid_cutoff!(ptr, length, 16, 0);
1047 assert_none_previous_valid_cutoff!(ptr, length, 16, 1);
1048 assert_none_previous_valid_cutoff!(ptr, length, 16, 2);
1049 assert_none_previous_valid_cutoff!(ptr, length, 16, 3);
1050 assert_none_previous_valid_cutoff!(ptr, length, 16, 4);
1051 assert_none_previous_valid_cutoff!(ptr, length, 16, 5);
1052 assert_some_previous_valid_cutoff!(ptr, length, 16, 6, 6, "π");
1053 assert_some_previous_valid_cutoff!(ptr, length, 16, 7, 6, "π");
1054 assert_some_previous_valid_cutoff!(ptr, length, 16, 8, 6, "π");
1055 assert_some_previous_valid_cutoff!(ptr, length, 16, 9, 6, "π");
1056 assert_some_previous_valid_cutoff!(ptr, length, 16, 10, 6, "π");
1057 assert_some_previous_valid_cutoff!(ptr, length, 16, 11, 6, "π");
1058 assert_some_previous_valid_cutoff!(ptr, length, 16, 12, 6, "π");
1059 assert_some_previous_valid_cutoff!(ptr, length, 16, 13, 6, "π");
1060 assert_some_previous_valid_cutoff!(ptr, length, 16, 14, 6, "π");
1061 assert_some_previous_valid_cutoff!(ptr, length, 16, 15, 6, "π");
1062 assert_some_previous_valid_cutoff!(ptr, length, 16, 16, 6, "π");
1063 Ok(())
1064 }
1065
1066 #[test]
1067 fn test_previous_valid_cutoff_at_various_indexes_ascii() -> Result<()> {
1068 let (ptr, length) = pointer::from_slice("abcdefghijklmnopqrstu".as_bytes())?;
1069 assert_none_previous_valid_cutoff!(ptr, length, 21, 7);
1070
1071 Ok(())
1072 }
1073
1074 #[test]
1075 fn test_previous_valid_cutoff_at_various_indexes_non_ascii() -> Result<()> {
1076 let (ptr, length) = pointer::from_slice("falcΓ£oπ¦
".as_bytes())?;
1077 assert_some_previous_valid_cutoff!(ptr, length, 11, 4, 4, "Γ£");
1078 assert_some_previous_valid_cutoff!(ptr, length, 11, 5, 4, "Γ£");
1079 assert_some_previous_valid_cutoff!(ptr, length, 11, 6, 4, "Γ£");
1080 assert_some_previous_valid_cutoff!(ptr, length, 11, 7, 7, "π¦
");
1081 assert_some_previous_valid_cutoff!(ptr, length, 11, 8, 7, "π¦
");
1082 assert_some_previous_valid_cutoff!(ptr, length, 11, 9, 7, "π¦
");
1083 assert_some_previous_valid_cutoff!(ptr, length, 11, 10, 7, "π¦
");
1084 assert_some_previous_valid_cutoff!(ptr, length, 11, 11, 7, "π¦
");
1085 assert_some_previous_valid_cutoff!(ptr, length, 11, 12, 7, "π¦
");
1086 assert_some_previous_valid_cutoff!(ptr, length, 11, 13, 7, "π¦
");
1087 assert_some_previous_valid_cutoff!(ptr, length, 11, 14, 7, "π¦
");
1088 assert_some_previous_valid_cutoff!(ptr, length, 11, 15, 7, "π¦
");
1089 Ok(())
1090 }
1091
1092 #[test]
1093 fn test_previous_valid_cutoff_at_first_index() -> Result<()> {
1094 let (ptr, length) = pointer::from_display("β€οΈπ¦
")?;
1095 assert_some_previous_valid_cutoff!(ptr, length, 10, 0, 0, "β€οΈ");
1096 assert_some_previous_valid_cutoff!(ptr, length, 10, 1, 0, "β€οΈ");
1097 assert_some_previous_valid_cutoff!(ptr, length, 10, 2, 0, "β€οΈ");
1098 assert_some_previous_valid_cutoff!(ptr, length, 10, 3, 0, "β€οΈ");
1099 assert_some_previous_valid_cutoff!(ptr, length, 10, 4, 0, "β€οΈ");
1100 assert_some_previous_valid_cutoff!(ptr, length, 10, 5, 0, "β€οΈ");
1101 assert_some_previous_valid_cutoff!(ptr, length, 10, 6, 6, "π¦
");
1102 assert_some_previous_valid_cutoff!(ptr, length, 10, 7, 6, "π¦
");
1103 assert_some_previous_valid_cutoff!(ptr, length, 10, 8, 6, "π¦
");
1104 assert_some_previous_valid_cutoff!(ptr, length, 10, 9, 6, "π¦
");
1105 assert_some_previous_valid_cutoff!(ptr, length, 10, 10, 6, "π¦
");
1106 assert_some_previous_valid_cutoff!(ptr, length, 10, 11, 6, "π¦
");
1107 assert_some_previous_valid_cutoff!(ptr, length, 10, 12, 6, "π¦
");
1108 assert_some_previous_valid_cutoff!(ptr, length, 10, 13, 6, "π¦
");
1109 assert_some_previous_valid_cutoff!(ptr, length, 10, 14, 6, "π¦
");
1110 assert_some_previous_valid_cutoff!(ptr, length, 10, 15, 6, "π¦
");
1111 Ok(())
1112 }
1113
1114 #[test]
1115 fn test_previous_valid_cutoff_at_various_indexes_94_bytes() -> Result<()> {
1116 let (ptr, length) = pointer::from_display("π©π»βπππΏπ§π½βππ¨βππΆοΈπΉππ₯β€οΈβπ₯β€οΈβπ©Ή")?;
1117 assert_some_previous_valid_cutoff!(ptr, length, 94, 0, 0, "π©π»βπ");
1118 assert_some_previous_valid_cutoff!(ptr, length, 94, 1, 0, "π©π»βπ");
1119 assert_some_previous_valid_cutoff!(ptr, length, 94, 2, 0, "π©π»βπ");
1120 assert_some_previous_valid_cutoff!(ptr, length, 94, 3, 0, "π©π»βπ");
1121 assert_some_previous_valid_cutoff!(ptr, length, 94, 4, 4, "π»\u{200d}π");
1122 assert_some_previous_valid_cutoff!(ptr, length, 94, 5, 4, "π»\u{200d}π");
1123 assert_some_previous_valid_cutoff!(ptr, length, 94, 6, 4, "π»\u{200d}π");
1124 assert_some_previous_valid_cutoff!(ptr, length, 94, 7, 4, "π»\u{200d}π");
1125 assert_some_previous_valid_cutoff!(ptr, length, 94, 8, 4, "π»\u{200d}π");
1126 assert_some_previous_valid_cutoff!(ptr, length, 94, 9, 4, "π»\u{200d}π");
1127 assert_some_previous_valid_cutoff!(ptr, length, 94, 10, 4, "π»\u{200d}π");
1128 assert_some_previous_valid_cutoff!(ptr, length, 94, 11, 11, "π");
1129 assert_some_previous_valid_cutoff!(ptr, length, 94, 12, 11, "π");
1130 assert_some_previous_valid_cutoff!(ptr, length, 94, 13, 11, "π");
1131 assert_some_previous_valid_cutoff!(ptr, length, 94, 14, 11, "π");
1132 assert_some_previous_valid_cutoff!(ptr, length, 94, 15, 15, "ππΏ");
1133 assert_some_previous_valid_cutoff!(ptr, length, 94, 16, 15, "ππΏ");
1134 assert_some_previous_valid_cutoff!(ptr, length, 94, 17, 15, "ππΏ");
1135 assert_some_previous_valid_cutoff!(ptr, length, 94, 18, 15, "ππΏ");
1136 assert_some_previous_valid_cutoff!(ptr, length, 94, 19, 19, "πΏ");
1137 assert_some_previous_valid_cutoff!(ptr, length, 94, 20, 19, "πΏ");
1138 assert_some_previous_valid_cutoff!(ptr, length, 94, 21, 19, "πΏ");
1139 assert_some_previous_valid_cutoff!(ptr, length, 94, 22, 19, "πΏ");
1140 assert_some_previous_valid_cutoff!(ptr, length, 94, 23, 23, "π§π½βπ");
1141 assert_some_previous_valid_cutoff!(ptr, length, 94, 24, 23, "π§π½βπ");
1142 assert_some_previous_valid_cutoff!(ptr, length, 94, 25, 23, "π§π½βπ");
1143 assert_some_previous_valid_cutoff!(ptr, length, 94, 26, 23, "π§π½βπ");
1144 assert_some_previous_valid_cutoff!(ptr, length, 94, 27, 27, "π½\u{200d}π");
1145 assert_some_previous_valid_cutoff!(ptr, length, 94, 28, 27, "π½\u{200d}π");
1146 assert_some_previous_valid_cutoff!(ptr, length, 94, 29, 27, "π½\u{200d}π");
1147 assert_some_previous_valid_cutoff!(ptr, length, 94, 30, 27, "π½\u{200d}π");
1148 assert_some_previous_valid_cutoff!(ptr, length, 94, 31, 27, "π½\u{200d}π");
1149 assert_some_previous_valid_cutoff!(ptr, length, 94, 32, 27, "π½\u{200d}π");
1150 assert_some_previous_valid_cutoff!(ptr, length, 94, 33, 27, "π½\u{200d}π");
1151 assert_some_previous_valid_cutoff!(ptr, length, 94, 34, 34, "ππ¨\u{200d}π");
1152 assert_some_previous_valid_cutoff!(ptr, length, 94, 35, 34, "ππ¨\u{200d}π");
1153 assert_some_previous_valid_cutoff!(ptr, length, 94, 36, 34, "ππ¨\u{200d}π");
1154 assert_some_previous_valid_cutoff!(ptr, length, 94, 36, 34, "ππ¨\u{200d}π");
1155 assert_some_previous_valid_cutoff!(ptr, length, 94, 37, 34, "ππ¨\u{200d}π");
1156 assert_some_previous_valid_cutoff!(ptr, length, 94, 38, 38, "π¨\u{200d}π");
1157 assert_some_previous_valid_cutoff!(ptr, length, 94, 39, 38, "π¨\u{200d}π");
1158 assert_some_previous_valid_cutoff!(ptr, length, 94, 40, 38, "π¨\u{200d}π");
1159 assert_some_previous_valid_cutoff!(ptr, length, 94, 41, 38, "π¨\u{200d}π");
1160 assert_some_previous_valid_cutoff!(ptr, length, 94, 42, 38, "π¨\u{200d}π");
1161 assert_some_previous_valid_cutoff!(ptr, length, 94, 43, 38, "π¨\u{200d}π");
1162 assert_some_previous_valid_cutoff!(ptr, length, 94, 44, 38, "π¨\u{200d}π");
1163 assert_some_previous_valid_cutoff!(ptr, length, 94, 45, 45, "ππΆ\u{fe0f}");
1164 assert_some_previous_valid_cutoff!(ptr, length, 94, 46, 45, "ππΆοΈ");
1165 assert_some_previous_valid_cutoff!(ptr, length, 94, 47, 45, "ππΆοΈ");
1166 assert_some_previous_valid_cutoff!(ptr, length, 94, 46, 45, "ππΆοΈ");
1167 assert_some_previous_valid_cutoff!(ptr, length, 94, 47, 45, "ππΆοΈ");
1168 assert_some_previous_valid_cutoff!(ptr, length, 94, 48, 45, "ππΆοΈ");
1169 assert_some_previous_valid_cutoff!(ptr, length, 94, 49, 49, "πΆοΈ");
1170 assert_some_previous_valid_cutoff!(ptr, length, 94, 50, 49, "πΆοΈ");
1171 assert_some_previous_valid_cutoff!(ptr, length, 94, 51, 49, "πΆοΈ");
1172 assert_some_previous_valid_cutoff!(ptr, length, 94, 52, 49, "πΆοΈ");
1173 assert_some_previous_valid_cutoff!(ptr, length, 94, 53, 49, "πΆοΈ");
1174 assert_some_previous_valid_cutoff!(ptr, length, 94, 54, 49, "πΆοΈ");
1175 assert_some_previous_valid_cutoff!(ptr, length, 94, 55, 49, "πΆοΈ");
1176 assert_some_previous_valid_cutoff!(ptr, length, 94, 56, 56, "πΉ");
1177 assert_some_previous_valid_cutoff!(ptr, length, 94, 57, 56, "πΉ");
1178 assert_some_previous_valid_cutoff!(ptr, length, 94, 58, 56, "πΉ");
1179 assert_some_previous_valid_cutoff!(ptr, length, 94, 59, 56, "πΉ");
1180 assert_some_previous_valid_cutoff!(ptr, length, 94, 60, 60, "π");
1181 assert_some_previous_valid_cutoff!(ptr, length, 94, 61, 60, "π");
1182 assert_some_previous_valid_cutoff!(ptr, length, 94, 62, 60, "π");
1183 assert_some_previous_valid_cutoff!(ptr, length, 94, 63, 60, "π");
1184 assert_some_previous_valid_cutoff!(ptr, length, 94, 64, 64, "π₯");
1185 assert_some_previous_valid_cutoff!(ptr, length, 94, 65, 64, "π₯");
1186 assert_some_previous_valid_cutoff!(ptr, length, 94, 66, 64, "π₯");
1187 assert_some_previous_valid_cutoff!(ptr, length, 94, 67, 64, "π₯");
1188 assert_some_previous_valid_cutoff!(ptr, length, 94, 68, 68, "β€οΈβπ₯");
1189 assert_some_previous_valid_cutoff!(ptr, length, 94, 69, 68, "β€οΈβπ₯");
1190 assert_some_previous_valid_cutoff!(ptr, length, 94, 70, 68, "β€οΈβπ₯");
1191 assert_some_previous_valid_cutoff!(ptr, length, 94, 71, 68, "β€οΈβπ₯");
1192 assert_some_previous_valid_cutoff!(ptr, length, 94, 72, 68, "β€οΈβπ₯");
1193 assert_some_previous_valid_cutoff!(ptr, length, 94, 73, 68, "β€οΈβπ₯");
1194 assert_some_previous_valid_cutoff!(ptr, length, 94, 74, 68, "β€οΈβπ₯");
1195 assert_some_previous_valid_cutoff!(ptr, length, 94, 75, 68, "β€οΈβπ₯");
1196 assert_some_previous_valid_cutoff!(ptr, length, 94, 76, 68, "β€οΈβπ₯");
1197 assert_some_previous_valid_cutoff!(ptr, length, 94, 77, 77, "π₯");
1198 assert_some_previous_valid_cutoff!(ptr, length, 94, 78, 77, "π₯");
1199 assert_some_previous_valid_cutoff!(ptr, length, 94, 79, 77, "π₯");
1200 assert_some_previous_valid_cutoff!(ptr, length, 94, 80, 77, "π₯");
1201 assert_some_previous_valid_cutoff!(ptr, length, 94, 81, 81, "β€οΈβπ©Ή");
1202 assert_some_previous_valid_cutoff!(ptr, length, 94, 82, 81, "β€οΈβπ©Ή");
1203 assert_some_previous_valid_cutoff!(ptr, length, 94, 83, 81, "β€οΈβπ©Ή");
1204 assert_some_previous_valid_cutoff!(ptr, length, 94, 84, 81, "β€οΈβπ©Ή");
1205 assert_some_previous_valid_cutoff!(ptr, length, 94, 85, 81, "β€οΈβπ©Ή");
1206 assert_some_previous_valid_cutoff!(ptr, length, 94, 86, 81, "β€οΈβπ©Ή");
1207 assert_some_previous_valid_cutoff!(ptr, length, 94, 87, 81, "β€οΈβπ©Ή");
1208 assert_some_previous_valid_cutoff!(ptr, length, 94, 88, 81, "β€οΈβπ©Ή");
1209 assert_some_previous_valid_cutoff!(ptr, length, 94, 89, 81, "β€οΈβπ©Ή");
1210 assert_some_previous_valid_cutoff!(ptr, length, 94, 90, 90, "π©Ή");
1211 assert_some_previous_valid_cutoff!(ptr, length, 94, 91, 90, "π©Ή");
1212 assert_some_previous_valid_cutoff!(ptr, length, 94, 92, 90, "π©Ή");
1213 assert_some_previous_valid_cutoff!(ptr, length, 94, 93, 90, "π©Ή");
1214 assert_some_previous_valid_cutoff!(ptr, length, 94, 94, 90, "π©Ή");
1215 Ok(())
1216 }
1217
1218 #[macro_export]
1219 macro_rules! assert_some_previous_valid_cutoff {
1220 (
1221 $ptr:expr,
1222 $length:expr,
1223 $expected_length:literal,
1224 $invalid_index:literal,
1225 $expected_valid_index:literal,
1226 $expected_rune_str:literal
1227 $(,)?
1228 ) => {{
1229
1230
1231 assert_eq!($length, $expected_length, "expected length to be {} rather than {}", $expected_length, $length);
1234 let result = previous_valid_cutoff($ptr, $length, $invalid_index);
1235 assert!(result.is_some(), "expected previous_valid_cutoff at {} to not be None", $invalid_index);
1236 let actual = result.unwrap();
1237 assert_eq!(actual, $expected_valid_index, "expected previous_valid_cutoff to be {} rather than {}", $expected_valid_index, actual);
1238 let parts = RuneParts::from_raw_parts($ptr, $length);
1239 let result = parts.rune_at_index(actual);
1240 assert!(result.is_ok(), "expected valid Rune at index to be {} but got error: {}", $expected_valid_index, result.err().map(|err|err.to_string()).unwrap_or_default());
1241 let rune = result.unwrap();
1242 assert_eq!(rune.as_str(), $expected_rune_str,
1243 "expected rune at index {} to match \"{}\" rather than \"{}\"",
1244 actual, $expected_rune_str, rune.as_str());
1245 }};
1246}
1247
1248 #[macro_export]
1249 macro_rules! assert_none_previous_valid_cutoff {
1250 (
1251 $ptr:expr, $length:expr, $expected_length:literal, $invalid_index:literal $(,)?
1252 ) => {{
1253
1254
1255 assert_eq!(
1258 $length, $expected_length,
1259 "expected length to be {} rather than {}",
1260 $expected_length, $length
1261 );
1262 let result = previous_valid_cutoff($ptr, $length, $invalid_index);
1263 assert!(
1264 result.is_none(),
1265 "expected previous_valid_cutoff at {} to not be None but is actually {:#?}",
1266 $invalid_index,
1267 result
1268 );
1269 }};
1270}
1271}