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 Bytes31Index = 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,130 @@ 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 : 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