42
42
// ! assert!(first_byte == 0x41);
43
43
// ! ```
44
44
45
- use crate :: array :: {ArrayTrait , SpanTrait };
45
+ use crate :: array :: {ArrayTrait , Span , SpanTrait };
46
46
#[allow(unused_imports)]
47
47
use crate :: bytes_31 :: {
48
48
BYTES_IN_BYTES31 , Bytes31Trait , POW_2_128 , POW_2_8 , U128IntoBytes31 , U8IntoBytes31 ,
@@ -52,12 +52,17 @@ use crate::clone::Clone;
52
52
use crate :: cmp :: min;
53
53
#[allow(unused_imports)]
54
54
use crate :: integer :: {U32TryIntoNonZero , u128_safe_divmod};
55
+ #[feature(" bounded-int-utils" )]
56
+ use crate :: internal :: bounded_int :: {BoundedInt , downcast};
55
57
#[allow(unused_imports)]
56
58
use crate :: serde :: Serde ;
57
59
use crate :: traits :: {Into , TryInto };
58
60
#[allow(unused_imports)]
59
61
use crate :: zeroable :: NonZeroIntoImpl ;
60
62
63
+ /// The number of bytes in [`ByteArray::pending_word`].
64
+ type WordBytes = BoundedInt <0 , { BYTES_IN_BYTES31_MINUS_ONE . into() }>;
65
+
61
66
/// A magic constant for identifying serialization of `ByteArray` variables. An array of `felt252`
62
67
/// with this magic value as one of the `felt252` indicates that you should expect right after it a
63
68
/// serialized `ByteArray`. This is currently used mainly for prints and panics.
@@ -586,3 +591,124 @@ impl ByteArrayFromIterator of crate::iter::FromIterator<ByteArray, u8> {
586
591
ba
587
592
}
588
593
}
594
+
595
+ /// A view into a contiguous collection of a string type.
596
+ /// Currently implemented only for `ByteArray`, but will soon be implemented for other string types.
597
+ /// `Span` implements the `Copy` and the `Drop` traits.
598
+ #[derive(Copy , Drop )]
599
+ pub struct ByteSpan {
600
+ /// A span representing the array of all `bytes31` words in the byte-span, excluding the last
601
+ /// bytes_31 word that is stored in [Self::last_word].
602
+ /// Invariant: every byte stored in `data` is part of the span except for the bytes appearing
603
+ /// before `first_char_start_offset` in the first word.
604
+ data : Span <bytes31 >,
605
+ /// The offset of the first character in the first entry of [Self::data], for use in span
606
+ /// slices. When data is empty, this offset applies to remainder_word instead.
607
+ first_char_start_offset : WordBytes ,
608
+ /// Contains the final bytes of the span when the end is either not in memory or isn't aligned
609
+ /// to a word boundary.
610
+ /// It is represented as a `felt252` to improve performance of building the byte array, but
611
+ /// represents a `bytes31`.
612
+ /// The first byte is the most significant byte among the `pending_word_len` bytes in the word.
613
+ remainder_word : felt252 ,
614
+ /// The number of bytes in [Self::remainder_word].
615
+ remainder_len : WordBytes ,
616
+ }
617
+
618
+
619
+ #[generate_trait]
620
+ pub impl ByteSpanImpl of ByteSpanTrait {
621
+ /// Returns the length of the `ByteSpan`.
622
+ ///
623
+ /// # Examples
624
+ ///
625
+ /// ```
626
+ /// let ba: ByteArray = "byte array";
627
+ /// let span = ba.span();
628
+ /// let len = span.len();
629
+ /// assert!(len == 10);
630
+ /// ```
631
+ #[must_use]
632
+ fn len (self : ByteSpan ) -> usize {
633
+ downcast (calc_bytespan_len (self )). unwrap ()
634
+ }
635
+
636
+ /// Returns `true` if the `ByteSpan` has a length of 0.
637
+ ///
638
+ /// # Examples
639
+ ///
640
+ /// ```
641
+ /// let ba: ByteArray = "";
642
+ /// let span = ba.span();
643
+ /// assert!(span.is_empty());
644
+ ///
645
+ /// let ba2: ByteArray = "not empty";
646
+ /// let span2 = ba2.span();
647
+ /// assert!(!span2.is_empty());
648
+ /// ```
649
+ fn is_empty (self : ByteSpan ) -> bool {
650
+ self . remainder_len == 0 && self . data. len () == 0
651
+ }
652
+ }
653
+
654
+ /// Trait for types that can be converted into a `ByteSpan`.
655
+ pub trait ToByteSpanTrait <C > {
656
+ #[must_use]
657
+ fn span (self : @ C ) -> ByteSpan ;
658
+ }
659
+
660
+ impl ByteArrayToByteSpan of ToByteSpanTrait <ByteArray > {
661
+ fn span (self : @ ByteArray ) -> ByteSpan {
662
+ ByteSpan {
663
+ data : self . data. span (),
664
+ first_char_start_offset : 0 ,
665
+ remainder_word : * self . pending_word,
666
+ remainder_len : downcast (self . pending_word_len). expect (' In [0,30] by assumption' ),
667
+ }
668
+ }
669
+ }
670
+
671
+ impl ByteSpanToByteSpan of ToByteSpanTrait <ByteSpan > {
672
+ fn span (self : @ ByteSpan ) -> ByteSpan {
673
+ * self
674
+ }
675
+ }
676
+
677
+ mod helpers {
678
+ use core :: num :: traits :: Bounded ;
679
+ use crate :: bytes_31 :: BYTES_IN_BYTES31 ;
680
+ #[feature(" bounded-int-utils" )]
681
+ use crate :: internal :: bounded_int :: {
682
+ self, AddHelper , BoundedInt , MulHelper , SubHelper , UnitInt , downcast,
683
+ };
684
+ use super :: {BYTES_IN_BYTES31_MINUS_ONE , ByteSpan , WordBytes };
685
+
686
+ type BytesInBytes31Typed = UnitInt <{ BYTES_IN_BYTES31 . into() }>;
687
+
688
+ const U32_MAX_TIMES_B31 : felt252 = Bounded :: <u32 >:: MAX . into () * BYTES_IN_BYTES31 . into ();
689
+ const BYTES_IN_BYTES31_UNIT_INT : BytesInBytes31Typed = downcast (BYTES_IN_BYTES31 ). unwrap ();
690
+
691
+ impl U32ByB31 of MulHelper <u32 , BytesInBytes31Typed > {
692
+ type Result = BoundedInt <0 , { U32_MAX_TIMES_B31 }>;
693
+ }
694
+
695
+ impl B30AddU32ByB31 of AddHelper <WordBytes , U32ByB31 :: Result > {
696
+ type Result = BoundedInt <0 , { BYTES_IN_BYTES31_MINUS_ONE . into() + U32_MAX_TIMES_B31 }>;
697
+ }
698
+
699
+ impl B30AddU32ByB31SubB30 of SubHelper <B30AddU32ByB31 :: Result , WordBytes > {
700
+ type Result =
701
+ BoundedInt <
702
+ { - BYTES_IN_BYTES31_MINUS_ONE . into() },
703
+ { BYTES_IN_BYTES31_MINUS_ONE . into() + U32_MAX_TIMES_B31 },
704
+ >;
705
+ }
706
+
707
+ pub fn calc_bytespan_len (span : ByteSpan ) -> B30AddU32ByB31SubB30 :: Result {
708
+ let data_bytes = bounded_int :: mul (span . data. len (), BYTES_IN_BYTES31_UNIT_INT );
709
+ let span_bytes_unadjusted = bounded_int :: add (span . remainder_len, data_bytes );
710
+ let span_bytes = bounded_int :: sub (span_bytes_unadjusted , span . first_char_start_offset);
711
+ span_bytes
712
+ }
713
+ }
714
+ use helpers :: calc_bytespan_len;
0 commit comments