Skip to content

Commit d48a793

Browse files
authored
Add Clone implementation for String and Vec (#6865)
## Description This PR implements the `Clone` for `String` and `Vec`. ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [x] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [x] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] I have added tests that prove my fix is effective or that my feature works. - [x] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [x] 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). - [x] I have requested a review from the relevant team or maintainers.
1 parent 3b8efe9 commit d48a793

File tree

10 files changed

+130
-77
lines changed

10 files changed

+130
-77
lines changed

sway-lib-std/src/bytes.sw

-54
Original file line numberDiff line numberDiff line change
@@ -1020,57 +1020,3 @@ impl AbiDecode for Bytes {
10201020
raw_slice::abi_decode(buffer).into()
10211021
}
10221022
}
1023-
1024-
#[test]
1025-
fn ok_bytes_buffer_ownership() {
1026-
let mut original_array = [1u8, 2u8, 3u8, 4u8];
1027-
let slice = raw_slice::from_parts::<u8>(__addr_of(original_array), 4);
1028-
1029-
// Check Bytes duplicates the original slice
1030-
let mut bytes = Bytes::from(slice);
1031-
bytes.set(0, 5);
1032-
assert(original_array[0] == 1);
1033-
1034-
// At this point, slice equals [5, 2, 3, 4]
1035-
let encoded_slice = encode(bytes);
1036-
1037-
// `Bytes` should duplicate the underlying buffer,
1038-
// so when we write to it, it should not change
1039-
// `encoded_slice`
1040-
let mut bytes = abi_decode::<Bytes>(encoded_slice);
1041-
bytes.set(0, 6);
1042-
assert(bytes.get(0) == Some(6));
1043-
1044-
let mut bytes = abi_decode::<Bytes>(encoded_slice);
1045-
assert(bytes.get(0) == Some(5));
1046-
}
1047-
1048-
#[test]
1049-
fn ok_bytes_bigger_than_3064() {
1050-
let mut v: Bytes = Bytes::new();
1051-
1052-
// We allocate 1024 bytes initially, this is throw away because
1053-
// it is not big enough for the buffer.
1054-
// Then we used to double the buffer to 2048.
1055-
// Then we write an `u64` with the length of the buffer.
1056-
// Then we write the buffer itself.
1057-
// (1024 + 2048) - 8 = 3064
1058-
// Thus, we need a buffer with 3065 bytes to write into the red zone
1059-
let mut a = 3065;
1060-
while a > 0 {
1061-
v.push(1u8);
1062-
a -= 1;
1063-
}
1064-
1065-
// This red zone should not be overwritten
1066-
let red_zone = asm(size: 1024) {
1067-
aloc size;
1068-
hp: raw_ptr
1069-
};
1070-
red_zone.write(0xFFFFFFFFFFFFFFFF);
1071-
assert(red_zone.read::<u64>() == 0xFFFFFFFFFFFFFFFF);
1072-
1073-
let _ = encode(v);
1074-
1075-
assert(red_zone.read::<u64>() == 0xFFFFFFFFFFFFFFFF);
1076-
}

sway-lib-std/src/prelude.sw

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub use ::revert::{require, revert, revert_with_log};
2525

2626
// Convert
2727
pub use ::convert::From;
28+
pub use ::clone::Clone;
2829

2930
// Primitive conversions
3031
pub use ::primitive_conversions::{b256::*, str::*, u16::*, u256::*, u32::*, u64::*, u8::*};

sway-lib-std/src/string.sw

+9
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use ::bytes::*;
66
use ::convert::*;
77
use ::hash::{Hash, Hasher};
88
use ::option::Option;
9+
use ::clone::Clone;
910

1011
/// A UTF-8 encoded growable string. It has ownership over its buffer.
1112
///
@@ -341,3 +342,11 @@ impl AbiDecode for String {
341342
}
342343
}
343344
}
345+
346+
impl Clone for String {
347+
fn clone(self) -> Self {
348+
Self {
349+
bytes: self.bytes.clone(),
350+
}
351+
}
352+
}

sway-lib-std/src/vec.sw

+10-22
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use ::assert::assert;
66
use ::option::Option::{self, *};
77
use ::convert::From;
88
use ::iterator::*;
9+
use ::clone::Clone;
910

