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,130 @@ 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+ #[unstable(feature: " byte-span" )]
657+ pub trait ToByteSpanTrait <C > {
658+ #[must_use]
659+ /// Create a `ByteSpan` view object for the given type.
660+ fn span (self : @ C ) -> ByteSpan ;
661+ }
662+
663+ #[feature(" byte-span" )]
664+ impl ByteArrayToByteSpan of ToByteSpanTrait <ByteArray > {
665+ fn span (self : @ ByteArray ) -> ByteSpan {
666+ ByteSpan {
667+ data : self . data. span (),
668+ first_char_start_offset : 0 ,
669+ remainder_word : * self . pending_word,
670+ remainder_len : downcast (self . pending_word_len). expect (' In [0,30] by assumption' ),
671+ }
672+ }
673+ }
674+
675+ #[feature(" byte-span" )]
676+ impl ByteSpanToByteSpan of ToByteSpanTrait <ByteSpan > {
677+ fn span (self : @ ByteSpan ) -> ByteSpan {
678+ * self
679+ }
680+ }
681+
682+ mod helpers {
683+ use core :: num :: traits :: Bounded ;
684+ use crate :: bytes_31 :: BYTES_IN_BYTES31 ;
685+ #[feature(" bounded-int-utils" )]
686+ use crate :: internal :: bounded_int :: {
687+ self, AddHelper , BoundedInt , MulHelper , SubHelper , UnitInt , downcast,
688+ };
689+ use super :: {BYTES_IN_BYTES31_MINUS_ONE , ByteSpan , Bytes31Index };
690+
691+ type BytesInBytes31Typed = UnitInt <{ BYTES_IN_BYTES31 . into() }>;
692+
693+ const U32_MAX_TIMES_B31 : felt252 = Bounded :: <u32 >:: MAX . into () * BYTES_IN_BYTES31 . into ();
694+ const BYTES_IN_BYTES31_UNIT_INT : BytesInBytes31Typed = downcast (BYTES_IN_BYTES31 ). unwrap ();
695+
696+ impl U32ByB31 of MulHelper <u32 , BytesInBytes31Typed > {
697+ type Result = BoundedInt <0 , U32_MAX_TIMES_B31 >;
698+ }
699+
700+ impl B30AddU32ByB31 of AddHelper <Bytes31Index , U32ByB31 :: Result > {
701+ type Result = BoundedInt <0 , { BYTES_IN_BYTES31_MINUS_ONE . into() + U32_MAX_TIMES_B31 }>;
702+ }
703+
704+ impl B30AddU32ByB31SubB30 of SubHelper <B30AddU32ByB31 :: Result , Bytes31Index > {
705+ type Result =
706+ BoundedInt <
707+ { - BYTES_IN_BYTES31_MINUS_ONE . into() },
708+ { BYTES_IN_BYTES31_MINUS_ONE . into() + U32_MAX_TIMES_B31 },
709+ >;
710+ }
711+
712+ /// Calculates the length of a `ByteSpan` in bytes.
713+ pub fn calc_bytespan_len (span : ByteSpan ) -> usize {
714+ let data_bytes = bounded_int :: mul (span . data. len (), BYTES_IN_BYTES31_UNIT_INT );
715+ let span_bytes_unadjusted = bounded_int :: add (span . remainder_len, data_bytes );
716+ let span_bytes = bounded_int :: sub (span_bytes_unadjusted , span . first_char_start_offset);
717+
718+ downcast (span_bytes ). unwrap ()
719+ }
720+ }
0 commit comments