From d465860ca5900524d1b70bba7b34d2db2fb46972 Mon Sep 17 00:00:00 2001 From: bitzoic Date: Tue, 28 Jan 2025 14:32:30 +0100 Subject: [PATCH 1/4] Add Clone for String and Vec --- .../bytes_inline_tests/src/main.sw | 56 ++++++++++++++++++- .../string_inline_tests/src/main.sw | 13 +++++ .../vec_inline_tests/src/main.sw | 39 +++++++++++++ 3 files changed, 107 insertions(+), 1 deletion(-) diff --git a/test/src/in_language_tests/test_programs/bytes_inline_tests/src/main.sw b/test/src/in_language_tests/test_programs/bytes_inline_tests/src/main.sw index 1532d74db76..1a7651e4680 100644 --- a/test/src/in_language_tests/test_programs/bytes_inline_tests/src/main.sw +++ b/test/src/in_language_tests/test_programs/bytes_inline_tests/src/main.sw @@ -1024,12 +1024,66 @@ fn bytes_clone() { assert(cloned_bytes.ptr() != bytes.ptr()); assert(cloned_bytes.len() == bytes.len()); // Capacity is not cloned - // assert(cloned_bytes.capacity() == bytes.capacity()); + assert(cloned_bytes.capacity() != bytes.capacity()); assert(cloned_bytes.get(0).unwrap() == bytes.get(0).unwrap()); assert(cloned_bytes.get(1).unwrap() == bytes.get(1).unwrap()); assert(cloned_bytes.get(2).unwrap() == bytes.get(2).unwrap()); } +#[test] +fn bytes_buffer_ownership() { + let mut original_array = [1u8, 2u8, 3u8, 4u8]; + let slice = raw_slice::from_parts::(__addr_of(original_array), 4); + + // Check Bytes duplicates the original slice + let mut bytes = Bytes::from(slice); + bytes.set(0, 5); + assert(original_array[0] == 1); + + // At this point, slice equals [5, 2, 3, 4] + let encoded_slice = encode(bytes); + + // `Bytes` should duplicate the underlying buffer, + // so when we write to it, it should not change + // `encoded_slice` + let mut bytes = abi_decode::(encoded_slice); + bytes.set(0, 6); + assert(bytes.get(0) == Some(6)); + + let mut bytes = abi_decode::(encoded_slice); + assert(bytes.get(0) == Some(5)); +} + +#[test] +fn bytes_bigger_than_3064() { + let mut v: Bytes = Bytes::new(); + + // We allocate 1024 bytes initially, this is throw away because + // it is not big enough for the buffer. + // Then we used to double the buffer to 2048. + // Then we write an `u64` with the length of the buffer. + // Then we write the buffer itself. + // (1024 + 2048) - 8 = 3064 + // Thus, we need a buffer with 3065 bytes to write into the red zone + let mut a = 3065; + while a > 0 { + v.push(1u8); + a -= 1; + } + + // This red zone should not be overwritten + let red_zone = asm(size: 1024) { + aloc size; + hp: raw_ptr + }; + red_zone.write(0xFFFFFFFFFFFFFFFF); + assert(red_zone.read::() == 0xFFFFFFFFFFFFFFFF); + + let _ = encode(v); + + assert(red_zone.read::() == 0xFFFFFFFFFFFFFFFF); +} + #[test] pub fn test_encode_decode() { let initial = 0x3333333333333333333333333333333333333333333333333333333333333333; diff --git a/test/src/in_language_tests/test_programs/string_inline_tests/src/main.sw b/test/src/in_language_tests/test_programs/string_inline_tests/src/main.sw index 079a28ee78d..8d763296114 100644 --- a/test/src/in_language_tests/test_programs/string_inline_tests/src/main.sw +++ b/test/src/in_language_tests/test_programs/string_inline_tests/src/main.sw @@ -380,3 +380,16 @@ fn string_test_abi_encoding() { assert(string == decoded_string); } + +#[test] +fn string_clone() { + let string = String::from_ascii_str("fuel"); + + let cloned_string = string.clone(); + + assert(cloned_string.ptr() != string.ptr()); + assert(cloned_string.as_bytes().len() == string.as_bytes().len()); + assert(cloned_string.as_bytes().get(0).unwrap() == string.as_bytes().get(0).unwrap()); + assert(cloned_string.as_bytes().get(1).unwrap() == string.as_bytes().get(1).unwrap()); + assert(cloned_string.as_bytes().get(2).unwrap() == string.as_bytes().get(2).unwrap()); +} diff --git a/test/src/in_language_tests/test_programs/vec_inline_tests/src/main.sw b/test/src/in_language_tests/test_programs/vec_inline_tests/src/main.sw index 78e2df5d1e5..2ad03fa26af 100644 --- a/test/src/in_language_tests/test_programs/vec_inline_tests/src/main.sw +++ b/test/src/in_language_tests/test_programs/vec_inline_tests/src/main.sw @@ -687,6 +687,45 @@ fn vec_raw_slice_into() { assert(vec.len() == slice.len::()); } +#[test] +fn vec_clone() { + let (mut vec, _a, _b, _c) = setup(); + + let cloned_vec = vec.clone(); + + assert(cloned_vec.ptr() != vec.ptr()); + assert(cloned_vec.len() == vec.len()); + // Capacity is not cloned + assert(cloned_vec.capacity() != vec.capacity()); + assert(cloned_vec.get(0).unwrap() == vec.get(0).unwrap()); + assert(cloned_vec.get(1).unwrap() == vec.get(1).unwrap()); + assert(cloned_vec.get(2).unwrap() == vec.get(2).unwrap()); +} + +#[test] +fn vec_buffer_ownership() { + let mut original_array = [1u8, 2u8, 3u8, 4u8]; + let slice = raw_slice::from_parts::(__addr_of(original_array), 4); + + // Check Vec duplicates the original slice + let mut bytes = Vec::::from(slice); + bytes.set(0, 5); + assert(original_array[0] == 1); + + // At this point, slice equals [5, 2, 3, 4] + let encoded_slice = encode(bytes); + + // `Vec` should duplicate the underlying buffer, + // so when we write to it, it should not change + // `encoded_slice` + let mut bytes = abi_decode::>(encoded_slice); + bytes.set(0, 6); + assert(bytes.get(0) == Some(6)); + + let mut bytes = abi_decode::>(encoded_slice); + assert(bytes.get(0) == Some(5)); +} + #[test()] fn vec_encode_and_decode() { let mut v1: Vec = Vec::new(); From abe64d282dd2f4bcf0f59b9e178a941af13f155b Mon Sep 17 00:00:00 2001 From: bitzoic Date: Tue, 28 Jan 2025 14:34:36 +0100 Subject: [PATCH 2/4] Add Clone for String and Vec --- sway-lib-std/src/bytes.sw | 54 -------------------------------------- sway-lib-std/src/string.sw | 7 +++++ sway-lib-std/src/vec.sw | 32 +++++++--------------- 3 files changed, 17 insertions(+), 76 deletions(-) diff --git a/sway-lib-std/src/bytes.sw b/sway-lib-std/src/bytes.sw index 701011c599b..b229d9d181c 100644 --- a/sway-lib-std/src/bytes.sw +++ b/sway-lib-std/src/bytes.sw @@ -1020,57 +1020,3 @@ impl AbiDecode for Bytes { raw_slice::abi_decode(buffer).into() } } - -#[test] -fn ok_bytes_buffer_ownership() { - let mut original_array = [1u8, 2u8, 3u8, 4u8]; - let slice = raw_slice::from_parts::(__addr_of(original_array), 4); - - // Check Bytes duplicates the original slice - let mut bytes = Bytes::from(slice); - bytes.set(0, 5); - assert(original_array[0] == 1); - - // At this point, slice equals [5, 2, 3, 4] - let encoded_slice = encode(bytes); - - // `Bytes` should duplicate the underlying buffer, - // so when we write to it, it should not change - // `encoded_slice` - let mut bytes = abi_decode::(encoded_slice); - bytes.set(0, 6); - assert(bytes.get(0) == Some(6)); - - let mut bytes = abi_decode::(encoded_slice); - assert(bytes.get(0) == Some(5)); -} - -#[test] -fn ok_bytes_bigger_than_3064() { - let mut v: Bytes = Bytes::new(); - - // We allocate 1024 bytes initially, this is throw away because - // it is not big enough for the buffer. - // Then we used to double the buffer to 2048. - // Then we write an `u64` with the length of the buffer. - // Then we write the buffer itself. - // (1024 + 2048) - 8 = 3064 - // Thus, we need a buffer with 3065 bytes to write into the red zone - let mut a = 3065; - while a > 0 { - v.push(1u8); - a -= 1; - } - - // This red zone should not be overwritten - let red_zone = asm(size: 1024) { - aloc size; - hp: raw_ptr - }; - red_zone.write(0xFFFFFFFFFFFFFFFF); - assert(red_zone.read::() == 0xFFFFFFFFFFFFFFFF); - - let _ = encode(v); - - assert(red_zone.read::() == 0xFFFFFFFFFFFFFFFF); -} diff --git a/sway-lib-std/src/string.sw b/sway-lib-std/src/string.sw index abe9673dbdc..cc05321c572 100644 --- a/sway-lib-std/src/string.sw +++ b/sway-lib-std/src/string.sw @@ -6,6 +6,7 @@ use ::bytes::*; use ::convert::*; use ::hash::{Hash, Hasher}; use ::option::Option; +use ::clone::Clone; /// A UTF-8 encoded growable string. It has ownership over its buffer. /// @@ -341,3 +342,9 @@ impl AbiDecode for String { } } } + +impl Clone for String { + fn clone(self) -> Self { + Self { bytes: self.bytes.clone() } + } +} diff --git a/sway-lib-std/src/vec.sw b/sway-lib-std/src/vec.sw index d36bec92f5f..759ca510118 100644 --- a/sway-lib-std/src/vec.sw +++ b/sway-lib-std/src/vec.sw @@ -6,6 +6,7 @@ use ::assert::assert; use ::option::Option::{self, *}; use ::convert::From; use ::iterator::*; +use ::clone::Clone; struct RawVec { ptr: raw_ptr, @@ -791,26 +792,13 @@ impl Iterator for VecIter { } } -#[test] -fn ok_vec_buffer_ownership() { - let mut original_array = [1u8, 2u8, 3u8, 4u8]; - let slice = raw_slice::from_parts::(__addr_of(original_array), 4); - - // Check Vec duplicates the original slice - let mut bytes = Vec::::from(slice); - bytes.set(0, 5); - assert(original_array[0] == 1); - - // At this point, slice equals [5, 2, 3, 4] - let encoded_slice = encode(bytes); - - // `Vec` should duplicate the underlying buffer, - // so when we write to it, it should not change - // `encoded_slice` - let mut bytes = abi_decode::>(encoded_slice); - bytes.set(0, 6); - assert(bytes.get(0) == Some(6)); - - let mut bytes = abi_decode::>(encoded_slice); - assert(bytes.get(0) == Some(5)); +impl Clone for Vec { + fn clone(self) -> Self { + let len = self.len(); + let buf = RawVec::with_capacity(len); + if len > 0 { + self.ptr().copy_to::(buf.ptr(), len); + } + Self { buf, len } + } } From 9b8b5e5c6d4ab57994c56eb5041983a53d093417 Mon Sep 17 00:00:00 2001 From: bitzoic Date: Tue, 28 Jan 2025 14:34:59 +0100 Subject: [PATCH 3/4] Run formatter --- sway-lib-std/src/string.sw | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sway-lib-std/src/string.sw b/sway-lib-std/src/string.sw index cc05321c572..b6015a756bc 100644 --- a/sway-lib-std/src/string.sw +++ b/sway-lib-std/src/string.sw @@ -345,6 +345,8 @@ impl AbiDecode for String { impl Clone for String { fn clone(self) -> Self { - Self { bytes: self.bytes.clone() } + Self { + bytes: self.bytes.clone(), + } } } From 5ab5c5ab34312d14c41abd70ad108816b6a39241 Mon Sep 17 00:00:00 2001 From: bitzoic Date: Tue, 28 Jan 2025 15:03:59 +0100 Subject: [PATCH 4/4] Fix e2e tests --- sway-lib-std/src/prelude.sw | 1 + .../reduced_std_libs/sway-lib-std-vec/reduced_lib.config | 1 + .../e2e_vm_tests/reduced_std_libs/sway-lib-std-vec/src/lib.sw | 1 + .../reduced_std_libs/sway-lib-std-vec/src/prelude.sw | 1 + 4 files changed, 4 insertions(+) diff --git a/sway-lib-std/src/prelude.sw b/sway-lib-std/src/prelude.sw index b86eb26ec31..f422ba0f41b 100644 --- a/sway-lib-std/src/prelude.sw +++ b/sway-lib-std/src/prelude.sw @@ -25,6 +25,7 @@ pub use ::revert::{require, revert, revert_with_log}; // Convert pub use ::convert::From; +pub use ::clone::Clone; // Primitive conversions pub use ::primitive_conversions::{b256::*, str::*, u16::*, u256::*, u32::*, u64::*, u8::*}; diff --git a/test/src/e2e_vm_tests/reduced_std_libs/sway-lib-std-vec/reduced_lib.config b/test/src/e2e_vm_tests/reduced_std_libs/sway-lib-std-vec/reduced_lib.config index ab261db638c..637d8a9a489 100644 --- a/test/src/e2e_vm_tests/reduced_std_libs/sway-lib-std-vec/reduced_lib.config +++ b/test/src/e2e_vm_tests/reduced_std_libs/sway-lib-std-vec/reduced_lib.config @@ -8,3 +8,4 @@ revert.sw vec.sw iterator.sw convert.sw +clone.sw diff --git a/test/src/e2e_vm_tests/reduced_std_libs/sway-lib-std-vec/src/lib.sw b/test/src/e2e_vm_tests/reduced_std_libs/sway-lib-std-vec/src/lib.sw index d9a4ed324c1..b79aaaed722 100644 --- a/test/src/e2e_vm_tests/reduced_std_libs/sway-lib-std-vec/src/lib.sw +++ b/test/src/e2e_vm_tests/reduced_std_libs/sway-lib-std-vec/src/lib.sw @@ -9,6 +9,7 @@ pub mod assert; pub mod convert; pub mod alloc; pub mod iterator; +pub mod clone; pub mod vec; pub mod prelude; diff --git a/test/src/e2e_vm_tests/reduced_std_libs/sway-lib-std-vec/src/prelude.sw b/test/src/e2e_vm_tests/reduced_std_libs/sway-lib-std-vec/src/prelude.sw index 990bde12d23..a12f91da7c7 100644 --- a/test/src/e2e_vm_tests/reduced_std_libs/sway-lib-std-vec/src/prelude.sw +++ b/test/src/e2e_vm_tests/reduced_std_libs/sway-lib-std-vec/src/prelude.sw @@ -14,6 +14,7 @@ pub use ::revert::{require, revert}; // Convert pub use ::convert::From; +pub use ::clone::Clone; // Logging pub use ::logging::log;