Skip to content

Commit

Permalink
feat: from_array for List (#183)
Browse files Browse the repository at this point in the history
## Pull Request type

Please check the type of change your PR introduces:

- [ ] Bugfix
- [x] Feature
- [ ] Code style update (formatting, renaming)
- [ ] Refactoring (no functional changes, no API changes)
- [ ] Build-related changes
- [ ] Documentation content changes
- [ ] Other (please describe):

## What is the current behavior?

Issue Number:
[#158](#158)

## What is the new behavior?

- Added the `from_array` method for `ListTrait`
- Added the corresponding unit tests

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

## Other information

The implementation is very similar to the `append` function except that
it sets the length only once.

There's one question still, what should happen when you call the
function with an empty list, like
```rust
lst.from_array(array![]);
```
For my current implementation it "cleans" the list (basically set the
length to zero) but maybe this is not what we want. Let me know! 😁

---------

Co-authored-by: akhercha <[email protected]>
  • Loading branch information
akhercha and akhercha authored Oct 4, 2023
1 parent 92c3c1b commit 95bad63
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 0 deletions.
26 changes: 26 additions & 0 deletions src/storage/src/list.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ trait ListTrait<T> {
fn clean(ref self: List<T>);
fn pop_front(ref self: List<T>) -> Option<T>;
fn array(self: @List<T>) -> Array<T>;
fn from_array(ref self: List<T>, array: @Array<T>);
fn from_span(ref self: List<T>, span: Span<T>);
}

impl ListImpl<T, impl TCopy: Copy<T>, impl TDrop: Drop<T>, impl TStore: Store<T>> of ListTrait<T> {
Expand Down Expand Up @@ -104,6 +106,30 @@ impl ListImpl<T, impl TCopy: Copy<T>, impl TDrop: Drop<T>, impl TStore: Store<T>
};
array
}

fn from_array(ref self: List<T>, array: @Array<T>) {
self.from_span(array.span());
}

fn from_span(ref self: List<T>, mut span: Span<T>) {
let mut index = 0;
self.len = span.len();
loop {
match span.pop_front() {
Option::Some(v) => {
let (base, offset) = calculate_base_and_offset_for_index(
self.base, index, self.storage_size
);
Store::write_at_offset(self.address_domain, base, offset, *v).unwrap_syscall();
index += 1;
},
Option::None => {
break;
}
};
};
Store::write(self.address_domain, self.base, self.len);
}
}

impl AListIndexViewImpl<
Expand Down
53 changes: 53 additions & 0 deletions src/storage/src/tests/list_test.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ trait IAListHolder<TContractState> {
fn do_clean(ref self: TContractState);
fn do_pop_front(ref self: TContractState) -> (Option<ContractAddress>, Option<u256>);
fn do_array(self: @TContractState) -> (Array<ContractAddress>, Array<u256>);
fn do_from_array(
ref self: TContractState, addrs_array: Array<ContractAddress>, numbers_array: Array<u256>
);
}

#[starknet::contract]
Expand Down Expand Up @@ -86,6 +89,15 @@ mod AListHolder {
let mut n = self.numbers.read();
(a.array(), n.array())
}

fn do_from_array(
ref self: ContractState, addrs_array: Array<ContractAddress>, numbers_array: Array<u256>
) {
let mut a = self.addrs.read();
let mut n = self.numbers.read();
a.from_array(@addrs_array);
n.from_array(@numbers_array);
}
}
}

Expand Down Expand Up @@ -415,4 +427,45 @@ mod tests {
assert(addr.is_none(), 'addr is none');
assert(number.is_none(), 'number is none');
}

#[test]
#[available_gas(100000000)]
fn test_from_array() {
let contract = deploy_mock();
let mock_addr = mock_addr();

let addrs_array = array![mock_addr, mock_addr, mock_addr];
let numbers_array = array![200, 300, 100];
contract.do_from_array(addrs_array, numbers_array);
assert(contract.do_get_len() == (3, 3), 'len should be 3');
assert(contract.do_get_index(0) == (mock_addr, 200), 'idx 0');
assert(contract.do_get_index(1) == (mock_addr, 300), 'idx 1');
assert(contract.do_get_index(2) == (mock_addr, 100), 'idx 2');
}

#[test]
#[available_gas(100000000)]
fn test_from_array_empty() {
let contract = deploy_mock();

contract.do_from_array(array![], array![]);
assert(contract.do_is_empty() == (true, true), 'should be empty');
}

#[test]
#[available_gas(100000000)]
fn test_from_array_remove_elements() {
let contract = deploy_mock();
let mock_addr = mock_addr();

assert(contract.do_append(mock_addr, 10) == (0, 0), '1st append idx');
assert(contract.do_append(mock_addr, 20) == (1, 1), '2nd append idx');
assert(contract.do_get_len() == (2, 2), 'len');
assert(contract.do_get_index(0) == (mock_addr, 10), 'idx 0');
assert(contract.do_get_index(1) == (mock_addr, 20), 'idx 1');

contract.do_from_array(array![], array![]);
let (a, b) = contract.do_get_len();
assert(contract.do_is_empty() == (true, true), 'should be empty');
}
}

0 comments on commit 95bad63

Please sign in to comment.