1use crate::{
11 EMPTY,
12 MAX_LENGTH,
13 MAX_LENGTH_SMALL,
14 MAX_LENGTH_SMALL_ADD1,
15 PREFIX_LENGTH,
16 StringPtr,
17 TkStrError,
18 TokenString,
19};
20
21extern crate alloc;
22
23use core::{fmt, marker, mem, ptr, slice};
24
25#[derive(Debug, Clone, Copy)]
37pub struct Builder<'a, const N: usize> {
38 strings: [*const TokenString; N],
40 total_size: usize,
42 num_strings: usize,
44 lifetime: marker::PhantomData<&'a ()>,
46}
47
48#[derive(Debug)]
52pub struct BuilderIter<'a, const N: usize> {
53 builder: &'a Builder<'a, N>,
55 idx: usize,
57}
58
59impl<const N: usize> fmt::Display for Builder<'_, N> {
60 #[inline]
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 write!(f, "Builder < ")?;
63 for idx in 0 .. self.num_strings {
64 if idx == 0 {
65 write!(
66 f,
67 "'{}'",
68 unsafe { &*self.strings[idx] }
72 )?;
73 } else {
74 write!(
75 f,
76 " + '{}'",
77 unsafe { &*self.strings[idx] }
81 )?;
82 }
83 }
84 write!(f, " >")
85 }
86}
87
88impl<'a, const N: usize> IntoIterator for &'a Builder<'a, N> {
89 type IntoIter = BuilderIter<'a, N>;
90 type Item = &'a TokenString;
91
92 #[inline]
93 fn into_iter(self) -> Self::IntoIter {
94 Self::IntoIter {
95 builder: self,
96 idx: 0,
97 }
98 }
99}
100
101impl<'a, const N: usize> Iterator for BuilderIter<'a, N> {
102 type Item = &'a TokenString;
103
104 #[inline]
105 fn next(&mut self) -> Option<Self::Item> {
106 debug_assert!(
107 self.idx <= self.builder.num_strings,
108 "Builder iterator index is out of bounds"
109 );
110 self.idx += 1;
111 if self.idx - 1 == self.builder.num_strings {
112 None
113 } else {
114 Some(unsafe { &*self.builder.strings[self.idx - 1] })
118 }
119 }
120}
121
122impl<'a, const N: usize> Builder<'a, N> {
123 #[inline]
124 #[must_use]
125 pub fn iter(&'a self) -> BuilderIter<'a, N> {
126 <&Self as IntoIterator>::into_iter(self)
127 }
128
129 #[inline]
137 #[must_use]
138 pub const fn new(s: &'a TokenString) -> Self {
139 assert!(N > 0, "the number of elements must not be 0");
140 let mut ret_val = Self {
141 total_size: s.len as usize,
142 strings: [ptr::null(); N],
143 num_strings: 1,
144 lifetime: marker::PhantomData,
145 };
146 ret_val.strings[0] = s;
147 ret_val
148 }
149
150 #[inline]
160 #[must_use]
161 pub const fn concat_unchecked(&mut self, s: &'a TokenString) -> &mut Self {
162 assert!(
163 (self.num_strings < N),
164 "more strings concatenated than reserved space in Builder"
165 );
166 self.total_size += s.len as usize;
167 self.strings[self.num_strings] = s;
168 self.num_strings += 1;
169
170 self
171 }
172
173 #[inline]
185 pub const fn concat_checked(
186 &mut self,
187 s: &'a TokenString,
188 ) -> Result<&mut Self, TkStrError> {
189 if self.num_strings == N {
190 return Err(TkStrError::TooMany(N));
191 }
192 if self.total_size + s.len as usize > MAX_LENGTH {
193 return Err(TkStrError::TooBig(self.total_size + s.len as usize));
194 }
195 self.total_size += s.len as usize;
196 self.strings[self.num_strings] = s;
197 self.num_strings += 1;
198
199 Ok(self)
200 }
201
202 #[inline]
209 pub fn collect_checked(self) -> Result<TokenString, TkStrError> {
210 match self.total_size {
211 | 0 => Ok(EMPTY),
212 | 1 ..= MAX_LENGTH_SMALL => Ok(self.collect_to_small()),
213 | MAX_LENGTH_SMALL_ADD1 ..= MAX_LENGTH =>
214 Ok(self.collect_to_alloc()),
215 | _ => Err(TkStrError::TooBig(self.total_size)),
216 }
217 }
218
219 #[inline]
226 #[must_use]
227 pub fn collect_unchecked(self) -> TokenString {
228 match self.total_size {
229 | 0 => EMPTY,
230 | 1 ..= MAX_LENGTH_SMALL => self.collect_to_small(),
231 | MAX_LENGTH_SMALL_ADD1 ..= MAX_LENGTH => self.collect_to_alloc(),
232 | _ => panic!(
233 "the result of this builder would be bigger than `MAX_LENGTH`!"
234 ),
235 }
236 }
237
238 fn collect_to_small(&self) -> TokenString {
240 let mut ret_val = EMPTY;
241 #[expect(
242 clippy::cast_possible_truncation,
243 reason = "We checked for overflow in the parent function"
244 )]
245 let total = self.total_size as u16;
246 ret_val.len = total;
247 let dest: &mut [u8] = unsafe {
251 slice::from_raw_parts_mut(
252 ret_val.prefix.as_mut_ptr(),
253 self.total_size,
254 )
255 };
256 let mut curr_end = 0;
257 for b in self {
258 let len = b.len as usize;
259 let idx = curr_end;
260 curr_end += len;
261 dest[idx .. curr_end].copy_from_slice(&b.as_bytes()[.. len]);
262 }
263
264 ret_val
265 }
266
267 fn collect_to_alloc(&self) -> TokenString {
269 let mut ret_val = EMPTY;
270 #[expect(
271 clippy::cast_possible_truncation,
272 reason = "We checked for overflow in the parent function"
273 )]
274 let total = self.total_size as u16;
275 ret_val.u.ptr =
276 mem::ManuallyDrop::new(StringPtr::alloc_manually(self.total_size));
277 ret_val.len = total;
278 let mut curr_end = 0;
279 for b in self {
280 let len = b.len as usize;
281 let idx = curr_end;
282 curr_end += len;
283 unsafe {
286 (*ret_val.u.ptr).copy_manually(idx, b.as_bytes());
287 }
288 }
289 ret_val.prefix.copy_from_slice(unsafe {
292 &(*ret_val.u.ptr).as_slice_manually_mut(self.total_size)
293 [.. PREFIX_LENGTH]
294 });
295 ret_val
296 }
297}
298
299pub trait Concat<T> {
302 type Output;
303
304 fn concat(self, s: T) -> Result<Self::Output, TkStrError>;
313}
314
315impl<'a, const N: usize> Concat<&'a TokenString>
316 for Result<&'a mut Builder<'a, N>, TkStrError>
317{
318 type Output = &'a mut Builder<'a, N>;
319
320 #[inline]
321 fn concat(self, s: &'a TokenString) -> Result<Self::Output, TkStrError> {
322 self?.concat_checked(s)
323 }
324}
325
326impl<'a, const N: usize> Concat<&'a TokenString> for &'a mut Builder<'a, N> {
327 type Output = &'a mut Builder<'a, N>;
328
329 #[inline]
330 fn concat(self, s: &'a TokenString) -> Result<Self::Output, TkStrError> {
331 self.concat_checked(s)
332 }
333}
334
335pub trait Collect {
338 fn collect(self) -> Result<TokenString, TkStrError>;
345}
346
347impl<'a, const N: usize> Collect
348 for Result<&'a mut Builder<'a, N>, TkStrError>
349{
350 #[inline]
351 fn collect(self) -> Result<TokenString, TkStrError> {
352 self?.collect_checked()
353 }
354}
355
356impl<'a, const N: usize> Collect for &'a mut Builder<'a, N> {
357 #[inline]
358 fn collect(self) -> Result<TokenString, TkStrError> {
359 self.collect_checked()
360 }
361}
362
363#[macro_export]
364macro_rules! num_args {
366 () => { 0_usize };
367 ($_x:tt $($xs:tt)*) => { 1_usize + $crate::num_args!($($xs)*) };
368}
369
370#[macro_export]
386macro_rules! concat {
387 ( $x0:expr, $($xs:expr),+ ) => {{
388 $crate::Builder::<'_, {$crate::num_args!($x0 $($xs)*)}>::new($x0)
389 $( .concat($xs) )+.collect()
390 }};
391}
392
393#[cfg(test)]
399mod prefix {
400 extern crate std;
401 use assert2::check;
402
403 use crate::{Builder, TokenString};
404
405 #[test]
406 fn concat_empty_unchecked() {
407 let s1 = TokenString::default();
408 let res = Builder::<6>::new(&s1).collect_unchecked();
409 check!(res.prefix[0] == 0);
410 check!(res.len == 0);
411 }
412
413 #[test]
414 fn concat_2_empty_unchecked() {
415 let s1 = TokenString::default();
416 let s2 = TokenString::default();
417 let res = Builder::<6>::new(&s1)
418 .concat_unchecked(&s2)
419 .collect_unchecked();
420 check!(res.prefix[0] == 0);
421 check!(res.len == 0);
422 }
423
424 #[test]
425 fn concat_1_unchecked() {
426 let s1 = TokenString::from_str_unchecked("12");
427 let res = Builder::<6>::new(&s1).collect_unchecked();
428 check!(&res.prefix[.. 2] == b"12");
429 check!(res.len == 2);
430 }
431
432 #[test]
433 fn concat_1_empty_unchecked() {
434 let s1 = TokenString::from_str_unchecked("12");
435 let s2 = TokenString::default();
436 let res = Builder::<6>::new(&s1)
437 .concat_unchecked(&s2)
438 .collect_unchecked();
439 check!(&res.prefix[.. 2] == b"12");
440 check!(res.len == 2);
441 }
442
443 #[test]
444 fn concat_empty_1_unchecked() {
445 let s1 = TokenString::default();
446 let s2 = TokenString::from_str_unchecked("12");
447 let res = Builder::<6>::new(&s1)
448 .concat_unchecked(&s2)
449 .collect_unchecked();
450 check!(&res.prefix[.. 2] == b"12");
451 }
452
453
454 #[test]
455 fn concat_2_unchecked() {
456 let s1 = TokenString::from_str_unchecked("12");
457 let s2 = TokenString::from_str_unchecked("34");
458 let res = Builder::<6>::new(&s1)
459 .concat_unchecked(&s2)
460 .collect_unchecked();
461 check!(&res.prefix[.. 4] == b"1234");
462 check!(res.len == 4);
463 }
464
465 #[test]
466 fn concat_1_empty_1_unchecked() {
467 let s1 = TokenString::from_str_unchecked("12");
468 let s2 = TokenString::from_str_unchecked("");
469 let s3 = TokenString::from_str_unchecked("34");
470 let res = Builder::<6>::new(&s1)
471 .concat_unchecked(&s2)
472 .concat_unchecked(&s3)
473 .collect_unchecked();
474 check!(&res.prefix[.. 4] == b"1234");
475 check!(res.len == 4);
476 }
477
478 #[test]
479 fn concat_3_unchecked() {
480 let s1 = TokenString::from_str_unchecked("12");
481 let s2 = TokenString::from_str_unchecked("34");
482 let s3 = TokenString::from_str_unchecked("56");
483 let res = Builder::<6>::new(&s1)
484 .concat_unchecked(&s2)
485 .concat_unchecked(&s3)
486 .collect_unchecked();
487 check!(&res.prefix == b"123456");
488 check!(res.len == 6);
489 }
490 #[test]
491 fn concat_empty_checked() {
492 let s1 = TokenString::default();
493 let res = Builder::<6>::new(&s1).collect_checked().unwrap();
494 check!(res.prefix[0] == 0);
495 check!(res.len == 0);
496 }
497
498 #[test]
499 fn concat_2_empty_checked() {
500 let s1 = TokenString::default();
501 let s2 = TokenString::default();
502 let res = Builder::<6>::new(&s1)
503 .concat_checked(&s2)
504 .unwrap()
505 .collect_checked()
506 .unwrap();
507 check!(res.prefix[0] == 0);
508 check!(res.len == 0);
509 }
510
511 #[test]
512 fn concat_1_checked() {
513 let s1 = TokenString::from_str_unchecked("12");
514 let res = Builder::<6>::new(&s1).collect_checked().unwrap();
515 check!(&res.prefix[.. 2] == b"12");
516 check!(res.len == 2);
517 }
518
519 #[test]
520 fn concat_1_empty_checked() {
521 let s1 = TokenString::from_str_unchecked("12");
522 let s2 = TokenString::default();
523 let res = Builder::<6>::new(&s1)
524 .concat_checked(&s2)
525 .unwrap()
526 .collect_checked()
527 .unwrap();
528 check!(&res.prefix[.. 2] == b"12");
529 check!(res.len == 2);
530 }
531
532 #[test]
533 fn concat_empty_1_checked() {
534 let s1 = TokenString::default();
535 let s2 = TokenString::from_str_unchecked("12");
536 let res = Builder::<6>::new(&s1)
537 .concat_checked(&s2)
538 .unwrap()
539 .collect_checked()
540 .unwrap();
541 check!(&res.prefix[.. 2] == b"12");
542 }
543
544
545 #[test]
546 fn concat_2_checked() {
547 let s1 = TokenString::from_str_unchecked("12");
548 let s2 = TokenString::from_str_unchecked("34");
549 let res = Builder::<6>::new(&s1)
550 .concat_checked(&s2)
551 .unwrap()
552 .collect_checked()
553 .unwrap();
554 check!(&res.prefix[.. 4] == b"1234");
555 check!(res.len == 4);
556 }
557
558 #[test]
559 fn concat_1_empty_1_checked() {
560 let s1 = TokenString::from_str_unchecked("12");
561 let s2 = TokenString::from_str_unchecked("");
562 let s3 = TokenString::from_str_unchecked("34");
563 let res = Builder::<6>::new(&s1)
564 .concat_checked(&s2)
565 .unwrap()
566 .concat_checked(&s3)
567 .unwrap()
568 .collect_checked()
569 .unwrap();
570 check!(&res.prefix[.. 4] == b"1234");
571 check!(res.len == 4);
572 }
573
574 #[test]
575 fn concat_3_checked() {
576 let s1 = TokenString::from_str_unchecked("12");
577 let s2 = TokenString::from_str_unchecked("34");
578 let s3 = TokenString::from_str_unchecked("56");
579 let res = Builder::<6>::new(&s1)
580 .concat_checked(&s2)
581 .unwrap()
582 .concat_checked(&s3)
583 .unwrap()
584 .collect_checked()
585 .unwrap();
586 check!(&res.prefix == b"123456");
587 check!(res.len == 6);
588 }
589}
590
591#[cfg(test)]
592mod small {
593 extern crate std;
594 use assert2::check;
595
596 use crate::{Builder, TokenString};
597
598
599 #[test]
600 fn concat_1_unchecked() {
601 let s1 = TokenString::from_str_unchecked("1234567");
602 let res = Builder::<6>::new(&s1).collect_unchecked();
603 check!(&res.prefix == b"123456");
604 check!(unsafe { res.u.small[0] } == b'7');
607 check!(res.len == 7);
608 }
609
610 #[test]
611 fn concat_1_empty_unchecked() {
612 let s1 = TokenString::from_str_unchecked("1234567");
613 let s2 = TokenString::default();
614 let res = Builder::<6>::new(&s1)
615 .concat_unchecked(&s2)
616 .collect_unchecked();
617 check!(&res.prefix == b"123456");
618 check!(unsafe { res.u.small[0] } == b'7');
621 check!(res.len == 7);
622 }
623
624 #[test]
625 fn concat_empty_1_unchecked() {
626 let s1 = TokenString::default();
627 let s2 = TokenString::from_str_unchecked("1234567");
628 let res = Builder::<6>::new(&s1)
629 .concat_unchecked(&s2)
630 .collect_unchecked();
631 check!(&res.prefix == b"123456");
632 check!(unsafe { res.u.small[0] } == b'7');
635 check!(res.len == 7);
636 }
637
638
639 #[test]
640 fn concat_2_unchecked() {
641 let s1 = TokenString::from_str_unchecked("1234");
642 let s2 = TokenString::from_str_unchecked("5678");
643 let res = Builder::<6>::new(&s1)
644 .concat_unchecked(&s2)
645 .collect_unchecked();
646 check!(&res.prefix[.. 6] == b"123456");
647 check!(unsafe { &res.u.small[.. 2] } == b"78");
650 check!(res.len == 8);
651 }
652
653 #[test]
654 fn concat_2_pref_unchecked() {
655 let s1 = TokenString::from_str_unchecked("1");
656 let s2 = TokenString::from_str_unchecked("2345678");
657 let res = Builder::<6>::new(&s1)
658 .concat_unchecked(&s2)
659 .collect_unchecked();
660 check!(&res.prefix[.. 6] == b"123456");
661 check!(unsafe { &res.u.small[.. 2] } == b"78");
664 check!(res.len == 8);
665 }
666
667 #[test]
668 fn concat_1_empty_1_unchecked() {
669 let s1 = TokenString::from_str_unchecked("1234");
670 let s2 = TokenString::from_str_unchecked("");
671 let s3 = TokenString::from_str_unchecked("5678");
672 let res = Builder::<6>::new(&s1)
673 .concat_unchecked(&s2)
674 .concat_unchecked(&s3)
675 .collect_unchecked();
676 check!(&res.prefix[.. 6] == b"123456");
677 check!(unsafe { &res.u.small[.. 2] } == b"78");
680 check!(res.len == 8);
681 }
682
683 #[test]
684 fn concat_3_unchecked() {
685 let s1 = TokenString::from_str_unchecked("1234");
686 let s2 = TokenString::from_str_unchecked("5678");
687 let s3 = TokenString::from_str_unchecked("90ABCD");
688 let res = Builder::<6>::new(&s1)
689 .concat_unchecked(&s2)
690 .concat_unchecked(&s3)
691 .collect_unchecked();
692 check!(&res.prefix[.. 6] == b"123456");
693 check!(unsafe { &res.u.small[.. 8] } == b"7890ABCD");
696 check!(res.len == 14);
697 }
698
699 #[test]
700 fn concat_1_checked() {
701 let s1 = TokenString::from_str_unchecked("1234567");
702 let res = Builder::<6>::new(&s1).collect_checked().unwrap();
703 check!(&res.prefix == b"123456");
704 check!(unsafe { res.u.small[0] } == b'7');
707 check!(res.len == 7);
708 }
709
710 #[test]
711 fn concat_1_empty_checked() {
712 let s1 = TokenString::from_str_unchecked("1234567");
713 let s2 = TokenString::default();
714 let res = Builder::<6>::new(&s1)
715 .concat_checked(&s2)
716 .unwrap()
717 .collect_checked()
718 .unwrap();
719 check!(&res.prefix == b"123456");
720 check!(unsafe { res.u.small[0] } == b'7');
723 check!(res.len == 7);
724 }
725
726 #[test]
727 fn concat_empty_1_checked() {
728 let s1 = TokenString::default();
729 let s2 = TokenString::from_str_unchecked("1234567");
730 let res = Builder::<6>::new(&s1)
731 .concat_checked(&s2)
732 .unwrap()
733 .collect_checked()
734 .unwrap();
735 check!(&res.prefix == b"123456");
736 check!(unsafe { res.u.small[0] } == b'7');
739 check!(res.len == 7);
740 }
741
742
743 #[test]
744 fn concat_2_checked() {
745 let s1 = TokenString::from_str_unchecked("1234");
746 let s2 = TokenString::from_str_unchecked("5678");
747 let res = Builder::<6>::new(&s1)
748 .concat_checked(&s2)
749 .unwrap()
750 .collect_checked()
751 .unwrap();
752 check!(&res.prefix[.. 6] == b"123456");
753 check!(unsafe { &res.u.small[.. 2] } == b"78");
756 check!(res.len == 8);
757 }
758
759 #[test]
760 fn concat_2_pref_checked() {
761 let s1 = TokenString::from_str_unchecked("1");
762 let s2 = TokenString::from_str_unchecked("2345678");
763 let res = Builder::<6>::new(&s1)
764 .concat_checked(&s2)
765 .unwrap()
766 .collect_checked()
767 .unwrap();
768 check!(&res.prefix[.. 6] == b"123456");
769 check!(unsafe { &res.u.small[.. 2] } == b"78");
772 check!(res.len == 8);
773 }
774
775 #[test]
776 fn concat_1_empty_1_checked() {
777 let s1 = TokenString::from_str_unchecked("1234");
778 let s2 = TokenString::from_str_unchecked("");
779 let s3 = TokenString::from_str_unchecked("5678");
780 let res = Builder::<6>::new(&s1)
781 .concat_checked(&s2)
782 .unwrap()
783 .concat_checked(&s3)
784 .unwrap()
785 .collect_checked()
786 .unwrap();
787 check!(&res.prefix[.. 6] == b"123456");
788 check!(unsafe { &res.u.small[.. 2] } == b"78");
791 check!(res.len == 8);
792 }
793
794 #[test]
795 fn concat_3_checked() {
796 let s1 = TokenString::from_str_unchecked("1234");
797 let s2 = TokenString::from_str_unchecked("5678");
798 let s3 = TokenString::from_str_unchecked("90ABCD");
799 let res = Builder::<6>::new(&s1)
800 .concat_checked(&s2)
801 .unwrap()
802 .concat_checked(&s3)
803 .unwrap()
804 .collect_checked()
805 .unwrap();
806 check!(&res.prefix[.. 6] == b"123456");
807 check!(unsafe { &res.u.small[.. 8] } == b"7890ABCD");
810 check!(res.len == 14);
811 }
812}
813
814#[cfg(test)]
815mod heap {
816 extern crate std;
817 use assert2::check;
818
819 use crate::{Builder, TokenString};
820
821
822 #[test]
823 fn concat_1_unchecked() {
824 let s1 = TokenString::from_str_unchecked("1234567890ABCDE");
825 let res = Builder::<6>::new(&s1).collect_unchecked();
826 check!(&res.prefix == b"123456");
827 check!(
828 unsafe { res.u.ptr.as_string_manually(res.len as usize) }
831 == "1234567890ABCDE"
832 );
833 check!(res.len == 15);
834 }
835
836 #[test]
837 fn concat_1_empty_unchecked() {
838 let s1 = TokenString::from_str_unchecked("1234567890ABCDE");
839 let s2 = TokenString::default();
840 let res = Builder::<6>::new(&s1)
841 .concat_unchecked(&s2)
842 .collect_unchecked();
843 check!(&res.prefix == b"123456");
844 check!(
845 unsafe { res.u.ptr.as_string_manually(res.len as usize) }
848 == "1234567890ABCDE"
849 );
850 check!(res.len == 15);
851 }
852
853 #[test]
854 fn concat_empty_1_unchecked() {
855 let s1 = TokenString::default();
856 let s2 = TokenString::from_str_unchecked("1234567890ABCDE");
857 let res = Builder::<6>::new(&s1)
858 .concat_unchecked(&s2)
859 .collect_unchecked();
860 check!(&res.prefix == b"123456");
861 check!(
862 unsafe { res.u.ptr.as_string_manually(res.len as usize) }
865 == "1234567890ABCDE"
866 );
867 check!(res.len == 15);
868 }
869
870
871 #[test]
872 fn concat_2_unchecked() {
873 let s1 = TokenString::from_str_unchecked("1234");
874 let s2 = TokenString::from_str_unchecked("567890ABCDE");
875 let res = Builder::<6>::new(&s1)
876 .concat_unchecked(&s2)
877 .collect_unchecked();
878 check!(&res.prefix[.. 6] == b"123456");
879 check!(
880 unsafe { res.u.ptr.as_string_manually(res.len as usize) }
883 == "1234567890ABCDE"
884 );
885 check!(res.len == 15);
886 }
887
888 #[test]
889 fn concat_1_empty_1_unchecked() {
890 let s1 = TokenString::from_str_unchecked("1234");
891 let s2 = TokenString::from_str_unchecked("");
892 let s3 = TokenString::from_str_unchecked("567890ABCDE");
893 let res = Builder::<6>::new(&s1)
894 .concat_unchecked(&s2)
895 .concat_unchecked(&s3)
896 .collect_unchecked();
897 check!(&res.prefix[.. 6] == b"123456");
898 check!(
899 unsafe { res.u.ptr.as_string_manually(res.len as usize) }
902 == "1234567890ABCDE"
903 );
904 check!(res.len == 15);
905 }
906
907 #[test]
908 fn concat_3_unchecked() {
909 let s1 = TokenString::from_str_unchecked("1234");
910 let s2 = TokenString::from_str_unchecked("5678");
911 let s3 = TokenString::from_str_unchecked("90ABCDE");
912 let res = Builder::<6>::new(&s1)
913 .concat_unchecked(&s2)
914 .concat_unchecked(&s3)
915 .collect_unchecked();
916 check!(&res.prefix[.. 6] == b"123456");
917 check!(
918 unsafe { res.u.ptr.as_string_manually(res.len as usize) }
921 == "1234567890ABCDE"
922 );
923 check!(res.len == 15);
924 }
925
926 #[test]
927 fn concat_1_checked() {
928 let s1 = TokenString::from_str_unchecked("1234567890ABCDE");
929 let res = Builder::<6>::new(&s1).collect_checked().unwrap();
930 check!(&res.prefix == b"123456");
931 check!(
932 unsafe { res.u.ptr.as_string_manually(res.len as usize) }
935 == "1234567890ABCDE"
936 );
937 check!(res.len == 15);
938 }
939
940 #[test]
941 fn concat_1_empty_checked() {
942 let s1 = TokenString::from_str_unchecked("1234567890ABCDE");
943 let s2 = TokenString::default();
944 let res = Builder::<6>::new(&s1)
945 .concat_checked(&s2)
946 .unwrap()
947 .collect_checked()
948 .unwrap();
949 check!(&res.prefix == b"123456");
950 check!(
951 unsafe { res.u.ptr.as_string_manually(res.len as usize) }
954 == "1234567890ABCDE"
955 );
956 check!(res.len == 15);
957 }
958
959 #[test]
960 fn concat_empty_1_checked() {
961 let s1 = TokenString::default();
962 let s2 = TokenString::from_str_unchecked("1234567890ABCDE");
963 let res = Builder::<6>::new(&s1)
964 .concat_checked(&s2)
965 .unwrap()
966 .collect_checked()
967 .unwrap();
968 check!(&res.prefix == b"123456");
969 check!(
970 unsafe { res.u.ptr.as_string_manually(res.len as usize) }
973 == "1234567890ABCDE"
974 );
975 check!(res.len == 15);
976 }
977
978
979 #[test]
980 fn concat_2_checked() {
981 let s1 = TokenString::from_str_unchecked("1234");
982 let s2 = TokenString::from_str_unchecked("567890ABCDE");
983 let res = Builder::<6>::new(&s1)
984 .concat_checked(&s2)
985 .unwrap()
986 .collect_checked()
987 .unwrap();
988 check!(&res.prefix[.. 6] == b"123456");
989 check!(
990 unsafe { res.u.ptr.as_string_manually(res.len as usize) }
993 == "1234567890ABCDE"
994 );
995 check!(res.len == 15);
996 }
997
998 #[test]
999 fn concat_1_empty_1_checked() {
1000 let s1 = TokenString::from_str_unchecked("1234");
1001 let s2 = TokenString::from_str_unchecked("");
1002 let s3 = TokenString::from_str_unchecked("567890ABCDE");
1003 let res = Builder::<6>::new(&s1)
1004 .concat_checked(&s2)
1005 .unwrap()
1006 .concat_checked(&s3)
1007 .unwrap()
1008 .collect_checked()
1009 .unwrap();
1010 check!(&res.prefix[.. 6] == b"123456");
1011 check!(
1012 unsafe { res.u.ptr.as_string_manually(res.len as usize) }
1015 == "1234567890ABCDE"
1016 );
1017 check!(res.len == 15);
1018 }
1019
1020 #[test]
1021 fn concat_3_checked() {
1022 let s1 = TokenString::from_str_unchecked("1234");
1023 let s2 = TokenString::from_str_unchecked("5678");
1024 let s3 = TokenString::from_str_unchecked("90ABCDE");
1025 let res = Builder::<6>::new(&s1)
1026 .concat_checked(&s2)
1027 .unwrap()
1028 .concat_checked(&s3)
1029 .unwrap()
1030 .collect_checked()
1031 .unwrap();
1032 check!(&res.prefix[.. 6] == b"123456");
1033 check!(
1034 unsafe { res.u.ptr.as_string_manually(res.len as usize) }
1037 == "1234567890ABCDE"
1038 );
1039 check!(res.len == 15);
1040 }
1041}