Skip to content

Commit 3ba3ba2

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 d8c0e8b commit 3ba3ba2

File tree

2 files changed

+55
-1
lines changed

2 files changed

+55
-1
lines changed

corelib/src/byte_array.cairo

Lines changed: 39 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,
@@ -624,6 +625,17 @@ pub impl ByteArraySpanImpl of ByteSpanTrait {
624625
}
625626
}
626627

628+
impl ByteSpanDefault of Default<ByteSpan> {
629+
fn default() -> ByteSpan {
630+
ByteSpan {
631+
data: [].span(),
632+
first_char_start_offset: downcast(0).unwrap(),
633+
remainder_word: 0,
634+
remainder_len: downcast(0).unwrap(),
635+
}
636+
}
637+
}
638+
627639
pub trait ToByteSpanTrait<C> {
628640
#[must_use]
629641
fn span(self: @C) -> ByteSpan;
@@ -639,3 +651,30 @@ impl ByteArrayToByteSpan of ToByteSpanTrait<ByteArray> {
639651
}
640652
}
641653
}
654+
655+
impl ByteSpanIntoByteArray of Into<ByteSpan, ByteArray> {
656+
fn into(mut self: ByteSpan) -> ByteArray {
657+
let start_offset = upcast(self.first_char_start_offset);
658+
// Span is aligned to word boundaries.
659+
if start_offset == 0 || self.data.is_empty() {
660+
return ByteArray {
661+
data: self.data.into(),
662+
pending_word: self.remainder_word,
663+
pending_word_len: upcast(self.remainder_len),
664+
};
665+
}
666+
667+
let mut ba = Default::default();
668+
// Remove the start offset from the first data word.
669+
let first_word = self.data.pop_front().expect('data non-empty checked above');
670+
let n_bytes_to_append = BYTES_IN_BYTES31 - start_offset;
671+
let (first_word_no_offset, _) = split_bytes31(
672+
(*first_word).into(), BYTES_IN_BYTES31, n_bytes_to_append,
673+
);
674+
ba.append_word(first_word_no_offset, n_bytes_to_append);
675+
676+
ba.data.append_span(self.data); // Contains everything after the first word.
677+
ba.append_word(self.remainder_word, upcast(self.remainder_len));
678+
ba
679+
}
680+
}

corelib/src/test/byte_array_test.cairo

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -546,5 +546,20 @@ fn test_span_copy() {
546546

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

0 commit comments

Comments
 (0)