diff --git a/noir_stdlib/src/cmp.nr b/noir_stdlib/src/cmp.nr index bdd5e2bc5ec..d2cf6b3836a 100644 --- a/noir_stdlib/src/cmp.nr +++ b/noir_stdlib/src/cmp.nr @@ -1,9 +1,37 @@ +use crate::meta::derive_via; + +#[derive_via(derive_eq)] // docs:start:eq-trait trait Eq { fn eq(self, other: Self) -> bool; } // docs:end:eq-trait +comptime fn derive_eq(s: StructDefinition) -> Quoted { + let typ = s.as_type(); + + let impl_generics = s.generics().join(quote {,}); + + let where_clause = s.generics().map(|name| quote { $name: Default }).join(quote {,}); + + // `(self.a == other.a) & (self.b == other.b) & ...` + let equalities = s.fields().map( + |f: (Quoted, Type)| { + let name = f.0; + quote { (self.$name == other.$name) } + } + ); + let body = equalities.join(quote { & }); + + quote { + impl<$impl_generics> Eq for $typ where $where_clause { + fn eq(self, other: Self) -> bool { + $body + } + } + } +} + impl Eq for Field { fn eq(self, other: Field) -> bool { self == other } } impl Eq for u64 { fn eq(self, other: u64) -> bool { self == other } } diff --git a/noir_stdlib/src/default.nr b/noir_stdlib/src/default.nr index 0acb3966034..f0d98205a90 100644 --- a/noir_stdlib/src/default.nr +++ b/noir_stdlib/src/default.nr @@ -1,9 +1,37 @@ +use crate::meta::derive_via; + +#[derive_via(derive_default)] // docs:start:default-trait trait Default { fn default() -> Self; } // docs:end:default-trait +comptime fn derive_default(s: StructDefinition) -> Quoted { + let typ = s.as_type(); + + let impl_generics = s.generics().join(quote {,}); + + let where_clause = s.generics().map(|name| quote { $name: Default }).join(quote {,}); + + // `foo: Default::default(), bar: Default::default(), ...` + let fields = s.fields().map( + |f: (Quoted, Type)| { + let name = f.0; + quote { $name: Default::default() } + } + ); + let fields = fields.join(quote {,}); + + quote { + impl<$impl_generics> Default for $typ where $where_clause { + fn default() -> Self { + Self { $fields } + } + } + } +} + impl Default for Field { fn default() -> Field { 0 } } impl Default for u8 { fn default() -> u8 { 0 } } diff --git a/noir_stdlib/src/hash/poseidon2.nr b/noir_stdlib/src/hash/poseidon2.nr index 08cf68d1f82..9626da0cf97 100644 --- a/noir_stdlib/src/hash/poseidon2.nr +++ b/noir_stdlib/src/hash/poseidon2.nr @@ -1,7 +1,7 @@ use crate::hash::Hasher; use crate::default::Default; -global RATE: u32 = 3; +comptime global RATE: u32 = 3; struct Poseidon2 { cache: [Field;3], diff --git a/noir_stdlib/src/meta/mod.nr b/noir_stdlib/src/meta/mod.nr index cdc0e29d752..21ba24972be 100644 --- a/noir_stdlib/src/meta/mod.nr +++ b/noir_stdlib/src/meta/mod.nr @@ -2,9 +2,9 @@ use crate::collections::umap::UHashMap; use crate::hash::BuildHasherDefault; use crate::hash::poseidon2::Poseidon2Hasher; +mod struct_def; mod trait_constraint; mod trait_def; -mod type_def; mod quoted; /// Calling unquote as a macro (via `unquote!(arg)`) will unquote diff --git a/noir_stdlib/src/meta/type_def.nr b/noir_stdlib/src/meta/struct_def.nr similarity index 100% rename from noir_stdlib/src/meta/type_def.nr rename to noir_stdlib/src/meta/struct_def.nr diff --git a/test_programs/execution_success/derive/src/main.nr b/test_programs/execution_success/derive/src/main.nr index 6e80bd59640..e4148f2c944 100644 --- a/test_programs/execution_success/derive/src/main.nr +++ b/test_programs/execution_success/derive/src/main.nr @@ -19,7 +19,17 @@ comptime fn derive_do_nothing(s: StructDefinition) -> Quoted { } } +// Test stdlib derive fns & multiple traits +#[derive(Eq, Default)] +struct MyOtherStruct { + field1: u32, + field2: u64, +} + fn main() { let s = MyStruct { my_field: 1 }; s.do_nothing(); + + let o = MyOtherStruct::default(); + assert_eq(o, o); }