Skip to content

Commit

Permalink
High level support and testsing for span-to-fixed-sized array. (#5583)
Browse files Browse the repository at this point in the history
  • Loading branch information
orizi committed May 21, 2024
1 parent 07f1c0d commit bde5f45
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 0 deletions.
26 changes: 26 additions & 0 deletions corelib/src/array.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,32 @@ impl EmptyFixedSizeArrayImpl<T, +Drop<T>> of ToSpanTrait<[T; 0], T> {
}
}

/// Returns a box of struct of members of the same type from a span.
/// The additional `+Copy<@T>` arg is to prevent later stages from propagating the `S` type Sierra
/// level, where it is deduced by the `T` type.
extern fn tuple_from_span<T, +Copy<@T>, S>(span: @Array<S>) -> Option<@Box<T>> nopanic;

/// Implements `TryInto` for only copyable types
impl SpanTryIntoFixedSizedArray<
T, const SIZE: usize, -TypeEqual<[T; SIZE], [T; 0]>
> of TryInto<Span<T>, @Box<[T; SIZE]>> {
#[inline(always)]
fn try_into(self: Span<T>) -> Option<@Box<[T; SIZE]>> {
tuple_from_span(self.snapshot)
}
}

impl SpanTryIntoEmptyFixedSizedArray<T, +Drop<T>> of TryInto<Span<T>, @Box<[T; 0]>> {
#[inline(always)]
fn try_into(self: Span<T>) -> Option<@Box<[T; 0]>> {
if self.is_empty() {
Option::Some(@BoxTrait::new([]))
} else {
Option::None
}
}
}

// TODO(spapini): Remove TDrop. It is necessary to get rid of response in case of panic.
impl ArrayTCloneImpl<T, +Clone<T>, +Drop<T>> of Clone<Array<T>> {
fn clone(self: @Array<T>) -> Array<T> {
Expand Down
17 changes: 17 additions & 0 deletions corelib/src/test/array_test.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,20 @@ fn test_fixed_size_array_copy() {
consume(arr);
consume(arr);
}

/// Helper for tests removing the box wrapping a fixed sized array wrapped by an option.
fn debox<T, const SIZE: usize>(value: Option<@Box<[T; SIZE]>>) -> Option<@[T; SIZE]> {
Option::Some(value?.as_snapshot().unbox())
}

#[test]
fn test_span_into_fixed_size_array() {
assert!(debox::<felt252, 2>([10, 11, 12].span().try_into()).is_none());
assert!(debox::<felt252, 3>([10, 11, 12].span().try_into()) == Option::Some(@[10, 11, 12]));
assert!(debox::<felt252, 4>([10, 11, 12].span().try_into()).is_none());
assert!(debox::<u256, 2>([10, 11, 12].span().try_into()).is_none());
assert!(debox::<u256, 3>([10, 11, 12].span().try_into()) == Option::Some(@[10, 11, 12]));
assert!(debox::<u256, 4>([10, 11, 12].span().try_into()).is_none());
assert!(debox::<felt252, 1>([].span().try_into()).is_none());
assert!(debox::<felt252, 0>([].span().try_into()) == Option::Some(@[]));
}
38 changes: 38 additions & 0 deletions corelib/src/traits.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -296,3 +296,41 @@ impl TupleSize4Default<

impl FixedSizedArrayDrop<T, +Drop<T>, const N: u32> of Drop<[T; N]>;
impl FixedSizedArrayCopy<T, +Copy<T>, const N: u32> of Copy<[T; N]>;

impl FixedSizedArraySize0PartialEq<T, +PartialEq<T>> of PartialEq<[T; 0]> {
fn eq(lhs: @[T; 0], rhs: @[T; 0]) -> bool {
true
}
}

impl FixedSizedArraySize1PartialEq<T, +PartialEq<T>> of PartialEq<[T; 1]> {
fn eq(lhs: @[T; 1], rhs: @[T; 1]) -> bool {
let [lhs] = lhs;
let [rhs] = rhs;
rhs == lhs
}
}

impl FixedSizedArraySize2PartialEq<T, +PartialEq<T>> of PartialEq<[T; 2]> {
fn eq(lhs: @[T; 2], rhs: @[T; 2]) -> bool {
let [lhs0, lhs1] = lhs;
let [rhs0, rhs1] = rhs;
(lhs0, lhs1) == (rhs0, rhs1)
}
}

impl FixedSizedArraySize3PartialEq<T, +PartialEq<T>> of PartialEq<[T; 3]> {
fn eq(lhs: @[T; 3], rhs: @[T; 3]) -> bool {
let [lhs0, lhs1, lhs2] = lhs;
let [rhs0, rhs1, rhs2] = rhs;
(lhs0, lhs1, lhs2) == (rhs0, rhs1, rhs2)
}
}

impl FixedSizedArraySize4PartialEq<T, +PartialEq<T>> of PartialEq<[T; 4]> {
fn eq(lhs: @[T; 4], rhs: @[T; 4]) -> bool {
let [lhs0, lhs1, lhs2, lhs3] = lhs;
let [rhs0, rhs1, rhs2, rhs3] = rhs;
(lhs0, lhs1, lhs2, lhs3) == (rhs0, rhs1, rhs2, rhs3)
}
}

0 comments on commit bde5f45

Please sign in to comment.