1011
struct RawVec<T> {
1112
ptr: raw_ptr,
@@ -791,26 +792,13 @@ impl<T> Iterator for VecIter<T> {
791792
}
792793
}
793794

794-
#[test]
795-
fn ok_vec_buffer_ownership() {
796-
let mut original_array = [1u8, 2u8, 3u8, 4u8];
797-
let slice = raw_slice::from_parts::<u8>(__addr_of(original_array), 4);
798-
799-
// Check Vec duplicates the original slice
800-
let mut bytes = Vec::<u8>::from(slice);
801-
bytes.set(0, 5);
802-
assert(original_array[0] == 1);
803-
804-
// At this point, slice equals [5, 2, 3, 4]
805-
let encoded_slice = encode(bytes);
806-
807-
// `Vec<u8>` should duplicate the underlying buffer,
808-
// so when we write to it, it should not change
809-
// `encoded_slice`
810-
let mut bytes = abi_decode::<Vec<u8>>(encoded_slice);
811-
bytes.set(0, 6);
812-
assert(bytes.get(0) == Some(6));
813-
814-
let mut bytes = abi_decode::<Vec<u8>>(encoded_slice);
815-
assert(bytes.get(0) == Some(5));
795+
impl<T> Clone for Vec<T> {
796+
fn clone(self) -> Self {
797+
let len = self.len();
798+
let buf = RawVec::with_capacity(len);
799+
if len > 0 {
800+
self.ptr().copy_to::<T>(buf.ptr(), len);
801+
}
802+
Self { buf, len }
803+
}
816804
}

test/src/e2e_vm_tests/reduced_std_libs/sway-lib-std-vec/reduced_lib.config

+1
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ revert.sw
88
vec.sw
99
iterator.sw
1010
convert.sw
11+
clone.sw

test/src/e2e_vm_tests/reduced_std_libs/sway-lib-std-vec/src/lib.sw

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ pub mod assert;
99
pub mod convert;
1010
pub mod alloc;
1111
pub mod iterator;
12+
pub mod clone;
1213
pub mod vec;
1314

1415
pub mod prelude;

test/src/e2e_vm_tests/reduced_std_libs/sway-lib-std-vec/src/prelude.sw

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub use ::revert::{require, revert};
1414

1515
// Convert
1616
pub use ::convert::From;
17+
pub use ::clone::Clone;
1718

1819
// Logging
1920
pub use ::logging::log;

test/src/in_language_tests/test_programs/bytes_inline_tests/src/main.sw

+55-1
Original file line numberDiff line numberDiff line change
@@ -1024,12 +1024,66 @@ fn bytes_clone() {
10241024
assert(cloned_bytes.ptr() != bytes.ptr());
10251025
assert(cloned_bytes.len() == bytes.len());
10261026
// Capacity is not cloned
1027-
// assert(cloned_bytes.capacity() == bytes.capacity());
1027+
assert(cloned_bytes.capacity() != bytes.capacity());
10281028
assert(cloned_bytes.get(0).unwrap() == bytes.get(0).unwrap());
10291029
assert(cloned_bytes.get(1).unwrap() == bytes.get(1).unwrap());
10301030
assert(cloned_bytes.get(2).unwrap() == bytes.get(2).unwrap());
10311031
}
10321032

1033+
#[test]
1034+
fn bytes_buffer_ownership() {
1035+
let mut original_array = [1u8, 2u8, 3u8, 4u8];
1036+
let slice = raw_slice::from_parts::<u8>(__addr_of(original_array), 4);
1037+
1038+
// Check Bytes duplicates the original slice
1039+
let mut bytes = Bytes::from(slice);
1040+
bytes.set(0, 5);
1041+
assert(original_array[0] == 1);
1042+
1043+
// At this point, slice equals [5, 2, 3, 4]
1044+
let encoded_slice = encode(bytes);
1045+
1046+
// `Bytes` should duplicate the underlying buffer,
1047+
// so when we write to it, it should not change
1048+
// `encoded_slice`
1049+
let mut bytes = abi_decode::<Bytes>(encoded_slice);
1050+
bytes.set(0, 6);
1051+
assert(bytes.get(0) == Some(6));
1052+
1053+
let mut bytes = abi_decode::<Bytes>(encoded_slice);
1054+
assert(bytes.get(0) == Some(5));
1055+
}
1056+
1057+
#[test]
1058+
fn bytes_bigger_than_3064() {
1059+
let mut v: Bytes = Bytes::new();
1060+
1061+
// We allocate 1024 bytes initially, this is throw away because
1062+
// it is not big enough for the buffer.
1063+
// Then we used to double the buffer to 2048.
1064+
// Then we write an `u64` with the length of the buffer.
1065+
// Then we write the buffer itself.
1066+
// (1024 + 2048) - 8 = 3064
1067+
// Thus, we need a buffer with 3065 bytes to write into the red zone
1068+
let mut a = 3065;
1069+
while a > 0 {
1070+
v.push(1u8);
1071+
a -= 1;
1072+
}
1073+
1074+
// This red zone should not be overwritten
1075+
let red_zone = asm(size: 1024) {
1076+
aloc size;
1077+
hp: raw_ptr
1078+
};
1079+
red_zone.write(0xFFFFFFFFFFFFFFFF);
1080+
assert(red_zone.read::<u64>() == 0xFFFFFFFFFFFFFFFF);
1081+
1082+
let _ = encode(v);
1083+
1084+
assert(red_zone.read::<u64>() == 0xFFFFFFFFFFFFFFFF);
1085+
}
1086+
10331087
#[test]
10341088
pub fn test_encode_decode() {
10351089
let initial = 0x3333333333333333333333333333333333333333333333333333333333333333;

test/src/in_language_tests/test_programs/string_inline_tests/src/main.sw

+13
Original file line numberDiff line numberDiff line change
@@ -380,3 +380,16 @@ fn string_test_abi_encoding() {
380380

381381
assert(string == decoded_string);
382382
}
383+
384+
#[test]
385+
fn string_clone() {
386+
let string = String::from_ascii_str("fuel");
387+
388+
let cloned_string = string.clone();
389+
390+
assert(cloned_string.ptr() != string.ptr());
391+
assert(cloned_string.as_bytes().len() == string.as_bytes().len());
392+
assert(cloned_string.as_bytes().get(0).unwrap() == string.as_bytes().get(0).unwrap());
393+
assert(cloned_string.as_bytes().get(1).unwrap() == string.as_bytes().get(1).unwrap());
394+
assert(cloned_string.as_bytes().get(2).unwrap() == string.as_bytes().get(2).unwrap());
395+
}

test/src/in_language_tests/test_programs/vec_inline_tests/src/main.sw

+39
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,45 @@ fn vec_raw_slice_into() {
687687
assert(vec.len() == slice.len::<u64>());
688688
}
689689

690+
#[test]
691+
fn vec_clone() {
692+
let (mut vec, _a, _b, _c) = setup();
693+
694+
let cloned_vec = vec.clone();
695+
696+
assert(cloned_vec.ptr() != vec.ptr());
697+
assert(cloned_vec.len() == vec.len());
698+
// Capacity is not cloned
699+
assert(cloned_vec.capacity() != vec.capacity());
700+
assert(cloned_vec.get(0).unwrap() == vec.get(0).unwrap());
701+
assert(cloned_vec.get(1).unwrap() == vec.get(1).unwrap());
702+
assert(cloned_vec.get(2).unwrap() == vec.get(2).unwrap());
703+
}
704+
705+
#[test]
706+
fn vec_buffer_ownership() {
707+
let mut original_array = [1u8, 2u8, 3u8, 4u8];
708+
let slice = raw_slice::from_parts::<u8>(__addr_of(original_array), 4);
709+
710+
// Check Vec duplicates the original slice
711+
let mut bytes = Vec::<u8>::from(slice);
712+
bytes.set(0, 5);
713+
assert(original_array[0] == 1);
714+
715+
// At this point, slice equals [5, 2, 3, 4]
716+
let encoded_slice = encode(bytes);
717+
718+
// `Vec<u8>` should duplicate the underlying buffer,
719+
// so when we write to it, it should not change
720+
// `encoded_slice`
721+
let mut bytes = abi_decode::<Vec<u8>>(encoded_slice);
722+
bytes.set(0, 6);
723+
assert(bytes.get(0) == Some(6));
724+
725+
let mut bytes = abi_decode::<Vec<u8>>(encoded_slice);
726+
assert(bytes.get(0) == Some(5));
727+
}
728+
690729
#[test()]
691730
fn vec_encode_and_decode() {
692731
let mut v1: Vec<u64> = Vec::new();

0 commit comments

Comments
 (0)