From 5924911686d5cff2309dccfd9ad41c74908e014d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Baranx?= Date: Mon, 11 Mar 2024 09:33:27 +0700 Subject: [PATCH] fix: handle primitive and custom types for enum introspect (#1643) The function `handle_introspect_enum` handles the derive Introspect attribute for an enum. At the moment, two cases are supported: tuples and type paths. A type path may be a primitive type or a custom type (struct or enum). A tuple may be composed of primitive and/or custom types. This PR updates the function `handle_introspect_enum` to handle all these cases properly. --- crates/dojo-lang/src/introspect.rs | 48 ++-- .../dojo-lang/src/plugin_test_data/introspect | 244 ++++++++++++++---- 2 files changed, 225 insertions(+), 67 deletions(-) diff --git a/crates/dojo-lang/src/introspect.rs b/crates/dojo-lang/src/introspect.rs index 0c9feb61d0..827690dbbf 100644 --- a/crates/dojo-lang/src/introspect.rs +++ b/crates/dojo-lang/src/introspect.rs @@ -144,6 +144,26 @@ pub fn handle_introspect_struct( handle_introspect_internal(db, name, struct_ast.generic_params(db), vec![], 0, type_ty, members) } +/// Generates enum arm type introspect +pub fn handle_enum_arm_type(ty_name: &String, is_primitive: bool) -> (String, String) { + let serialized = if is_primitive { + format!( + "dojo::database::introspect::serialize_member_type( + @dojo::database::introspect::Ty::Primitive('{}') + )", + ty_name + ) + } else { + format!( + "dojo::database::introspect::serialize_member_type( + @dojo::database::introspect::Introspect::<{}>::ty() + )", + ty_name + ) + }; + (serialized, ty_name.to_string()) +} + /// A handler for Dojo code derives Introspect for an enum /// Parameters: /// * db: The semantic database. @@ -155,6 +175,8 @@ pub fn handle_introspect_enum( diagnostics: &mut Vec, enum_ast: ItemEnum, ) -> RewriteNode { + let primitive_sizes = primitive_type_introspection(); + let name = enum_ast.name(db).text(db).into(); let variant_type = enum_ast.variants(db).elements(db).first().unwrap().type_clause(db); @@ -167,29 +189,15 @@ pub fn handle_introspect_enum( let args = (*paren_list.expressions(db)).elements(db); args.iter().for_each(|arg| { let ty_name = arg.as_syntax_node().get_text(db); - variant_type_arr.push(( - // Not using Ty right now, but still keeping it for later. - format!( - "dojo::database::introspect::serialize_member_type( - @dojo::database::introspect::Ty::Primitive('{}') - )", - ty_name - ), - ty_name, - )); + let is_primitive = primitive_sizes.get(&ty_name).is_some(); + + variant_type_arr.push(handle_enum_arm_type(&ty_name, is_primitive)); }); } else if let Expr::Path(type_path) = types_tuple.ty(db) { let ty_name = type_path.as_syntax_node().get_text(db); - variant_type_arr.push(( - // Not using Ty right now, but still keeping it for later. - format!( - "dojo::database::introspect::serialize_member_type( - @dojo::database::introspect::Introspect::<{}>::ty() - )", - ty_name - ), - ty_name, - )); + let is_primitive = primitive_sizes.get(&ty_name).is_some(); + + variant_type_arr.push(handle_enum_arm_type(&ty_name, is_primitive)); } else { diagnostics.push(PluginDiagnostic { stable_ptr: types_tuple.stable_ptr().0, diff --git a/crates/dojo-lang/src/plugin_test_data/introspect b/crates/dojo-lang/src/plugin_test_data/introspect index 210ad28b58..872d50f34f 100644 --- a/crates/dojo-lang/src/plugin_test_data/introspect +++ b/crates/dojo-lang/src/plugin_test_data/introspect @@ -19,13 +19,13 @@ enum PlainEnum { } #[derive(Serde, Copy, Drop, Introspect)] -enum EnumPrimitive { +enum EnumTupleOnePrimitive { Left: (u16,), Right: (u16,), } #[derive(Serde, Copy, Drop, Introspect)] -enum EnumTuple { +enum EnumTupleSeveralPrimitive { Left: (u8, u8), Right: (u8, u8), } @@ -36,6 +36,18 @@ enum EnumCustom { Right: Vec2, } +#[derive(Serde, Copy, Drop, Introspect)] +enum EnumPrimitive{ + Left: u64, + Right: u64 +} + +#[derive(Serde, Copy, Drop, Introspect)] +enum EnumTupleMix{ + Left: (Vec2, u64, EnumCustom), + Right: (Vec2, u64, EnumCustom), +} + #[derive(Copy, Drop, Introspect)] struct Position { #[key] @@ -84,13 +96,13 @@ enum PlainEnum { } #[derive(Serde, Copy, Drop, Introspect)] -enum EnumPrimitive { +enum EnumTupleOnePrimitive { Left: (u16,), Right: (u16,), } #[derive(Serde, Copy, Drop, Introspect)] -enum EnumTuple { +enum EnumTupleSeveralPrimitive { Left: (u8, u8), Right: (u8, u8), } @@ -101,6 +113,18 @@ enum EnumCustom { Right: Vec2, } +#[derive(Serde, Copy, Drop, Introspect)] +enum EnumPrimitive{ + Left: u64, + Right: u64 +} + +#[derive(Serde, Copy, Drop, Introspect)] +enum EnumTupleMix{ + Left: (Vec2, u64, EnumCustom), + Right: (Vec2, u64, EnumCustom), +} + #[derive(Copy, Drop, Introspect)] struct Position { #[key] @@ -230,28 +254,28 @@ impl PlainEnumIntrospect<> of dojo::database::introspect::Introspect ) } } -impl EnumPrimitiveSerde of core::serde::Serde:: { - fn serialize(self: @EnumPrimitive, ref output: core::array::Array) { +impl EnumTupleOnePrimitiveSerde of core::serde::Serde:: { + fn serialize(self: @EnumTupleOnePrimitive, ref output: core::array::Array) { match self { - EnumPrimitive::Left(x) => { core::serde::Serde::serialize(@0, ref output); core::serde::Serde::serialize(x, ref output); }, - EnumPrimitive::Right(x) => { core::serde::Serde::serialize(@1, ref output); core::serde::Serde::serialize(x, ref output); }, + EnumTupleOnePrimitive::Left(x) => { core::serde::Serde::serialize(@0, ref output); core::serde::Serde::serialize(x, ref output); }, + EnumTupleOnePrimitive::Right(x) => { core::serde::Serde::serialize(@1, ref output); core::serde::Serde::serialize(x, ref output); }, } } - fn deserialize(ref serialized: core::array::Span) -> core::option::Option { + fn deserialize(ref serialized: core::array::Span) -> core::option::Option { let idx: felt252 = core::serde::Serde::deserialize(ref serialized)?; core::option::Option::Some( match idx { - 0 => EnumPrimitive::Left(core::serde::Serde::deserialize(ref serialized)?), - 1 => EnumPrimitive::Right(core::serde::Serde::deserialize(ref serialized)?), + 0 => EnumTupleOnePrimitive::Left(core::serde::Serde::deserialize(ref serialized)?), + 1 => EnumTupleOnePrimitive::Right(core::serde::Serde::deserialize(ref serialized)?), _ => { return core::option::Option::None; } } ) } } -impl EnumPrimitiveCopy of core::traits::Copy::; -impl EnumPrimitiveDrop of core::traits::Drop::; +impl EnumTupleOnePrimitiveCopy of core::traits::Copy::; +impl EnumTupleOnePrimitiveDrop of core::traits::Drop::; -impl EnumPrimitiveIntrospect<> of dojo::database::introspect::Introspect> { +impl EnumTupleOnePrimitiveIntrospect<> of dojo::database::introspect::Introspect> { #[inline(always)] fn size() -> usize { 2 @@ -268,48 +292,48 @@ layout.append(16); fn ty() -> dojo::database::introspect::Ty { dojo::database::introspect::Ty::Enum( dojo::database::introspect::Enum { - name: 'EnumPrimitive', + name: 'EnumTupleOnePrimitive', attrs: array![].span(), children: array![( 'Left', dojo::database::introspect::serialize_member_type( @dojo::database::introspect::Ty::Tuple(array![dojo::database::introspect::serialize_member_type( - @dojo::database::introspect::Ty::Primitive('u16') - )].span())) + @dojo::database::introspect::Ty::Primitive('u16') + )].span())) ), ( 'Right', dojo::database::introspect::serialize_member_type( @dojo::database::introspect::Ty::Tuple(array![dojo::database::introspect::serialize_member_type( - @dojo::database::introspect::Ty::Primitive('u16') - )].span())) + @dojo::database::introspect::Ty::Primitive('u16') + )].span())) )].span() } ) } } -impl EnumTupleSerde of core::serde::Serde:: { - fn serialize(self: @EnumTuple, ref output: core::array::Array) { +impl EnumTupleSeveralPrimitiveSerde of core::serde::Serde:: { + fn serialize(self: @EnumTupleSeveralPrimitive, ref output: core::array::Array) { match self { - EnumTuple::Left(x) => { core::serde::Serde::serialize(@0, ref output); core::serde::Serde::serialize(x, ref output); }, - EnumTuple::Right(x) => { core::serde::Serde::serialize(@1, ref output); core::serde::Serde::serialize(x, ref output); }, + EnumTupleSeveralPrimitive::Left(x) => { core::serde::Serde::serialize(@0, ref output); core::serde::Serde::serialize(x, ref output); }, + EnumTupleSeveralPrimitive::Right(x) => { core::serde::Serde::serialize(@1, ref output); core::serde::Serde::serialize(x, ref output); }, } } - fn deserialize(ref serialized: core::array::Span) -> core::option::Option { + fn deserialize(ref serialized: core::array::Span) -> core::option::Option { let idx: felt252 = core::serde::Serde::deserialize(ref serialized)?; core::option::Option::Some( match idx { - 0 => EnumTuple::Left(core::serde::Serde::deserialize(ref serialized)?), - 1 => EnumTuple::Right(core::serde::Serde::deserialize(ref serialized)?), + 0 => EnumTupleSeveralPrimitive::Left(core::serde::Serde::deserialize(ref serialized)?), + 1 => EnumTupleSeveralPrimitive::Right(core::serde::Serde::deserialize(ref serialized)?), _ => { return core::option::Option::None; } } ) } } -impl EnumTupleCopy of core::traits::Copy::; -impl EnumTupleDrop of core::traits::Drop::; +impl EnumTupleSeveralPrimitiveCopy of core::traits::Copy::; +impl EnumTupleSeveralPrimitiveDrop of core::traits::Drop::; -impl EnumTupleIntrospect<> of dojo::database::introspect::Introspect> { +impl EnumTupleSeveralPrimitiveIntrospect<> of dojo::database::introspect::Introspect> { #[inline(always)] fn size() -> usize { 3 @@ -327,25 +351,25 @@ layout.append(8); fn ty() -> dojo::database::introspect::Ty { dojo::database::introspect::Ty::Enum( dojo::database::introspect::Enum { - name: 'EnumTuple', + name: 'EnumTupleSeveralPrimitive', attrs: array![].span(), children: array![( 'Left', dojo::database::introspect::serialize_member_type( @dojo::database::introspect::Ty::Tuple(array![dojo::database::introspect::serialize_member_type( - @dojo::database::introspect::Ty::Primitive('u8') - ), dojo::database::introspect::serialize_member_type( - @dojo::database::introspect::Ty::Primitive('u8') - )].span())) + @dojo::database::introspect::Ty::Primitive('u8') + ), dojo::database::introspect::serialize_member_type( + @dojo::database::introspect::Ty::Primitive('u8') + )].span())) ), ( 'Right', dojo::database::introspect::serialize_member_type( @dojo::database::introspect::Ty::Tuple(array![dojo::database::introspect::serialize_member_type( - @dojo::database::introspect::Ty::Primitive('u8') - ), dojo::database::introspect::serialize_member_type( - @dojo::database::introspect::Ty::Primitive('u8') - )].span())) + @dojo::database::introspect::Ty::Primitive('u8') + ), dojo::database::introspect::serialize_member_type( + @dojo::database::introspect::Ty::Primitive('u8') + )].span())) )].span() } ) @@ -395,15 +419,141 @@ dojo::database::introspect::Introspect::::layout(ref layout); 'Left', dojo::database::introspect::serialize_member_type( @dojo::database::introspect::Ty::Tuple(array![dojo::database::introspect::serialize_member_type( - @dojo::database::introspect::Introspect::::ty() - )].span())) + @dojo::database::introspect::Introspect::::ty() + )].span())) ), ( 'Right', dojo::database::introspect::serialize_member_type( @dojo::database::introspect::Ty::Tuple(array![dojo::database::introspect::serialize_member_type( - @dojo::database::introspect::Introspect::::ty() - )].span())) + @dojo::database::introspect::Introspect::::ty() + )].span())) + )].span() + } + ) + } +} +impl EnumPrimitiveSerde of core::serde::Serde:: { + fn serialize(self: @EnumPrimitive, ref output: core::array::Array) { + match self { + EnumPrimitive::Left(x) => { core::serde::Serde::serialize(@0, ref output); core::serde::Serde::serialize(x, ref output); }, + EnumPrimitive::Right(x) => { core::serde::Serde::serialize(@1, ref output); core::serde::Serde::serialize(x, ref output); }, + } + } + fn deserialize(ref serialized: core::array::Span) -> core::option::Option { + let idx: felt252 = core::serde::Serde::deserialize(ref serialized)?; + core::option::Option::Some( + match idx { + 0 => EnumPrimitive::Left(core::serde::Serde::deserialize(ref serialized)?), + 1 => EnumPrimitive::Right(core::serde::Serde::deserialize(ref serialized)?), + _ => { return core::option::Option::None; } + } + ) + } +} +impl EnumPrimitiveCopy of core::traits::Copy::; +impl EnumPrimitiveDrop of core::traits::Drop::; + +impl EnumPrimitiveIntrospect<> of dojo::database::introspect::Introspect> { + #[inline(always)] + fn size() -> usize { + 2 + } + + #[inline(always)] + fn layout(ref layout: Array) { + layout.append(8); +layout.append(64); + + } + + #[inline(always)] + fn ty() -> dojo::database::introspect::Ty { + dojo::database::introspect::Ty::Enum( + dojo::database::introspect::Enum { + name: 'EnumPrimitive', + attrs: array![].span(), + children: array![( + 'Left', + dojo::database::introspect::serialize_member_type( + @dojo::database::introspect::Ty::Tuple(array![dojo::database::introspect::serialize_member_type( + @dojo::database::introspect::Ty::Primitive('u64') + )].span())) + ), +( + 'Right', + dojo::database::introspect::serialize_member_type( + @dojo::database::introspect::Ty::Tuple(array![dojo::database::introspect::serialize_member_type( + @dojo::database::introspect::Ty::Primitive('u64') + )].span())) + )].span() + } + ) + } +} +impl EnumTupleMixSerde of core::serde::Serde:: { + fn serialize(self: @EnumTupleMix, ref output: core::array::Array) { + match self { + EnumTupleMix::Left(x) => { core::serde::Serde::serialize(@0, ref output); core::serde::Serde::serialize(x, ref output); }, + EnumTupleMix::Right(x) => { core::serde::Serde::serialize(@1, ref output); core::serde::Serde::serialize(x, ref output); }, + } + } + fn deserialize(ref serialized: core::array::Span) -> core::option::Option { + let idx: felt252 = core::serde::Serde::deserialize(ref serialized)?; + core::option::Option::Some( + match idx { + 0 => EnumTupleMix::Left(core::serde::Serde::deserialize(ref serialized)?), + 1 => EnumTupleMix::Right(core::serde::Serde::deserialize(ref serialized)?), + _ => { return core::option::Option::None; } + } + ) + } +} +impl EnumTupleMixCopy of core::traits::Copy::; +impl EnumTupleMixDrop of core::traits::Drop::; + +impl EnumTupleMixIntrospect<> of dojo::database::introspect::Introspect> { + #[inline(always)] + fn size() -> usize { + dojo::database::introspect::Introspect::::size() + dojo::database::introspect::Introspect::::size() + 2 + } + + #[inline(always)] + fn layout(ref layout: Array) { + layout.append(8); +dojo::database::introspect::Introspect::::layout(ref layout); +layout.append(64); +dojo::database::introspect::Introspect::::layout(ref layout); + + } + + #[inline(always)] + fn ty() -> dojo::database::introspect::Ty { + dojo::database::introspect::Ty::Enum( + dojo::database::introspect::Enum { + name: 'EnumTupleMix', + attrs: array![].span(), + children: array![( + 'Left', + dojo::database::introspect::serialize_member_type( + @dojo::database::introspect::Ty::Tuple(array![dojo::database::introspect::serialize_member_type( + @dojo::database::introspect::Introspect::::ty() + ), dojo::database::introspect::serialize_member_type( + @dojo::database::introspect::Ty::Primitive('u64') + ), dojo::database::introspect::serialize_member_type( + @dojo::database::introspect::Introspect::::ty() + )].span())) + ), +( + 'Right', + dojo::database::introspect::serialize_member_type( + @dojo::database::introspect::Ty::Tuple(array![dojo::database::introspect::serialize_member_type( + @dojo::database::introspect::Introspect::::ty() + ), dojo::database::introspect::serialize_member_type( + @dojo::database::introspect::Ty::Primitive('u64') + ), dojo::database::introspect::serialize_member_type( + @dojo::database::introspect::Introspect::::ty() + )].span())) )].span() } ) @@ -626,26 +776,26 @@ impl FeltsArrayBadCapacityIntrospect expected_diagnostics error: Unsupported attribute. - --> test_src/lib.cairo:49:5 + --> test_src/lib.cairo:61:5 #[capacity(10)] ^*************^ error: Capacity is only supported for Array or Span. - --> test_src/lib.cairo:55:5 + --> test_src/lib.cairo:67:5 #[capacity(10)] ^*************^ error: Unsupported attribute. - --> test_src/lib.cairo:55:5 + --> test_src/lib.cairo:67:5 #[capacity(10)] ^*************^ error: Capacity must be greater than 0. - --> test_src/lib.cairo:61:5 + --> test_src/lib.cairo:73:5 #[capacity(0)] ^************^ error: Unsupported attribute. - --> test_src/lib.cairo:61:5 + --> test_src/lib.cairo:73:5 #[capacity(0)] ^************^