Skip to content

Commit dfc0b07

Browse files
authored
Storage Vector New Methods (#4174)
## Description > Note: > Part 3 of 3 breakout of PR #3935 > Blocked by PR's #4171 and #4172 This PR introduces six new methods for `StorageVec`: 1. `swap` 2. `first` 3. `last` 4. `reverse` 5. `fill` 6. `resize` ## Checklist - [✅] I have linked to any relevant issues. - [✅] I have commented my code, particularly in hard-to-understand areas. - [✅] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [✅] I have added tests that prove my fix is effective or that my feature works. - [✅] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [✅] I have done my best to ensure that my PR adheres to [the Fuel Labs Code Review Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md). - [✅] I have requested a review from the relevant team or maintainers.
1 parent 31dc809 commit dfc0b07

File tree

13 files changed

+995
-0
lines changed

13 files changed

+995
-0
lines changed

sway-lib-std/src/storage.sw

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,256 @@ impl<V> StorageVec<V> {
794794
pub fn clear(self) {
795795
let _ = clear::<u64>(__get_storage_key());
796796
}
797+
798+
/// Swaps two elements.
799+
///
800+
/// ### Arguments
801+
///
802+
/// * element1_index - The index of the first element.
803+
/// * element2_index - The index of the second element.
804+
///
805+
/// ### Reverts
806+
///
807+
/// * If `element1_index` or `element2_index` is greater than the length of the vector.
808+
///
809+
/// ### Number of Storage Accesses
810+
///
811+
/// * Reads: `3`
812+
/// * Writes: `2`
813+
///
814+
/// ### Examples
815+
///
816+
/// ```sway
817+
/// use std::storage::StorageVec;
818+
///
819+
/// storage {
820+
/// vec: StorageVec<u64> = StorageVec {}
821+
/// }
822+
///
823+
/// fn foo() {
824+
/// storage.vec.push(5);
825+
/// storage.vec.push(10);
826+
/// storage.vec.push(15);
827+
///
828+
/// storage.vec.swap(0, 2);
829+
/// assert(15 == storage.vec.get(0).unwrap());
830+
/// assert(10 == storage.vec.get(1).unwrap());
831+
/// assert(5 == storage.vec.get(2).unwrap());
832+
/// ```
833+
#[storage(read, write)]
834+
pub fn swap(self, element1_index: u64, element2_index: u64) {
835+
let len = get::<u64>(__get_storage_key()).unwrap_or(0);
836+
assert(element1_index < len);
837+
assert(element2_index < len);
838+
839+
if element1_index == element2_index {
840+
return;
841+
}
842+
843+
let element1_key = sha256((element1_index, __get_storage_key()));
844+
let element2_key = sha256((element2_index, __get_storage_key()));
845+
846+
let element1_value = get::<V>(element1_key).unwrap();
847+
store::<V>(element1_key, get::<V>(element2_key).unwrap());
848+
store::<V>(element2_key, element1_value);
849+
}
850+
851+
/// Returns the first element of the vector, or `None` if it is empty.
852+
///
853+
/// ### Number of Storage Accesses
854+
///
855+
/// * Reads: `2`
856+
///
857+
/// ### Examples
858+
///
859+
/// ```sway
860+
/// storage {
861+
/// vec: StorageVec<u64> = StorageVec {},
862+
/// }
863+
///
864+
/// fn foo() {
865+
/// assert(storage.vec.first().is_none());
866+
///
867+
/// storage.vec.push(5);
868+
///
869+
/// assert(5 == storage.vec.first().unwrwap());
870+
/// }
871+
/// ```
872+
#[storage(read)]
873+
pub fn first(self) -> Option<V> {
874+
match get::<u64>(__get_storage_key()).unwrap_or(0) {
875+
0 => Option::None,
876+
_ => get::<V>(sha256((0, __get_storage_key()))),
877+
}
878+
}
879+
880+
/// Returns the last element of the vector, or `None` if it is empty.
881+
///
882+
/// ### Number of Storage Accesses
883+
///
884+
/// * Reads: `2`
885+
///
886+
/// ### Examples
887+
///
888+
/// ```sway
889+
/// storage {
890+
/// vec: StorageVec<u64> = StorageVec {},
891+
/// }
892+
///
893+
/// fn foo() {
894+
/// assert(storage.vec.last().is_none());
895+
///
896+
/// storage.vec.push(5);
897+
/// storage.vec.push(10);
898+
///
899+
/// assert(10 == storage.vec.last().unwrap());
900+
/// }
901+
/// ```
902+
#[storage(read)]
903+
pub fn last(self) -> Option<V> {
904+
match get::<u64>(__get_storage_key()).unwrap_or(0) {
905+
0 => Option::None,
906+
len => get::<V>(sha256((len - 1, __get_storage_key()))),
907+
}
908+
}
909+
910+
/// Reverses the order of elements in the vector, in place.
911+
///
912+
/// ### Number of Storage Accesses
913+
///
914+
/// * Reads: `1 + (2 * (self.len() / 2))`
915+
/// * Writes: `2 * (self.len() / 2)`
916+
///
917+
/// ### Examples
918+
///
919+
/// ```sway
920+
/// storage {
921+
/// vec: StorageVec<u64> = StorageVec {},
922+
/// }
923+
///
924+
/// fn foo() {
925+
/// storage.vec.push(5);
926+
/// storage.vec.push(10);
927+
/// storage.vec.push(15);
928+
/// storage.vec.reverse();
929+
///
930+
/// assert(15 == storage.vec.get(0).unwrap());
931+
/// assert(10 == storage.vec.get(1).unwrap());
932+
/// assert(5 == storage.vec.get(2).unwrap());
933+
/// }
934+
/// ```
935+
#[storage(read, write)]
936+
pub fn reverse(self) {
937+
let len = get::<u64>(__get_storage_key()).unwrap_or(0);
938+
939+
if len < 2 {
940+
return;
941+
}
942+
943+
let mid = len / 2;
944+
let mut i = 0;
945+
while i < mid {
946+
let element1_key = sha256((i, __get_storage_key()));
947+
let element2_key = sha256((len - i - 1, __get_storage_key()));
948+
949+
let element1_value = get::<V>(element1_key).unwrap();
950+
store::<V>(element1_key, get::<V>(element2_key).unwrap());
951+
store::<V>(element2_key, element1_value);
952+
953+
i += 1;
954+
}
955+
}
956+
957+
/// Fills `self` with elements by cloning `value`.
958+
///
959+
/// ### Arguments
960+
///
961+
/// * value - Value to copy to each element of the vector.
962+
///
963+
/// ### Number of Storage Accesses
964+
///
965+
/// * Reads: `1`
966+
/// * Writes: `self.len()`
967+
///
968+
/// ### Examples
969+
///
970+
/// ```sway
971+
/// storage {
972+
/// vec: StorageVec<u64> = StorageVec {},
973+
/// }
974+
///
975+
/// fn foo() {
976+
/// storage.vec.push(5);
977+
/// storage.vec.push(10);
978+
/// storage.vec.push(15);
979+
/// storage.vec.fill(20);
980+
///
981+
/// assert(20 == storage.vec.get(0).unwrap());
982+
/// assert(20 == storage.vec.get(1).unwrap());
983+
/// assert(20 == storage.vec.get(2).unwrap());
984+
/// }
985+
/// ```
986+
#[storage(read, write)]
987+
pub fn fill(self, value: V) {
988+
let len = get::<u64>(__get_storage_key()).unwrap_or(0);
989+
990+
let mut i = 0;
991+
while i < len {
992+
store::<V>(sha256((i, __get_storage_key())), value);
993+
i += 1;
994+
}
995+
}
996+
997+
/// Resizes `self` in place so that `len` is equal to `new_len`.
998+
///
999+
/// If `new_len` is greater than `len`, `self` is extended by the difference, with each
1000+
/// additional slot being filled with `value`. If the `new_len` is less than `len`, `self` is
1001+
/// simply truncated.
1002+
///
1003+
/// ### Arguments
1004+
///
1005+
/// * new_len - The new length to expand or truncate to
1006+
/// * value - The value to fill into new slots if the `new_len` is greater than the current length
1007+
///
1008+
/// ### Number of Storage Accesses
1009+
///
1010+
/// * Reads - `1`
1011+
/// * Writes - `if new_len > self.len() { new_len - len + 1 } else { 1 }`
1012+
///
1013+
/// ### Examples
1014+
///
1015+
/// ```sway
1016+
/// storage {
1017+
/// vec: StorageVec<u64> = StorageVec {},
1018+
/// }
1019+
///
1020+
/// fn foo() {
1021+
/// storage.vec.push(5);
1022+
/// storage.vec.push(10);
1023+
/// storage.vec.resize(4, 20);
1024+
///
1025+
/// assert(5 == storage.vec.get(0).unwrap());
1026+
/// assert(10 == storage.vec.get(1).unwrap());
1027+
/// assert(20 == storage.vec.get(2).unwrap());
1028+
/// assert(20 == storage.vec.get(3).unwrap());
1029+
///
1030+
/// storage.vec.resize(2, 0);
1031+
///
1032+
/// assert(5 == storage.vec.get(0).unwrap());
1033+
/// assert(10 == storage.vec.get(1).unwrap());
1034+
/// assert(Option::None == storage.vec.get(2));
1035+
/// assert(Option::None == storage.vec.get(3));
1036+
/// }
1037+
/// ```
1038+
#[storage(read, write)]
1039+
pub fn resize(self, new_len: u64, value: V) {
1040+
let mut len = get::<u64>(__get_storage_key()).unwrap_or(0);
1041+
while len < new_len {
1042+
store::<V>(sha256((len, __get_storage_key())), value);
1043+
len += 1;
1044+
}
1045+
store::<u64>(__get_storage_key(), new_len);
1046+
}
7971047
}
7981048

7991049
pub struct StorageBytes {}

test/src/sdk-harness/test_artifacts/storage_vec/svec_array/src/main.sw

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,24 @@ abi MyContract {
3232

3333
#[storage(write)]
3434
fn clear();
35+
36+
#[storage(read, write)]
37+
fn swap(index_0: u64, index_1: u64);
38+
39+
#[storage(read)]
40+
fn first() -> [u8; 3];
41+
42+
#[storage(read)]
43+
fn last() -> [u8; 3];
44+
45+
#[storage(read, write)]
46+
fn reverse();
47+
48+
#[storage(read, write)]
49+
fn fill(value: [u8; 3]);
50+
51+
#[storage(read, write)]
52+
fn resize(new_len: u64, value: [u8; 3]);
3553
}
3654

3755
storage {
@@ -88,4 +106,34 @@ impl MyContract for Contract {
88106
fn clear() {
89107
storage.my_vec.clear();
90108
}
109+
110+
#[storage(read, write)]
111+
fn swap(index_0: u64, index_1: u64) {
112+
storage.my_vec.swap(index_0, index_1);
113+
}
114+
115+
#[storage(read)]
116+
fn first() -> [u8; 3] {
117+
storage.my_vec.first().unwrap()
118+
}
119+
120+
#[storage(read)]
121+
fn last() -> [u8; 3] {
122+
storage.my_vec.last().unwrap()
123+
}
124+
125+
#[storage(read, write)]
126+
fn reverse() {
127+
storage.my_vec.reverse();
128+
}
129+
130+
#[storage(read, write)]
131+
fn fill(value: [u8; 3]) {
132+
storage.my_vec.fill(value);
133+
}
134+
135+
#[storage(read, write)]
136+
fn resize(new_len: u64, value: [u8; 3]) {
137+
storage.my_vec.resize(new_len, value);
138+
}
91139
}

test/src/sdk-harness/test_artifacts/storage_vec/svec_b256/src/main.sw

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,24 @@ abi MyContract {
3232

3333
#[storage(write)]
3434
fn clear();
35+
36+
#[storage(read, write)]
37+
fn swap(index_0: u64, index_1: u64);
38+
39+
#[storage(read)]
40+
fn first() -> b256;
41+
42+
#[storage(read)]
43+
fn last() -> b256;
44+
45+
#[storage(read, write)]
46+
fn reverse();
47+
48+
#[storage(read, write)]
49+
fn fill(value: b256);
50+
51+
#[storage(read, write)]
52+
fn resize(new_len: u64, value: b256);
3553
}
3654

3755
storage {
@@ -88,4 +106,34 @@ impl MyContract for Contract {
88106
fn clear() {
89107
storage.my_vec.clear();
90108
}
109+
110+
#[storage(read, write)]
111+
fn swap(index_0: u64, index_1: u64) {
112+
storage.my_vec.swap(index_0, index_1);
113+
}
114+
115+
#[storage(read)]
116+
fn first() -> b256 {
117+
storage.my_vec.first().unwrap()
118+
}
119+
120+
#[storage(read)]
121+
fn last() -> b256 {
122+
storage.my_vec.last().unwrap()
123+
}
124+
125+
#[storage(read, write)]
126+
fn reverse() {
127+
storage.my_vec.reverse();
128+
}
129+
130+
#[storage(read, write)]
131+
fn fill(value: b256) {
132+
storage.my_vec.fill(value);
133+
}
134+
135+
#[storage(read, write)]
136+
fn resize(new_len: u64, value: b256) {
137+
storage.my_vec.resize(new_len, value);
138+
}
91139
}

0 commit comments

Comments
 (0)