From 72e84a9a248738fae059852600efa874982c8357 Mon Sep 17 00:00:00 2001 From: Brandon <89608157+brandonsurh@users.noreply.github.com> Date: Sun, 3 Dec 2023 00:15:05 -0500 Subject: [PATCH] Implements the `Eq` trait for `Option` (#5302) ## Description Closes #3542 Implements the `Eq` trait for `Option`. Also adds tests for the implementation. ## Checklist - [x] I have linked to any relevant issues. - [x] 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). - [x] 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. - [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. --------- Co-authored-by: Braqzen <103777923+Braqzen@users.noreply.github.com> Co-authored-by: Cameron Carstens <54727135+bitzoic@users.noreply.github.com> --- sway-lib-std/src/option.sw | 10 + .../call_basic_storage/src/main.sw | 2 +- .../call_storage_enum/src/main.sw | 2 +- .../should_pass/stdlib/option_eq/.gitignore | 2 + .../should_pass/stdlib/option_eq/Forc.lock | 13 + .../should_pass/stdlib/option_eq/Forc.toml | 8 + .../stdlib/option_eq/json_abi_oracle.json | 25 ++ .../should_pass/stdlib/option_eq/src/main.sw | 294 ++++++++++++++++++ .../should_pass/stdlib/option_eq/test.toml | 5 + 9 files changed, 359 insertions(+), 2 deletions(-) create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option_eq/.gitignore create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option_eq/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option_eq/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option_eq/json_abi_oracle.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option_eq/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option_eq/test.toml diff --git a/sway-lib-std/src/option.sw b/sway-lib-std/src/option.sw index d6e865e3071..23ec90da995 100644 --- a/sway-lib-std/src/option.sw +++ b/sway-lib-std/src/option.sw @@ -87,6 +87,16 @@ pub enum Option { } // ANCHOR_END: docs_option +impl core::ops::Eq for Option where T: Eq { + fn eq(self, other: Self) -> bool { + match (self, other) { + (Option::Some(a), Option::Some(b)) => a == b, + (Option::None, Option::None) => true, + _ => false, + } + } +} + // Type implementation // impl Option { diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw index a11d28284c8..c66393e1eb6 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw @@ -2,7 +2,7 @@ script; use basic_storage_abi::{BasicStorage, Quad}; fn main() -> u64 { - let addr = abi(BasicStorage, 0xb0d36fd04e733889ce2b24307a00ec871314ed54964404d441aafb376eb01e7d); + let addr = abi(BasicStorage, 0xe683b03352239f4b23986cd283948b7dfc22b528ace56859e562dff5a0165dc8); let key = 0x0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; let value = 4242; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw index 581f0085047..b69d8430437 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw @@ -3,7 +3,7 @@ script; use storage_enum_abi::*; fn main() -> u64 { - let contract_id = 0x8836ec87c97907ff0f4cf0cf62f852c7f654b8a6bd6845ee2d0203c5dbd029a5; + let contract_id = 0xe2f370fb01c8c36a521093494a023ce2d7232398e5e88722164c42ec0303f381; let caller = abi(StorageEnum, contract_id); let res = caller.read_write_enums(); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option_eq/.gitignore b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option_eq/.gitignore new file mode 100644 index 00000000000..77d3844f58c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option_eq/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option_eq/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option_eq/Forc.lock new file mode 100644 index 00000000000..236f3be397c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option_eq/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = 'core' +source = 'path+from-root-9E5F9380FAC5610F' + +[[package]] +name = 'option_eq' +source = 'member' +dependencies = ['std'] + +[[package]] +name = 'std' +source = 'path+from-root-9E5F9380FAC5610F' +dependencies = ['core'] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option_eq/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option_eq/Forc.toml new file mode 100644 index 00000000000..95addb6137d --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option_eq/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "option_eq" + +[dependencies] +std = { path = "../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option_eq/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option_eq/json_abi_oracle.json new file mode 100644 index 00000000000..03b2f150939 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option_eq/json_abi_oracle.json @@ -0,0 +1,25 @@ +{ + "configurables": [], + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "messagesTypes": [], + "types": [ + { + "components": null, + "type": "bool", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option_eq/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option_eq/src/main.sw new file mode 100644 index 00000000000..f3728eda5ef --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option_eq/src/main.sw @@ -0,0 +1,294 @@ +script; + +struct MyStruct { + x: u64, +} + +enum MyEnum { + A: u64, + B: bool, +} + +pub type StringArray = str[4]; +impl core::ops::Eq for StringArray { + fn eq(self, other: Self) -> bool { + from_str_array(self) == from_str_array(other) + } +} + +pub type Array = [u32; 2]; +impl core::ops::Eq for Array { + fn eq(self, other: Self) -> bool { + self[0] == other[0] && self[1] == other[1] + } +} + +impl core::ops::Eq for MyStruct { + fn eq(self, other: Self) -> bool { + self.x == other.x + } +} + +pub type Tuple = (u32, u32); +impl core::ops::Eq for Tuple { + fn eq(self, other: Self) -> bool { + self.0 == other.0 && self.1 == other.1 + } +} + +impl core::ops::Eq for MyEnum { + fn eq(self, other: MyEnum) -> bool { + match (self, other) { + (MyEnum::A(inner1), MyEnum::A(inner2)) => inner1 == inner2, + (MyEnum::B(inner1), MyEnum::B(inner2)) => inner1 == inner2, + _ => false, + } + } +} + +fn main() -> bool { + // Test with u8 + let u8_option1 = Option::::Some(10); + let u8_option2 = Option::::Some(10); + let u8_option3 = Option::::Some(20); + let u8_none_option: Option = Option::None; + + // Eq tests + assert(u8_option1 == u8_option1); + assert(u8_option1 == u8_option2); + + // Neq tests + assert(u8_option1 != u8_option3); + assert(u8_option1 != u8_none_option); + + // None tests + assert(u8_none_option == Option::None); + assert(Option::::None == u8_none_option); + + // Test with u16 + let u16_option1 = Option::::Some(10); + let u16_option2 = Option::::Some(10); + let u16_option3 = Option::::Some(20); + let u16_none_option: Option = Option::None; + + // Eq tests + assert(u16_option1 == u16_option1); + assert(u16_option1 == u16_option2); + + // Neq tests + assert(u16_option1 != u16_option3); + assert(u16_option1 != u16_none_option); + + // None tests + assert(u16_none_option == Option::None); + assert(Option::::None == u16_none_option); + + // Test with u32 + let u32_option1 = Option::::Some(10); + let u32_option2 = Option::::Some(10); + let u32_option3 = Option::::Some(20); + let u32_none_option: Option = Option::None; + + // Eq tests + assert(u32_option1 == u32_option1); + assert(u32_option1 == u32_option2); + + // Neq tests + assert(u32_option1 != u32_option3); + assert(u32_option1 != u32_none_option); + + // None tests + assert(u32_none_option == Option::None); + assert(Option::::None == u32_none_option); + + // Test with u64 + let u64_option1 = Option::::Some(10); + let u64_option2 = Option::::Some(10); + let u64_option3 = Option::::Some(20); + let u64_none_option: Option = Option::None; + + // Eq tests + assert(u64_option1 == u64_option1); + assert(u64_option1 == u64_option2); + + // Neq tests + assert(u64_option1 != u64_option3); + assert(u64_option1 != u64_none_option); + + // None tests + assert(u64_none_option == Option::None); + assert(Option::::None == u64_none_option); + + // Test with u256 + let u256_option1 = Option::::Some(10); + let u256_option2 = Option::::Some(10); + let u256_option3 = Option::::Some(20); + let u256_none_option: Option = Option::None; + + // Eq tests + assert(u256_option1 == u256_option1); + assert(u256_option1 == u256_option2); + + // Neq tests + assert(u256_option1 != u256_option3); + assert(u256_option1 != u256_none_option); + + // None tests + assert(u256_none_option == Option::None); + assert(Option::::None == u256_none_option); + + // Test with str + let str_option1 = Option::::Some("fuel"); + let str_option2 = Option::::Some("fuel"); + let str_option3 = Option::::Some("sway"); + let str_none_option: Option = Option::None; + + // Eq tests + assert(str_option1 == str_option1); + assert(str_option1 == str_option2); + + // Neq tests + assert(str_option1 != str_option3); + assert(str_option1 != str_none_option); + + // None tests + assert(str_none_option == Option::None); + assert(Option::::None == str_none_option); + + // Test with bool + let bool_option1 = Option::Some(true); + let bool_option2 = Option::Some(true); + let bool_option3 = Option::Some(false); + let bool_none_option: Option = Option::None; + + // Eq tests + assert(bool_option1 == bool_option1); + assert(bool_option1 == bool_option2); + + // Neq tests + assert(bool_option1 != bool_option3); + assert(bool_option1 != bool_none_option); + + // None tests + assert(bool_none_option == Option::None); + assert(Option::::None == bool_none_option); + + // Test with b256 + let b256_option1 = Option::::Some(0x0000000000000000000000000000000000000000000000000000000000000001); + let b256_option2 = Option::::Some(0x0000000000000000000000000000000000000000000000000000000000000001); + let b256_option3 = Option::::Some(0x0000000000000000000000000000000000000000000000000000000000000002); + let b256_none_option: Option = Option::None; + + // Eq tests + assert(b256_option1 == b256_option1); + assert(b256_option1 == b256_option2); + + // Neq tests + assert(b256_option1 != b256_option3); + assert(b256_option1 != b256_none_option); + + // None tests + assert(b256_none_option == Option::None); + assert(Option::::None == b256_none_option); + + // Test with string array + let string1: StringArray = __to_str_array("fuel"); + let string2: StringArray = __to_str_array("sway"); + + let string_option1 = Option::Some(string1); + let string_option2 = Option::Some(string1); + let string_option3 = Option::Some(string2); + let string_none_option: Option = Option::None; + + // Eq tests + assert(string_option1 == string_option1); + assert(string_option1 == string_option2); + + // Neq tests + assert(string_option1 != string_option3); + assert(string_option1 != string_none_option); + + // None tests + assert(string_none_option == Option::None); + assert(Option::::None == string_none_option); + + // Test with array + let array1: Array = [10, 20]; + let array2: Array = [10, 30]; + + let array_option1 = Option::Some(array1); + let array_option2 = Option::Some(array1); + let array_option3 = Option::Some(array2); + let array_none_option: Option = Option::None; + + // Eq tests + assert(array_option1 == array_option1); + assert(array_option1 == array_option2); + + // Neq tests + assert(array_option1 != array_option3); + assert(array_option1 != array_none_option); + + // None tests + assert(array_none_option == Option::None); + assert(Option::::None == array_none_option); + + // Test with struct + let struct_option1 = Option::Some(MyStruct { x: 10 }); + let struct_option2 = Option::Some(MyStruct { x: 10 }); + let struct_option3 = Option::Some(MyStruct { x: 20 }); + let struct_none_option: Option = Option::None; + + // Eq tests + assert(struct_option1 == struct_option1); + assert(struct_option1 == struct_option2); + + // Neq tests + assert(struct_option1 != struct_option3); + assert(struct_option1 != struct_none_option); + + // None tests + assert(struct_none_option == Option::None); + assert(Option::::None == struct_none_option); + + // Test with tuple + let tuple1: Tuple = (10, 20); + let tuple2: Tuple = (10, 30); + + let tuple_option1 = Option::Some(tuple1); + let tuple_option2 = Option::Some(tuple1); + let tuple_option3 = Option::Some(tuple2); + let tuple_none_option: Option = Option::None; + + // Eq tests + assert(tuple_option1 == tuple_option1); + assert(tuple_option1 == tuple_option2); + + // Neq tests + assert(tuple_option1 != tuple_option3); + assert(tuple_option1 != tuple_none_option); + + // None tests + assert(tuple_none_option == Option::None); + assert(Option::::None == tuple_none_option); + + // Test with enums + let enum_option1 = Option::Some(MyEnum::A(42)); + let enum_option2 = Option::Some(MyEnum::A(42)); + let enum_option3 = Option::Some(MyEnum::B(true)); + let enum_none_option: Option = Option::None; + + // Eq tests + assert(enum_option1 == enum_option1); + assert(enum_option1 == enum_option2); + + // Neq tests + assert(enum_option1 != enum_option3); + assert(enum_option1 != enum_none_option); + + // None tests + assert(enum_none_option == Option::None); + assert(Option::::None == enum_none_option); + + true +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option_eq/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option_eq/test.toml new file mode 100644 index 00000000000..92d859c8396 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option_eq/test.toml @@ -0,0 +1,5 @@ +category = "run" +expected_result = { action = "return", value = 1 } +validate_abi = true + +expected_warnings = 5 \ No newline at end of file