Skip to content

Commit 055a0e3

Browse files
author
Gilad Chase
committed
feat(byte_array): add ByteSpan::into and bytes31_slice
When slicing bytespans, the first data word can have a start-offset, this has to be split-off before casting into `ByteArray`, which has no concept of start-offset of a bytes31 word. Note: when slicing bytespans that are included in `remainder_word`, the upcoming `slice` logic will remove the start-offset while slicing (for simplicity and consistency), hence we only need to split off the start-offset if the first word is in the data span.
1 parent 4dff15c commit 055a0e3

File tree

2 files changed

+59
-3
lines changed

2 files changed

+59
-3
lines changed

corelib/src/byte_array.cairo

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
//! ```
4444

4545
use crate::array::{ArrayTrait, Span, SpanTrait};
46+
use crate::bytes_31::split_bytes31;
4647
#[allow(unused_imports)]
4748
use crate::bytes_31::{
4849
BYTES_IN_BYTES31, Bytes31Trait, POW_2_128, POW_2_8, U128IntoBytes31, U8IntoBytes31,
@@ -648,6 +649,14 @@ pub impl ByteArraySpanImpl of ByteSpanTrait {
648649
}
649650
}
650651

652+
impl ByteSpanDefault of Default<ByteSpan> {
653+
fn default() -> ByteSpan {
654+
ByteSpan {
655+
data: [].span(), first_char_start_offset: 0, remainder_word: 0, remainder_len: 0,
656+
}
657+
}
658+
}
659+
651660
pub trait ToByteSpanTrait<C> {
652661
#[must_use]
653662
fn span(self: @C) -> ByteSpan;
@@ -669,3 +678,30 @@ impl ByteSpanToByteSpan of ToByteSpanTrait<ByteSpan> {
669678
*self
670679
}
671680
}
681+
682+
impl ByteSpanIntoByteArray of Into<ByteSpan, ByteArray> {
683+
fn into(mut self: ByteSpan) -> ByteArray {
684+
// Span is aligned to word boundaries.
685+
// Note: byte-spans smaller than 31 bytes trim off their start-offset when sliced.
686+
if self.first_char_start_offset == 0 || self.data.is_empty() {
687+
return ByteArray {
688+
data: self.data.into(),
689+
pending_word: self.remainder_word,
690+
pending_word_len: upcast(self.remainder_len),
691+
};
692+
}
693+
694+
let mut ba = Default::default();
695+
// Remove the start offset from the first data word.
696+
let first_word = self.data.pop_front().expect('data non-empty checked above');
697+
let n_bytes_to_append = BYTES_IN_BYTES31 - upcast(self.first_char_start_offset);
698+
let (first_word_no_offset, _) = split_bytes31(
699+
(*first_word).into(), BYTES_IN_BYTES31, n_bytes_to_append,
700+
);
701+
ba.append_word(first_word_no_offset, n_bytes_to_append);
702+
703+
ba.data.append_span(self.data); // Contains everything after the first word.
704+
ba.append_word(self.remainder_word, upcast(self.remainder_len));
705+
ba
706+
}
707+
}

corelib/src/test/byte_array_test.cairo

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -546,9 +546,29 @@ fn test_span_copy() {
546546

547547
let other_span = span;
548548
assert_eq!(other_span.len(), 2);
549+
assert_eq!(ba, span.into());
550+
549551
let span_again = span.span();
550-
assert_eq!(span_again.len(), span.len());
552+
assert_eq!(ba, span_again.into());
553+
assert_eq!(ba, span.into());
554+
551555
let even_more_span_again = other_span.span();
552-
assert_eq!(even_more_span_again.len(), other_span.len());
553-
// TODO(giladchase): verify span content once we add `into` or `PartialEq`.
556+
assert_eq!(ba, even_more_span_again.into());
557+
assert_eq!(ba, other_span.into());
558+
assert_eq!(ba, span.into());
559+
}
560+
561+
#[test]
562+
fn test_span_into_bytearray() {
563+
let empty_ba: ByteArray = "";
564+
assert_eq!(empty_ba.span().into(), empty_ba);
565+
566+
// Only remainder.
567+
let small_ba: ByteArray = "hello";
568+
assert_eq!(small_ba.span().into(), small_ba);
569+
570+
// Data word and remainder.
571+
let large_ba: ByteArray = "0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVW"; // 40 bytes
572+
assert_eq!(large_ba.span().into(), large_ba);
573+
// TODO(giladchase): test with slice.
554574
}

0 commit comments

Comments
 (0)