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 Bytes31Index = 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,125 @@ 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 : Bytes31Index ,
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 : Bytes31Index ,
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+ // No need to check offsets: when `slice` consumes the span it returns `Default::default()`.
651+ self . remainder_len == 0 && self . data. len () == 0
652+ }
653+ }
654+
655+ /// Trait for types that can be converted into a `ByteSpan`.
656+ pub trait ToByteSpanTrait <C > {
657+ #[must_use]
658+ fn span (self : @ C ) -> ByteSpan ;
659+ }
660+
661+ impl ByteArrayToByteSpan of ToByteSpanTrait <ByteArray > {
662+ fn span (self : @ ByteArray ) -> ByteSpan {
663+ ByteSpan {
664+ data : self . data. span (),
665+ first_char_start_offset : 0 ,
666+ remainder_word : * self . pending_word,
667+ remainder_len : downcast (self . pending_word_len). expect (' In [0,30] by assumption' ),
668+ }
669+ }
670+ }
671+
672+ impl ByteSpanToByteSpan of ToByteSpanTrait <ByteSpan > {
673+ fn span (self : @ ByteSpan ) -> ByteSpan {
674+ * self
675+ }
676+ }
677+
678+ mod helpers {
679+ use core :: num :: traits :: Bounded ;
680+ use crate :: bytes_31 :: BYTES_IN_BYTES31 ;
681+ #[feature(" bounded-int-utils" )]
682+ use crate :: internal :: bounded_int :: {
683+ self, AddHelper , BoundedInt , MulHelper , SubHelper , UnitInt , downcast,
684+ };
685+ use super :: {BYTES_IN_BYTES31_MINUS_ONE , ByteSpan , Bytes31Index };
686+
687+ type BytesInBytes31Typed = UnitInt <{ BYTES_IN_BYTES31 . into() }>;
688+
689+ const U32_MAX_TIMES_B31 : felt252 = Bounded :: <u32 >:: MAX . into () * BYTES_IN_BYTES31 . into ();
690+ const BYTES_IN_BYTES31_UNIT_INT : BytesInBytes31Typed = downcast (BYTES_IN_BYTES31 ). unwrap ();
691+
692+ impl U32ByB31 of MulHelper <u32 , BytesInBytes31Typed > {
693+ type Result = BoundedInt <0 , U32_MAX_TIMES_B31 >;
694+ }
695+
696+ impl B30AddU32ByB31 of AddHelper <Bytes31Index , U32ByB31 :: Result > {
697+ type Result = BoundedInt <0 , { BYTES_IN_BYTES31_MINUS_ONE . into() + U32_MAX_TIMES_B31 }>;
698+ }
699+
700+ impl B30AddU32ByB31SubB30 of SubHelper <B30AddU32ByB31 :: Result , Bytes31Index > {
701+ type Result =
702+ BoundedInt <
703+ { - BYTES_IN_BYTES31_MINUS_ONE . into() },
704+ { BYTES_IN_BYTES31_MINUS_ONE . into() + U32_MAX_TIMES_B31 },
705+ >;
706+ }
707+
708+ pub fn calc_bytespan_len (span : ByteSpan ) -> usize {
709+ let data_bytes = bounded_int :: mul (span . data. len (), BYTES_IN_BYTES31_UNIT_INT );
710+ let span_bytes_unadjusted = bounded_int :: add (span . remainder_len, data_bytes );
711+ let span_bytes = bounded_int :: sub (span_bytes_unadjusted , span . first_char_start_offset);
712+
713+ downcast (span_bytes ). unwrap ()
714+ }
715+ }
0 commit comments