diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr index e64d031b909f..354847b89eb2 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr @@ -228,14 +228,20 @@ pub(crate) comptime fn derive_deserialize(s: TypeDefinition) -> Quoted { let generics_declarations = get_generics_declarations(s); let where_deserialize_clause = get_where_trait_clause(s, quote {Deserialize}); - // The following will give us ::N + ::N + ... - let right_hand_side_of_definition_of_n = params - .map(|(_, param_type, _): (Quoted, Type, Quoted)| { - quote { + // The following will give us: + // ::N + ::N + ... + // (or 0 if the struct has no members) + let right_hand_side_of_definition_of_n = if params.len() > 0 { + params + .map(|(_, param_type, _): (Quoted, Type, Quoted)| { + quote { <$param_type as $crate::traits::Deserialize>::N } - }) - .join(quote {+}); + }) + .join(quote {+}) + } else { + quote {0} + }; // For structs containing a single member, we can enhance performance by directly deserializing the input array, // bypassing the need for loop-based array construction. While this optimization yields significant benefits in @@ -269,11 +275,15 @@ pub(crate) comptime fn derive_deserialize(s: TypeDefinition) -> Quoted { Self { $struct_members } } - } else { + } else if params.len() == 1 { let param_name = params[0].0; quote { Self { $param_name: $crate::traits::Deserialize::deserialize(serialized) } } + } else { + quote { + Self {} + } }; quote { @@ -365,14 +375,20 @@ pub comptime fn derive_packable(s: TypeDefinition) -> Quoted { let generics_declarations = get_generics_declarations(s); let where_packable_clause = get_where_trait_clause(s, quote {Packable}); - // The following will give us ::N + ::N + ... - let right_hand_side_of_definition_of_n = params - .map(|(_, param_type, _): (Quoted, Type, Quoted)| { - quote { + // The following will give us: + // ::N + ::N + ... + // (or 0 if the struct has no members) + let right_hand_side_of_definition_of_n = if params.len() > 0 { + params + .map(|(_, param_type, _): (Quoted, Type, Quoted)| { + quote { <$param_type as $crate::traits::Packable>::N } - }) - .join(quote {+}); + }) + .join(quote {+}) + } else { + quote {0} + }; // For structs containing a single member, we can enhance performance by directly returning the packed member, // bypassing the need for loop-based array construction. While this optimization yields significant benefits in @@ -404,11 +420,15 @@ pub comptime fn derive_packable(s: TypeDefinition) -> Quoted { result } - } else { + } else if params.len() == 1 { let param_name = params[0].0; quote { $crate::traits::Packable::pack(self.$param_name) } + } else { + quote { + [0; Self::N] + } }; // For structs containing a single member, we can enhance performance by directly unpacking the input array, @@ -443,11 +463,15 @@ pub comptime fn derive_packable(s: TypeDefinition) -> Quoted { $unpacking_of_struct_members Self { $struct_members } } - } else { + } else if params.len() == 1 { let param_name = params[0].0; quote { Self { $param_name: $crate::traits::Packable::unpack(packed) } } + } else { + quote { + Self {} + } }; quote { @@ -472,6 +496,9 @@ pub comptime fn derive_packable(s: TypeDefinition) -> Quoted { mod test { use crate::traits::{Deserialize, Packable, Serialize}; + #[derive(Deserialize, Eq, Packable, Serialize)] + pub struct Empty {} + #[derive(Deserialize, Eq, Packable, Serialize)] pub struct Smol { a: Field, @@ -498,6 +525,24 @@ mod test { pub length: u32, } + #[test] + fn serde_on_empty() { + let original = Empty {}; + let serialized = original.serialize(); + assert_eq(serialized, [], "Serialized does not match empty array"); + let deserialized = Empty::deserialize(serialized); + assert_eq(deserialized, original, "Deserialized does not match original"); + } + + #[test] + fn packable_on_empty() { + let original = Empty {}; + let packed = original.pack(); + assert_eq(packed, [], "Packed does not match empty array"); + let unpacked = Empty::unpack(packed); + assert_eq(unpacked, original, "Unpacked does not match original"); + } + #[test] fn serde_on_smol() { let smol = Smol { a: 1, b: 2 };