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,19 +52,25 @@ 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, upcast};
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
64
+ pub type WordBytes = BoundedInt <0 , BYTES_IN_BYTES31_MINUS_ONE_FELT >;
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.
64
69
pub const BYTE_ARRAY_MAGIC : felt252 =
65
70
0x46a6158a16a947e5916b2a2ca68501a45e93d7110e81aa2d6438b1c57c879a3 ;
66
71
const BYTES_IN_U128 : usize = 16 ;
67
72
const BYTES_IN_BYTES31_MINUS_ONE : usize = BYTES_IN_BYTES31 - 1 ;
73
+ const BYTES_IN_BYTES31_MINUS_ONE_FELT : felt252 = BYTES_IN_BYTES31_MINUS_ONE . into ();
68
74
const BYTES_IN_BYTES31_NONZERO : NonZero <usize > = 31 ;
69
75
70
76
// TODO(yuval): don't allow creation of invalid ByteArray?
@@ -586,3 +592,84 @@ impl ByteArrayFromIterator of crate::iter::FromIterator<ByteArray, u8> {
586
592
ba
587
593
}
588
594
}
595
+
596
+ /// A view into a contiguous collection of a string type.
597
+ /// Currently implemented only for `ByteArray`, but will soon be implemented for other string types.
598
+ /// `Span` implements the `Copy` and the `Drop` traits.
599
+ #[derive(Copy , Drop )]
600
+ pub struct ByteSpan {
601
+ /// A span representing the array of all `bytes31` words in the byte-span, excluding the last
602
+ /// bytes_31 word that is stored in [Self::last_word].
603
+ /// Invariant: every byte stored in `data` is part of the span except for the bytes appearing
604
+ /// before `first_char_start_offset` in the first word.
605
+ data : Span <bytes31 >,
606
+ /// The offset of the first character in the first entry of [Self::data], for use in span
607
+ /// slices. When data is empty, this offset applies to remainder_word instead.
608
+ first_char_start_offset : WordBytes ,
609
+ /// Contains the final bytes of the span when the end is either not in memory or isn't aligned
610
+ /// to a word boundary.
611
+ /// It is represented as a `felt252` to improve performance of building the byte array, but
612
+ /// represents a `bytes31`.
613
+ /// The first byte is the most significant byte among the `pending_word_len` bytes in the word.
614
+ remainder_word : felt252 ,
615
+ /// The number of bytes in [Self::remainder_word].
616
+ remainder_len : WordBytes ,
617
+ }
618
+
619
+ #[generate_trait]
620
+ pub impl ByteArraySpanImpl 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
+ let data_bytes = self . data. len () * BYTES_IN_BYTES31 ;
634
+ data_bytes + upcast (self . remainder_len) - upcast (self . first_char_start_offset)
635
+ }
636
+
637
+ /// Returns `true` if the `ByteSpan` has a length of 0.
638
+ ///
639
+ /// # Examples
640
+ ///
641
+ /// ```
642
+ /// let ba: ByteArray = "";
643
+ /// let span = ba.span();
644
+ /// assert!(span.is_empty());
645
+ ///
646
+ /// let ba2: ByteArray = "not empty";
647
+ /// let span2 = ba2.span();
648
+ /// assert!(!span2.is_empty());
649
+ /// ```
650
+ fn is_empty (self : @ ByteSpan ) -> bool {
651
+ self . data. len () == 0 && * self . remainder_len == 0
652
+ }
653
+ }
654
+
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
+ }
0 commit comments