4242// ! assert!(first_byte == 0x41);
4343// ! ```
4444
45- use crate :: array :: {ArrayTrait , SpanTrait };
45+ use crate :: array :: {ArrayTrait , Span , SpanTrait };
4646#[allow(unused_imports)]
4747use crate :: bytes_31 :: {
4848 BYTES_IN_BYTES31 , Bytes31Trait , POW_2_128 , POW_2_8 , U128IntoBytes31 , U8IntoBytes31 ,
@@ -52,12 +52,17 @@ use crate::clone::Clone;
5252use crate :: cmp :: min;
5353#[allow(unused_imports)]
5454use crate :: integer :: {U32TryIntoNonZero , u128_safe_divmod};
55+ #[feature(" bounded-int-utils" )]
56+ use crate :: internal :: bounded_int :: {BoundedInt , downcast};
5557#[allow(unused_imports)]
5658use crate :: serde :: Serde ;
5759use crate :: traits :: {Into , TryInto };
5860#[allow(unused_imports)]
5961use crate :: zeroable :: NonZeroIntoImpl ;
6062
63+ /// The number of bytes in [`ByteArray::pending_word`].
64+ type WordBytes = BoundedInt <0 , { BYTES_IN_BYTES31_MINUS_ONE . into() }>;
65+
6166/// A magic constant for identifying serialization of `ByteArray` variables. An array of `felt252`
6267/// with this magic value as one of the `felt252` indicates that you should expect right after it a
6368/// serialized `ByteArray`. This is currently used mainly for prints and panics.
@@ -586,3 +591,127 @@ impl ByteArrayFromIterator of crate::iter::FromIterator<ByteArray, u8> {
586591 ba
587592 }
588593}
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+ helpers :: calc_bytespan_len (self )
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+ // If the span's last word isn't aligned to a bytes31 boundary, it's in `remainder_word` and
651+ // `remainder_len > 0`, otherwise it's in the `data` array, implying that it's size is
652+ // nonzero.
653+ self . remainder_len == 0 && self . data. len () == 0
654+ }
655+ }
656+
657+ /// Trait for types that can be converted into a `ByteSpan`.
658+ pub trait ToByteSpanTrait <C > {
659+ #[must_use]
660+ fn span (self : @ C ) -> ByteSpan ;
661+ }
662+
663+ impl ByteArrayToByteSpan of ToByteSpanTrait <ByteArray > {
664+ fn span (self : @ ByteArray ) -> ByteSpan {
665+ ByteSpan {
666+ data : self . data. span (),
667+ first_char_start_offset : 0 ,
668+ remainder_word : * self . pending_word,
669+ remainder_len : downcast (self . pending_word_len). expect (' In [0,30] by assumption' ),
670+ }
671+ }
672+ }
673+
674+ impl ByteSpanToByteSpan of ToByteSpanTrait <ByteSpan > {
675+ fn span (self : @ ByteSpan ) -> ByteSpan {
676+ * self
677+ }
678+ }
679+
680+ mod helpers {
681+ use core :: num :: traits :: Bounded ;
682+ use crate :: bytes_31 :: BYTES_IN_BYTES31 ;
683+ #[feature(" bounded-int-utils" )]
684+ use crate :: internal :: bounded_int :: {
685+ self, AddHelper , BoundedInt , MulHelper , SubHelper , UnitInt , downcast,
686+ };
687+ use super :: {BYTES_IN_BYTES31_MINUS_ONE , ByteSpan , WordBytes };
688+
689+ type BytesInBytes31Typed = UnitInt <{ BYTES_IN_BYTES31 . into() }>;
690+
691+ const U32_MAX_TIMES_B31 : felt252 = Bounded :: <u32 >:: MAX . into () * BYTES_IN_BYTES31 . into ();
692+ const BYTES_IN_BYTES31_UNIT_INT : BytesInBytes31Typed = downcast (BYTES_IN_BYTES31 ). unwrap ();
693+
694+ impl U32ByB31 of MulHelper <u32 , BytesInBytes31Typed > {
695+ type Result = BoundedInt <0 , U32_MAX_TIMES_B31 >;
696+ }
697+
698+ impl B30AddU32ByB31 of AddHelper <WordBytes , U32ByB31 :: Result > {
699+ type Result = BoundedInt <0 , { BYTES_IN_BYTES31_MINUS_ONE . into() + U32_MAX_TIMES_B31 }>;
700+ }
701+
702+ impl B30AddU32ByB31SubB30 of SubHelper <B30AddU32ByB31 :: Result , WordBytes > {
703+ type Result =
704+ BoundedInt <
705+ { - BYTES_IN_BYTES31_MINUS_ONE . into() },
706+ { BYTES_IN_BYTES31_MINUS_ONE . into() + U32_MAX_TIMES_B31 },
707+ >;
708+ }
709+
710+ pub fn calc_bytespan_len (span : ByteSpan ) -> usize {
711+ let data_bytes = bounded_int :: mul (span . data. len (), BYTES_IN_BYTES31_UNIT_INT );
712+ let span_bytes_unadjusted = bounded_int :: add (span . remainder_len, data_bytes );
713+ let span_bytes = bounded_int :: sub (span_bytes_unadjusted , span . first_char_start_offset);
714+
715+ downcast (span_bytes ). unwrap ()
716+ }
717+ }
0 commit comments