From 7fa95129fe2c3a82aedbd1a38b59eb667ad5102e Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Thu, 11 Jan 2024 18:30:34 -0800 Subject: [PATCH] Implement ISerialize as well as ISerialize One more step in replacing ISerialize with ISerialize. --- src/generator/Generator.Deserialize.cs | 2 +- src/generator/Generator.Impl.cs | 14 +- src/generator/Generator.Serialize.Generic.cs | 871 ++++++++++++++++++ src/generator/Generator.Wrapper.cs | 1 + src/generator/SymbolUtilities.cs | 2 +- src/generator/WellKnownTypes.cs | 1 + src/serde-xml/XmlSerializer.cs | 4 +- src/serde/ISerialize.cs | 31 +- src/serde/Wrappers.Dictionary.cs | 39 +- src/serde/Wrappers.List.cs | 34 +- src/serde/Wrappers.cs | 107 ++- src/serde/json/JsonSerializer.cs | 17 +- src/serde/json/JsonSerializerImpl.cs | 3 +- src/serde/json/JsonValue.Serialize.cs | 6 +- test/Serde.Generation.Test/SerializeTests.cs | 40 +- ...One.ColorEnumWrap.ISerialize`1.verified.cs | 26 + ...rde.Test.AllInOne.ISerialize`1.verified.cs | 33 + .../S.ISerialize`1.verified.cs | 16 + .../S.ISerialize`1.verified.cs | 16 + .../ColorEnumWrap.ISerialize`1.verified.cs | 20 + .../S.ISerialize`1.verified.cs | 15 + .../S2.ISerialize`1.verified.cs | 15 + .../S.ISerialize`1.verified.cs | 16 + ...TestCase15.Class0.ISerialize`1.verified.cs | 19 + ...TestCase15.Class1.ISerialize`1.verified.cs | 19 + .../C.ISerialize`1.verified.cs | 15 + .../C2.ISerialize`1.verified.cs | 15 + ...ested.Namespace.C.ISerialize`1.verified.cs | 21 + ...ace.ColorByteWrap.ISerialize`1.verified.cs | 23 + ...pace.ColorIntWrap.ISerialize`1.verified.cs | 23 + ...ace.ColorLongWrap.ISerialize`1.verified.cs | 23 + ...ce.ColorULongWrap.ISerialize`1.verified.cs | 23 + .../C.ISerialize`1.verified.cs | 15 + .../RgbWrap.ISerialize`1.verified.cs | 20 + .../OPTSWrap.ISerialize`1.verified.cs | 18 + .../S.ISerialize`1.verified.cs | 15 + .../SectionWrap.ISerialize`1.verified.cs | 16 + ...tionaryGenerate#C.ISerialize`1.verified.cs | 15 + ...tGenericWrapper#C.ISerialize`1.verified.cs | 15 + ...ExplicitWrapper#C.ISerialize`1.verified.cs | 15 + ...aryImplGenerate#C.ISerialize`1.verified.cs | 15 + .../MemberSkip#Rgb.ISerialize`1.verified.cs | 16 + ...ipDeserialize#Rgb.ISerialize`1.verified.cs | 17 + ...SkipSerialize#Rgb.ISerialize`1.verified.cs | 16 + .../NestedArray#C.ISerialize`1.verified.cs | 15 + .../NestedArray2#C.ISerialize`1.verified.cs | 15 + .../NullableFields#S.ISerialize`1.verified.cs | 16 + ...llableRefFields#S.ISerialize`1.verified.cs | 19 + .../Rgb#Rgb.ISerialize`1.verified.cs | 17 + ...mentISerialize#S1.ISerialize`1.verified.cs | 14 + .../TypeWithArray#C.ISerialize`1.verified.cs | 15 + ...ericWrapperForm#C.ISerialize`1.verified.cs | 14 + .../WrongGenericWrapperForm.verified.txt | 4 +- .../Address.ISerialize`1.verified.cs | 19 + .../OPTSWrap.ISerialize`1.verified.cs | 18 + .../OPTSWrap.ISerialize`1.verified.cs | 18 + ...Outer.SectionWrap.ISerialize`1.verified.cs | 19 + .../S.ISerialize`1.verified.cs | 15 + .../PointWrap.ISerialize`1.verified.cs | 16 + .../Test.Parent.ISerialize`1.verified.cs | 18 + ...est.RecursiveWrap.ISerialize`1.verified.cs | 18 + test/Serde.Test/GenericWrapperTests.cs | 8 +- test/Serde.Test/JsonSerializerTests.cs | 14 +- test/Serde.Test/RoundtripTests.cs | 2 +- ...est.AllInOne.ColorEnumWrap.ISerialize`1.cs | 25 + .../Serde.Test.AllInOne.ISerialize`1.cs | 32 + ...tomArrayWrapExplicitOnType.ISerialize`1.cs | 20 + ...mArrayExplicitWrapOnMember.ISerialize`1.cs | 20 + ...alizerTests.NullableFields.ISerialize`1.cs | 21 + .../Serde.Test.MaxSizeType.ISerialize`1.cs | 80 ++ ...est.AllInOne.ColorEnumWrap.ISerialize`1.cs | 25 + .../Serde.Test.AllInOne.ISerialize`1.cs | 32 + ...de.Test.SampleTest.Address.ISerialize`1.cs | 24 + ...est.SampleTest.OrderedItem.ISerialize`1.cs | 24 + ...t.SampleTest.PurchaseOrder.ISerialize`1.cs | 25 + ...e.Test.XmlTests.BoolStruct.ISerialize`1.cs | 20 + ...rde.Test.XmlTests.MapTest1.ISerialize`1.cs | 20 + ...Test.XmlTests.NestedArrays.ISerialize`1.cs | 20 + ...mlTests.StructWithIntField.ISerialize`1.cs | 20 + ...mlTests.TypeWithArrayField.ISerialize`1.cs | 20 + 80 files changed, 2362 insertions(+), 63 deletions(-) create mode 100644 src/generator/Generator.Serialize.Generic.cs create mode 100644 test/Serde.Generation.Test/test_output/AllInOneTest.GeneratorTest/Serde.Test.AllInOne.ColorEnumWrap.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/AllInOneTest.GeneratorTest/Serde.Test.AllInOne.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/MemberFormatTests.CamelCase/S.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/MemberFormatTests.Default/S.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/MemberFormatTests.EnumValues/ColorEnumWrap.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/MemberFormatTests.EnumValues/S.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/MemberFormatTests.EnumValues/S2.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/MemberFormatTests.KebabCase/S.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests.ArrayOfGenerateSerialize/TestCase15.Class0.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests.ArrayOfGenerateSerialize/TestCase15.Class1.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests.DictionaryGenerate2/C.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests.DictionaryGenerate2/C2.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests.EnumMember/Some.Nested.Namespace.C.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests.EnumMember/Some.Nested.Namespace.ColorByteWrap.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests.EnumMember/Some.Nested.Namespace.ColorIntWrap.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests.EnumMember/Some.Nested.Namespace.ColorLongWrap.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests.EnumMember/Some.Nested.Namespace.ColorULongWrap.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests.NestedEnumWrapper/C.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests.NestedEnumWrapper/RgbWrap.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests.NestedExplicitSerializeWrapper/OPTSWrap.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests.NestedExplicitSerializeWrapper/S.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests.SerializeOnlyWrapper/SectionWrap.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests/DictionaryGenerate#C.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests/ExplicitGenericWrapper#C.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests/ExplicitWrapper#C.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests/IDictionaryImplGenerate#C.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests/MemberSkip#Rgb.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests/MemberSkipDeserialize#Rgb.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests/MemberSkipSerialize#Rgb.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests/NestedArray#C.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests/NestedArray2#C.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests/NullableFields#S.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests/NullableRefFields#S.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests/Rgb#Rgb.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests/TypeDoesntImplementISerialize#S1.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests/TypeWithArray#C.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests/WrongGenericWrapperForm#C.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/WrapperTests.AttributeWrapperTest/Address.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/WrapperTests.GenerateSerdeWrap/OPTSWrap.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/WrapperTests.NestedDeserializeWrap/OPTSWrap.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/WrapperTests.NestedExplicitWrapper/Outer.SectionWrap.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/WrapperTests.NestedExplicitWrapper/S.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/WrapperTests.PointWrap/PointWrap.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/WrapperTests.RecursiveType/Test.Parent.ISerialize`1.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/WrapperTests.RecursiveType/Test.RecursiveWrap.ISerialize`1.verified.cs create mode 100644 test/Serde.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.AllInOne.ColorEnumWrap.ISerialize`1.cs create mode 100644 test/Serde.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.AllInOne.ISerialize`1.cs create mode 100644 test/Serde.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.GenericWrapperTests.CustomArrayWrapExplicitOnType.ISerialize`1.cs create mode 100644 test/Serde.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.GenericWrapperTests.CustomImArrayExplicitWrapOnMember.ISerialize`1.cs create mode 100644 test/Serde.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.JsonSerializerTests.NullableFields.ISerialize`1.cs create mode 100644 test/Serde.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.MaxSizeType.ISerialize`1.cs create mode 100644 test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.AllInOne.ColorEnumWrap.ISerialize`1.cs create mode 100644 test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.AllInOne.ISerialize`1.cs create mode 100644 test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.SampleTest.Address.ISerialize`1.cs create mode 100644 test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.SampleTest.OrderedItem.ISerialize`1.cs create mode 100644 test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.SampleTest.PurchaseOrder.ISerialize`1.cs create mode 100644 test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.XmlTests.BoolStruct.ISerialize`1.cs create mode 100644 test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.XmlTests.MapTest1.ISerialize`1.cs create mode 100644 test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.XmlTests.NestedArrays.ISerialize`1.cs create mode 100644 test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.XmlTests.StructWithIntField.ISerialize`1.cs create mode 100644 test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.XmlTests.TypeWithArrayField.ISerialize`1.cs diff --git a/src/generator/Generator.Deserialize.cs b/src/generator/Generator.Deserialize.cs index 377343db..7723f614 100644 --- a/src/generator/Generator.Deserialize.cs +++ b/src/generator/Generator.Deserialize.cs @@ -16,7 +16,7 @@ partial class SerdeImplRoslynGenerator { private const string GeneratedVisitorName = "SerdeVisitor"; - private static (MemberDeclarationSyntax[], BaseListSyntax) GenerateDeserializeImpl( + internal static (MemberDeclarationSyntax[], BaseListSyntax) GenerateDeserializeImpl( GeneratorExecutionContext context, ITypeSymbol receiverType, ExpressionSyntax receiverExpr, diff --git a/src/generator/Generator.Impl.cs b/src/generator/Generator.Impl.cs index aa3990f1..2f43816c 100644 --- a/src/generator/Generator.Impl.cs +++ b/src/generator/Generator.Impl.cs @@ -128,6 +128,18 @@ partial class SerdeImplRoslynGenerator context); } + if (usage.HasFlag(SerdeUsage.Serialize)) + { + SerializeImplRoslynGenerator.GenerateImpl( + usage, + new TypeDeclContext(typeDecl), + receiverType, + IdentifierName("value"), + context, + inProgress); + + } + GenerateImpl( usage, new TypeDeclContext(typeDecl), @@ -346,7 +358,7 @@ private static bool ImplementsSerde(ITypeSymbol memberType, GeneratorExecutionCo private static string GetWrapperName(string typeName) => typeName + "Wrap"; - private static bool HasGenerateAttribute(ITypeSymbol memberType, SerdeUsage usage) + internal static bool HasGenerateAttribute(ITypeSymbol memberType, SerdeUsage usage) { var attributes = memberType.GetAttributes(); foreach (var attr in attributes) diff --git a/src/generator/Generator.Serialize.Generic.cs b/src/generator/Generator.Serialize.Generic.cs new file mode 100644 index 00000000..606e5d0e --- /dev/null +++ b/src/generator/Generator.Serialize.Generic.cs @@ -0,0 +1,871 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; +using static Serde.Diagnostics; +using static Serde.WellKnownTypes; + +namespace Serde +{ + public partial class SerializeImplRoslynGenerator + { + private static void GenerateISerializeWrapImpl( + string wrapperName, + string wrappedName, + BaseTypeDeclarationSyntax typeDecl, + GeneratorExecutionContext context) + { + var typeDeclContext = new TypeDeclContext(typeDecl); + var newType = SyntaxFactory.ParseMemberDeclaration($$""" +partial record struct {{wrapperName}} : Serde.ISerializeWrap<{{wrappedName}}, {{wrapperName}}> +{ + static {{wrapperName}} Serde.ISerializeWrap<{{wrappedName}}, {{wrapperName}}>.Create({{wrappedName}} value) => new(value); +} +""")!; + newType = typeDeclContext.WrapNewType(newType); + string fullWrapperName = string.Join(".", typeDeclContext.NamespaceNames + .Concat(typeDeclContext.ParentTypeInfo.Select(x => x.Name)) + .Concat(new[] { wrapperName })); + + var tree = CompilationUnit( + externs: default, + usings: default, + attributeLists: default, + members: List(new[] { newType })); + tree = tree.NormalizeWhitespace(eol: Environment.NewLine); + + context.AddSource($"{fullWrapperName}.ISerializeWrap", Environment.NewLine + tree.ToFullString()); + } + + internal static void GenerateImpl( + SerdeUsage usage, + TypeDeclContext typeDeclContext, + ITypeSymbol receiverType, + ExpressionSyntax receiverExpr, + GeneratorExecutionContext context, + ImmutableList inProgress) + { + var typeName = typeDeclContext.Name; + + // Generate statements for the implementation + var (implMembers, baseList) = usage switch + { + SerdeUsage.Serialize => GenerateSerializeGenericImpl(context, receiverType, receiverExpr, inProgress), + SerdeUsage.Deserialize => SerdeImplRoslynGenerator.GenerateDeserializeImpl(context, receiverType, receiverExpr, inProgress), + _ => throw ExceptionUtilities.Unreachable + }; + + var typeKind = typeDeclContext.Kind; + MemberDeclarationSyntax newType; + if (typeKind == SyntaxKind.EnumDeclaration) + { + var wrapperName = GetWrapperName(typeName); + newType = RecordDeclaration( + kind: SyntaxKind.RecordStructDeclaration, + attributeLists: default, + modifiers: TokenList(Token(SyntaxKind.PartialKeyword)), + keyword: Token(SyntaxKind.RecordKeyword), + classOrStructKeyword: Token(SyntaxKind.StructKeyword), + identifier: Identifier(wrapperName), + typeParameterList: default, + parameterList: null, + baseList: baseList, + constraintClauses: default, + openBraceToken: Token(SyntaxKind.OpenBraceToken), + members: List(implMembers), + closeBraceToken: Token(SyntaxKind.CloseBraceToken), + semicolonToken: default); + typeName = wrapperName; + } + else + { + newType = TypeDeclaration( + typeKind, + attributes: default, + modifiers: TokenList(Token(SyntaxKind.PartialKeyword)), + keyword: Token(typeKind switch + { + SyntaxKind.ClassDeclaration => SyntaxKind.ClassKeyword, + SyntaxKind.StructDeclaration => SyntaxKind.StructKeyword, + SyntaxKind.RecordDeclaration + or SyntaxKind.RecordStructDeclaration => SyntaxKind.RecordKeyword, + _ => throw ExceptionUtilities.Unreachable + }), + identifier: Identifier(typeName), + typeParameterList: typeDeclContext.TypeParameterList, + baseList: baseList, + constraintClauses: default, + openBraceToken: Token(SyntaxKind.OpenBraceToken), + members: List(implMembers), + closeBraceToken: Token(SyntaxKind.CloseBraceToken), + semicolonToken: default); + } + string fullTypeName = string.Join(".", typeDeclContext.NamespaceNames + .Concat(typeDeclContext.ParentTypeInfo.Select(x => x.Name)) + .Concat(new[] { typeName })); + + var srcName = fullTypeName + "." + usage.GetInterfaceName() + "`1"; + + newType = typeDeclContext.WrapNewType(newType); + + var tree = CompilationUnit( + externs: default, + usings: List(new[] { UsingDirective(IdentifierName("System")), UsingDirective(IdentifierName("Serde")) }), + attributeLists: default, + members: List(new[] { newType })); + tree = tree.NormalizeWhitespace(eol: Environment.NewLine); + + context.AddSource(srcName, + Environment.NewLine + "#nullable enable" + Environment.NewLine + tree.ToFullString()); + } + + private static string GetWrapperName(string typeName) => typeName + "Wrap"; + + private static (MemberDeclarationSyntax[], BaseListSyntax) GenerateSerializeGenericImpl( + GeneratorExecutionContext context, + ITypeSymbol receiverType, + ExpressionSyntax receiverExpr, + ImmutableList inProgress) + { + var statements = new List(); + var fieldsAndProps = SymbolUtilities.GetDataMembers(receiverType, SerdeUsage.Serialize); + + if (receiverType.TypeKind == TypeKind.Enum) + { + // For enums, the generated body should look like + // ``` + // var name = receiver switch + // { + // Enum.Case1 => "Case1", + // Enum.Case2 => "Case2", + // _ => null + // }; + // serializer.SerializeEnumValue("Enum", name, receiver); + var enumType = (INamedTypeSymbol)receiverType; + var typeSyntax = enumType.ToFqnSyntax(); + var cases = fieldsAndProps.Select(m => SwitchExpressionArm( + ConstantPattern(QualifiedName((NameSyntax)typeSyntax, IdentifierName(m.Name))), + whenClause: null, + expression: StringLiteral(m.GetFormattedName()))); + cases = cases.Concat(new[] { SwitchExpressionArm( + DiscardPattern(), + whenClause: null, + LiteralExpression(SyntaxKind.NullLiteralExpression, Token(SyntaxKind.NullKeyword))) }); + statements.Add(LocalDeclarationStatement(VariableDeclaration( + IdentifierName("var"), + SeparatedList(new[] { VariableDeclarator( + Identifier("name"), + argumentList: null, + EqualsValueClause(SwitchExpression(receiverExpr, SeparatedList(cases)))) })))); + var wrapper = TryGetPrimitiveWrapper(enumType.EnumUnderlyingType!, SerdeUsage.Serialize)!; + statements.Add(ExpressionStatement(InvocationExpression( + QualifiedName(IdentifierName("serializer"), IdentifierName("SerializeEnumValue")), + ArgumentList(SeparatedList(new[] { + Argument(StringLiteral(receiverType.Name)), + Argument(IdentifierName("name")), + Argument(ObjectCreationExpression( + wrapper, + ArgumentList(SeparatedList(new[] { Argument(CastExpression(enumType.EnumUnderlyingType!.ToFqnSyntax(), receiverExpr)) })), + null)) + })) + ))); + } + else + { + // The generated body of ISerialize is + // `var type = serializer.SerializeType("TypeName", numFields)` + // type.SerializeField("FieldName", receiver.FieldValue); + // type.End(); + + // `var type = serializer.SerializeType("TypeName", numFields)` + statements.Add(LocalDeclarationStatement(VariableDeclaration( + IdentifierName(Identifier("var")), + SeparatedList(new[] { + VariableDeclarator( + Identifier("type"), + argumentList: null, + EqualsValueClause(InvocationExpression( + QualifiedName(IdentifierName("serializer"), IdentifierName("SerializeType")), + ArgumentList(SeparatedList(new [] { + Argument(StringLiteral(receiverType.Name)), Argument(NumericLiteral(fieldsAndProps.Count)) + })) + )) + ) + }) + ))); + + foreach (var m in fieldsAndProps) + { + // Generate statements of the form `type.SerializeField("FieldName", receiver.FieldValue)` + var memberExpr = MakeMemberAccessExpr(m, receiverExpr); + var serializeImpl = MakeSerializeType(m, context, memberExpr, inProgress); + if (serializeImpl is null) + { + // No built-in handling and doesn't implement ISerialize, error + context.ReportDiagnostic(CreateDiagnostic( + DiagId.ERR_DoesntImplementInterface, + m.Locations[0], + m.Symbol, + m.Type, + "Serde.ISerialize")); + } + else + { + statements.Add(MakeSerializeFieldStmt(m, memberExpr, serializeImpl, receiverExpr)); + } + } + + // `type.End();` + statements.Add(ExpressionStatement(InvocationExpression( + QualifiedName(IdentifierName("type"), IdentifierName("End")), + ArgumentList() + ))); + } + + var receiverSyntax = ((INamedTypeSymbol)receiverType).ToFqnSyntax(); + + // Generate method `void ISerialize.Serialize(type value, ISerializer serializer) { ... }` + var members = new MemberDeclarationSyntax[] { + MethodDeclaration( + attributeLists: default, + modifiers: default, + PredefinedType(Token(SyntaxKind.VoidKeyword)), + explicitInterfaceSpecifier: ExplicitInterfaceSpecifier( + GenericName( + Identifier("ISerialize"), + TypeArgumentList(SeparatedList(new TypeSyntax[] { receiverSyntax })))), + identifier: Identifier("Serialize"), + typeParameterList: null, + parameterList: ParameterList(SeparatedList(new[] { + Parameter(receiverSyntax, "value"), + Parameter("ISerializer", "serializer") + })), + constraintClauses: default, + body: Block(statements), + expressionBody: null) + }; + var baseList = BaseList(SeparatedList(new BaseTypeSyntax[] { + SimpleBaseType(ParseTypeName($"Serde.ISerialize<{receiverType.ToDisplayString()}>")) + })); + return (members, baseList); + + // Make a statement like `type.SerializeField("member.Name", value)` + static ExpressionStatementSyntax MakeSerializeFieldStmt( + DataMemberSymbol member, + ExpressionSyntax value, + TypeSyntax serializeType, + ExpressionSyntax receiver) + { + var arguments = new List() { + // "FieldName"u8 + ParseExpression($"\"{member.GetFormattedName()}\""), + // Value + value, + }; + var typeArgs = new List() { + member.Type.ToFqnSyntax(), + serializeType + }; + + string methodName; + if (member.IsNullable && !member.SerializeNull) + { + // Use SerializeFieldIfNotNull if it's not been disabled and the field is nullable + methodName = "SerializeFieldIfNotNull"; + } + else + { + methodName = "SerializeField"; + } + + // If the member is marked as providing attributes we will need to create an array of the + // attributes and pass it as the last argument + if (member.ProvideAttributes) + { + var attributeExpressions = member.Attributes.SelectNotNull(attributeData => + { + if (attributeData.AttributeClass is not { } attrClass) + { + return null; + } + + // Construct the positional arguments to the attribute constructor + var args = attributeData.ConstructorArguments + .Select(a => Argument(ParseExpression(a.ToCSharpString()))).ToList(); + + // Construct the named arguments to the attribute constructor + var assignments = attributeData.NamedArguments.Select(pair => + (ExpressionSyntax)AssignmentExpression( + SyntaxKind.SimpleAssignmentExpression, + IdentifierName(pair.Key), + ParseExpression(pair.Value.ToCSharpString()))).ToList(); + + return (ExpressionSyntax)ObjectCreationExpression( + attrClass.ToFqnSyntax(), + ArgumentList(SeparatedList(args)), + InitializerExpression( + SyntaxKind.ObjectInitializerExpression, + SeparatedList(assignments))); + }).ToList(); + + if (attributeExpressions.Count > 0) + { + arguments.Add(ArrayCreationExpression( + ArrayType( + ParseTypeName("System.Attribute"), + SingletonList(ArrayRankSpecifier( + SingletonSeparatedList((ExpressionSyntax)OmittedArraySizeExpression())))), + InitializerExpression( + SyntaxKind.ArrayInitializerExpression, + SeparatedList(attributeExpressions)))); + } + } + + return ExpressionStatement(InvocationExpression( + // type.SerializeField + QualifiedName(IdentifierName("type"), + GenericName(Identifier(methodName), TypeArgumentList(SeparatedList(typeArgs)))), + ArgumentList(SeparatedList(arguments.Select(Argument))))); + } + } + + /// + /// Constructs the argument to a ISerializer.Serialize call, i.e. constructs a term which + /// implements ISerialize. SerdeDn provides wrappers for primitives and common types in the + /// framework. If found, we generate and initialize the wrapper. + /// + private static TypeSyntax? MakeSerializeType( + DataMemberSymbol member, + GeneratorExecutionContext context, + ExpressionSyntax memberExpr, + ImmutableList inProgress) + { + // 1. Check for an explicit wrapper + if (TryGetExplicitWrapper(member, context, SerdeUsage.Serialize, inProgress) is {} wrapper) + { + return wrapper; + } + + // 2. Check for a direct implementation of ISerialize + if (ImplementsSerde(member.Type, context, SerdeUsage.Serialize)) + { + return GenericName(Identifier("IdWrap"), TypeArgumentList(SeparatedList(new[] { member.Type.ToFqnSyntax() }))); + } + + // 3. A wrapper that implements ISerialize + var wrapperType = TryGetAnyWrapper(member.Type, context, SerdeUsage.Serialize, inProgress); + if (wrapperType is not null) + { + return wrapperType; + } + + return null; + } + + /// + /// Check to see if the type implements ISerialize or IDeserialize, depending on the WrapUsage. + /// + private static bool ImplementsSerde(ITypeSymbol memberType, GeneratorExecutionContext context, SerdeUsage usage) + { + // Nullable types are not considered as implementing the Serde interfaces -- they use wrappers to map to the underlying + if (memberType.NullableAnnotation == NullableAnnotation.Annotated || + memberType.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T) + { + return false; + } + + // Check if the type either has the GenerateSerialize attribute, or directly implements ISerialize + // (If the type has the GenerateSerialize attribute then the generator will implement the interface) + if (memberType.TypeKind is not TypeKind.Enum && SerdeImplRoslynGenerator.HasGenerateAttribute(memberType, usage)) + { + return true; + } + + INamedTypeSymbol? serdeSymbol; + if (usage == SerdeUsage.Serialize) + { + serdeSymbol = context.Compilation.GetTypeByMetadataName("Serde.ISerialize`1"); + serdeSymbol = serdeSymbol?.Construct(memberType); + } + else + { + var deserialize = context.Compilation.GetTypeByMetadataName("Serde.IDeserialize`1"); + serdeSymbol = deserialize?.Construct(memberType); + } + if (serdeSymbol is not null && memberType.Interfaces.Contains(serdeSymbol, SymbolEqualityComparer.Default) + || (memberType is ITypeParameterSymbol param && param.ConstraintTypes.Contains(serdeSymbol, SymbolEqualityComparer.Default))) + { + return true; + } + return false; + } + + private static TypeSyntax? TryGetExplicitWrapper( + DataMemberSymbol member, + GeneratorExecutionContext context, + SerdeUsage usage, + ImmutableList inProgress) + { + if (TryGetExplicitWrapperType(member, usage, context) is {} wrapperType) + { + var memberType = member.Type; + if (usage.HasFlag(SerdeUsage.Serialize)) + { + var ctor = wrapperType.Constructors.Where(c => c.Parameters.Length == 1).SingleOrDefault(); + if (ctor is { Parameters: [{ } typeArg] } && typeArg.Type.Equals(memberType, SymbolEqualityComparer.Default)) + { + return ParseTypeName(wrapperType.ToDisplayString()); + } + } + else if (usage.HasFlag(SerdeUsage.Deserialize)) + { + var deserialize = context.Compilation.GetTypeByMetadataName("Serde.IDeserialize`1")?.Construct(memberType); + if (wrapperType.Interfaces.Contains(deserialize, SymbolEqualityComparer.Default)) + { + return ParseTypeName(wrapperType.ToDisplayString()); + } + } + + var typeArgs = memberType switch + { + INamedTypeSymbol n => n.TypeArguments, + _ => ImmutableArray.Empty + }; + return MakeWrappedExpression(wrapperType, typeArgs, context, usage, inProgress); + } + return null; + + // + // Looks to see if the given member or its type explicitly specifies a wrapper to use via + // the SerdeWrapAttribute or similar. If so, returns the symbol of the wrapper type. + // + static INamedTypeSymbol? TryGetExplicitWrapperType(DataMemberSymbol member, SerdeUsage usage, GeneratorExecutionContext context) + { + // Look first for a wrapper attribute on the member being serialized, and then for a + // wrapper attribute + var typeToWrap = member.Type; + return GetSerdeWrapAttributeArg(member.Symbol, typeToWrap, usage, context) + ?? GetSerdeWrapAttributeArg(member.Type, typeToWrap, usage, context); + + static INamedTypeSymbol? GetSerdeWrapAttributeArg(ISymbol symbol, ITypeSymbol typeToWrap, SerdeUsage usage, GeneratorExecutionContext context) + { + foreach (var attr in symbol.GetAttributes()) + { + if (attr.AttributeClass?.Name is "SerdeWrapAttribute") + { + if (attr is { ConstructorArguments: { Length: 1 } attrArgs } && + attrArgs[0] is { Value: INamedTypeSymbol wrapperType }) + { + // If the typeToWrap is a generic type, we should expect that the wrapper type + // is not listed directly, but instead a parent type is listed (possibly static) and + // the Serialize and Deserialize wrappers are nested below. + if (typeToWrap.OriginalDefinition is INamedTypeSymbol { Arity: > 0 } wrapped) + { + var nestedName = usage == SerdeUsage.Serialize ? "SerializeImpl" : "DeserializeImpl"; + var nestedTypes = wrapperType.GetTypeMembers(nestedName); + if (nestedTypes.Length != 1) + { + context.ReportDiagnostic(CreateDiagnostic( + DiagId.ERR_CantFindNestedWrapper, + symbol.Locations[0], + nestedName, + wrapperType, + wrapped)); + return null; + } + return nestedTypes[0]; + } + return wrapperType; + } + // Return null if the attribute is somehow incorrect + // TODO: produce a warning? + return null; + } + else if (attr is { AttributeClass.Name: nameof(SerdeMemberOptions), NamedArguments: { } named }) + { + foreach (var arg in named) + { + if (usage.HasFlag(SerdeUsage.Serialize) + && arg is { Key: nameof(SerdeMemberOptions.WrapperSerialize), + Value.Value: INamedTypeSymbol wrapperType }) + { + return wrapperType; + } + if (usage.HasFlag(SerdeUsage.Deserialize) + && arg is { Key: nameof(SerdeMemberOptions.WrapperDeserialize), + Value.Value: INamedTypeSymbol wrapperType2 }) + { + return wrapperType2; + } + } + } + } + return null; + } + } + } + + private static TypeSyntax? MakeWrappedExpression( + INamedTypeSymbol baseWrapper, + ImmutableArray elemTypes, + GeneratorExecutionContext context, + SerdeUsage usage, + ImmutableList inProgress) + { + if (elemTypes.Length == 0) + { + return baseWrapper.ToFqnSyntax(); + } + + var wrapperTypes = new List(); + foreach (var elemType in elemTypes) + { + var elemSyntax = elemType.ToFqnSyntax(); + if (ImplementsSerde(elemType, context, usage)) + { + // Special case for List-like types: + // If the element type directly implements ISerialize, we can + // use a single-arity version of the wrapper + // ArrayWrap<`elemType`> + wrapperTypes.Add(elemSyntax); + + // Otherwise we need an `IdWrap` which just delegates to the inner + // type. + //if (elemTypes.Length > 1) + if (usage == SerdeUsage.Serialize) + { + var idWrap = GenericName(Identifier("IdWrap"), TypeArgumentList(SeparatedList(new[] { elemSyntax }))); + wrapperTypes.Add(idWrap); + } + else + { + wrapperTypes.Add(elemSyntax); + } + continue; + } + + // Otherwise we'll need to wrap the element type as well e.g., + // ArrayWrap<`elemType`, `elemTypeWrapper`> + var wrapper = TryGetAnyWrapper(elemType, context, usage, inProgress); + + if (wrapper is null) + { + // Could not find a wrapper + return null; + } + else + { + wrapperTypes.Add(elemSyntax); + wrapperTypes.Add(wrapper); + } + } + + var wrapperSyntax = (QualifiedNameSyntax)baseWrapper.ToFqnSyntax(); + wrapperSyntax = wrapperSyntax.WithRight( + ((GenericNameSyntax)wrapperSyntax.Right).WithTypeArgumentList( + TypeArgumentList(SeparatedList(wrapperTypes.ToArray())))); + + return wrapperSyntax; + } + + private static TypeSyntax? TryGetAnyWrapper( + ITypeSymbol elemType, + GeneratorExecutionContext context, + SerdeUsage usage, + ImmutableList inProgress) + { + // If we're in the process of generating a wrapper type, just return the name of the wrapper + // and assume it has been generated already. + if (inProgress.Contains(elemType, SymbolEqualityComparer.Default)) + { + var typeName = elemType.Name; + var allTypes = typeName; + for (var parent = elemType.ContainingType; parent is not null; parent = parent.ContainingType) + { + allTypes = parent.Name + allTypes; + } + var wrapperName = $"{allTypes}Wrap"; + return IdentifierName(wrapperName); + } + var nameSyntax = TryGetPrimitiveWrapper(elemType, usage) + ?? TryGetEnumWrapper(elemType, usage) + ?? TryGetCompoundWrapper(elemType, context, usage, inProgress); + if (nameSyntax is null) + { + return null; + } + return nameSyntax; + } + + + private static TypeSyntax? TryCreateWrapper( + ITypeSymbol type, + GeneratorExecutionContext context, + SerdeUsage usage, + ImmutableList inProgress) + { + if (type is ({ TypeKind: not TypeKind.Enum } and { DeclaringSyntaxReferences.Length: > 0 }) or + { CanBeReferencedByName: false } or + { OriginalDefinition: INamedTypeSymbol { Arity: > 0 } }) + { + return null; + } + + var typeName = type.Name; + var allTypes = typeName; + for (var parent = type.ContainingType; parent is not null; parent = parent.ContainingType) + { + allTypes = parent.Name + allTypes; + } + var wrapperName = $"{allTypes}Wrap"; + + // If we're in the process of generating this type, just return the name of the wrapper + // and assume it has been generated already. + if (inProgress.Contains(type, SymbolEqualityComparer.Default)) + { + return IdentifierName(wrapperName); + } + + var wrapperFqn = $"Serde.{wrapperName}"; + var argName = "Value"; + var src = @$" +namespace Serde +{{ + internal readonly partial record struct {wrapperName}({type.ToDisplayString()} {argName}); +}}"; + context.AddSource(wrapperFqn, src); + var tree = SyntaxFactory.ParseSyntaxTree(src); + var typeDecl = (RecordDeclarationSyntax)((NamespaceDeclarationSyntax)tree.GetCompilationUnitRoot().Members[0]).Members[0]; + GenerateImpl( + usage, + new TypeDeclContext(typeDecl), + type, + IdentifierName(argName), + context, + inProgress.Add(type)); + return IdentifierName(wrapperName); + } + + // If the target is a core type, we can wrap it + private static TypeSyntax? TryGetPrimitiveWrapper(ITypeSymbol type, SerdeUsage usage) + { + if (type.NullableAnnotation == NullableAnnotation.Annotated) + { + return null; + } + var name = type.SpecialType switch + { + SpecialType.System_Boolean => "BoolWrap", + SpecialType.System_Char => "CharWrap", + SpecialType.System_Byte => "ByteWrap", + SpecialType.System_UInt16 => "UInt16Wrap", + SpecialType.System_UInt32 => "UInt32Wrap", + SpecialType.System_UInt64 => "UInt64Wrap", + SpecialType.System_SByte => "SByteWrap", + SpecialType.System_Int16 => "Int16Wrap", + SpecialType.System_Int32 => "Int32Wrap", + SpecialType.System_Int64 => "Int64Wrap", + SpecialType.System_String => "StringWrap", + SpecialType.System_Single => "FloatWrap", + SpecialType.System_Double => "DoubleWrap", + SpecialType.System_Decimal => "DecimalWrap", + _ => null + }; + return name is null ? null : IdentifierName(name); + } + + private static TypeSyntax? TryGetEnumWrapper(ITypeSymbol type, SerdeUsage usage) + { + if (type.TypeKind is not TypeKind.Enum) + { + return null; + } + + // Check for the generation attributes + if (!HasGenerateAttribute(type, usage)) + { + return null; + } + + var wrapperName = GetWrapperName(type.Name); + var containing = type.ContainingType?.ToDisplayString(); + if (containing is null && type.ContainingNamespace is { IsGlobalNamespace: false } ns) + { + containing = ns.ToDisplayString(); + } + var wrapperFqn = containing is not null + ? containing + "." + wrapperName + : "global::" + wrapperName; + + return SyntaxFactory.ParseTypeName(wrapperFqn); + } + + private static bool HasGenerateAttribute(ITypeSymbol memberType, SerdeUsage usage) + { + var attributes = memberType.GetAttributes(); + foreach (var attr in attributes) + { + var attrClass = attr.AttributeClass; + if (attrClass is null) + { + continue; + } + if (WellKnownTypes.IsWellKnownAttribute(attrClass, WellKnownAttribute.GenerateSerde)) + { + return true; + } + if (usage == SerdeUsage.Serialize && + WellKnownTypes.IsWellKnownAttribute(attrClass, WellKnownAttribute.GenerateSerialize)) + { + return true; + } + if (usage == SerdeUsage.Deserialize && + WellKnownTypes.IsWellKnownAttribute(attrClass, WellKnownAttribute.GenerateDeserialize)) + { + return true; + } + } + return false; + } + + private static TypeSyntax? TryGetCompoundWrapper(ITypeSymbol type, GeneratorExecutionContext context, SerdeUsage usage, ImmutableList inProgress) + { + return type switch + { + { OriginalDefinition.SpecialType: SpecialType.System_Nullable_T } => + MakeWrappedExpression( + context.Compilation.GetTypeByMetadataName("Serde.NullableWrap+" + GetImplName(usage) + "`2")!, + ImmutableArray.Create(((INamedTypeSymbol)type).TypeArguments[0]), + context, + usage, + inProgress), + + // This is rather subtle. One might think that we would want to use a + // NullableRefWrapper for any reference type that could contain null. In fact, we + // only want to use one if the type in question is actually annotated as nullable. + // The difference comes down to type parameters. If a type parameter is constrained + // as `class?` then it is both a reference type and nullable, but we don't want to + // use a wrapper for it. The reason why is that in we don't know the actual + // "underlying" type and couldn't dispatch to the underlying type's ISerialize + // implementation. Instead, for type parameters that aren't actually "annotated" as + // nullable (i.e., "T?") we must rely on the type parameter itself implementing + // ISerialize, and therefore the substitution to provide the appropriate nullable + // wrapper. + { IsReferenceType: true, NullableAnnotation: NullableAnnotation.Annotated} => + MakeWrappedExpression( + context.Compilation.GetTypeByMetadataName("Serde.NullableRefWrap+" + GetImplName(usage) + "`2")!, + ImmutableArray.Create(type.WithNullableAnnotation(NullableAnnotation.NotAnnotated)), + context, + usage, + inProgress), + + IArrayTypeSymbol and { IsSZArray: true, Rank: 1, ElementType: { } elemType } + => MakeWrappedExpression( + context.Compilation.GetTypeByMetadataName("Serde.ArrayWrap+" + GetImplName(usage) + "`2")!, + ImmutableArray.Create(elemType), + context, + usage, + inProgress), + + INamedTypeSymbol t when TryGetWrapperName(t, context, usage) is { } tuple + => MakeWrappedExpression( + tuple.WrapperType, tuple.Args, context, usage, inProgress), + + _ => null, + }; + } + + private static string GetImplName(SerdeUsage usage) => usage switch + { + SerdeUsage.Serialize => "SerializeImpl", + SerdeUsage.Deserialize => "DeserializeImpl", + _ => throw ExceptionUtilities.Unreachable + }; + + private static (INamedTypeSymbol WrapperType, ImmutableArray Args)? TryGetWrapperName( + ITypeSymbol typeSymbol, + GeneratorExecutionContext context, + SerdeUsage usage) + { + if (typeSymbol.NullableAnnotation == NullableAnnotation.Annotated) + { + var nullableRefWrap = context.Compilation.GetTypeByMetadataName("Serde.NullableRefWrap+" + GetImplName(usage) + "`1")!; + return (nullableRefWrap, ImmutableArray.Create(typeSymbol.WithNullableAnnotation(NullableAnnotation.NotAnnotated))); + } + if (typeSymbol is INamedTypeSymbol named && TryGetWellKnownType(named, context) is {} wk) + { + return (ToWrapper(wk, context.Compilation, usage), named.TypeArguments); + } + + // Check if it implements well-known interfaces + foreach (var iface in WellKnownTypes.GetAvailableInterfacesInOrder(context)) + { + Debug.Assert(iface.TypeKind == TypeKind.Interface); + foreach (var impl in typeSymbol.Interfaces) + { + if (impl.OriginalDefinition.Equals(iface, SymbolEqualityComparer.Default) && + ToWrapper(TryGetWellKnownType(iface, context), context.Compilation, usage) is { } wrap) + { + return (wrap, impl.TypeArguments); + } + } + } + return null; + } + + [return: NotNullIfNotNull(nameof(wk))] + internal static INamedTypeSymbol? ToWrapper(WellKnownType? wk, Compilation comp, SerdeUsage usage) + { + if (wk is null) + { + return null; + } + var (baseName, arity) = wk.GetValueOrDefault() switch + { + WellKnownType.ImmutableArray_1 => ("ImmutableArrayWrap", 2), + WellKnownType.List_1 => ("ListWrap", 2), + WellKnownType.Dictionary_2 => ("DictWrap", 4), + WellKnownType.IDictionary_2 => ("IDictWrap", 4), + WellKnownType.IReadOnlyDictionary_2 => ("IRODictWrap", 4), + }; + string fqn = "Serde." + baseName + "+" + GetImplName(usage) + "`" + arity; + var type = comp.GetTypeByMetadataName(fqn)!; + return type; + } + + private static ParameterSyntax Parameter(string typeName, string paramName, bool byRef = false) => SyntaxFactory.Parameter( + attributeLists: default, + modifiers: default, + type: byRef ? SyntaxFactory.RefType(IdentifierName(typeName)) : IdentifierName(typeName), + Identifier(paramName), + default + ); + + private static ParameterSyntax Parameter(TypeSyntax typeSyntax, string paramName) => SyntaxFactory.Parameter( + attributeLists: default, + modifiers: default, + type: typeSyntax, + Identifier(paramName), + default + ); + + private static LiteralExpressionSyntax NumericLiteral(int num) + => LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(num)); + + private static LiteralExpressionSyntax StringLiteral(string text) + => LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(text)); + + private static MemberAccessExpressionSyntax MakeMemberAccessExpr(DataMemberSymbol m, ExpressionSyntax receiverExpr) + => MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + receiverExpr, + IdentifierName(m.Name)); + } +} \ No newline at end of file diff --git a/src/generator/Generator.Wrapper.cs b/src/generator/Generator.Wrapper.cs index 072d0e5c..8667a436 100644 --- a/src/generator/Generator.Wrapper.cs +++ b/src/generator/Generator.Wrapper.cs @@ -61,6 +61,7 @@ partial class SerdeImplRoslynGenerator var inProgress = ImmutableList.Create(receiverType); GenerateImpl(SerdeUsage.Serialize, new TypeDeclContext(typeDecl), receiverType, receiverExpr, context, inProgress); + SerializeImplRoslynGenerator.GenerateImpl(SerdeUsage.Serialize, new TypeDeclContext(typeDecl), receiverType, receiverExpr, context, inProgress); GenerateImpl(SerdeUsage.Deserialize, new TypeDeclContext(typeDecl), receiverType, receiverExpr, context, inProgress); } diff --git a/src/generator/SymbolUtilities.cs b/src/generator/SymbolUtilities.cs index c3262f3e..fa76e371 100644 --- a/src/generator/SymbolUtilities.cs +++ b/src/generator/SymbolUtilities.cs @@ -47,7 +47,7 @@ public static List GetDataMembers(ITypeSymbol type, SerdeUsage return members; } - public static TypeSyntax ToFqnSyntax(this INamedTypeSymbol t) => SyntaxFactory.ParseTypeName(t.ToDisplayString()); + public static TypeSyntax ToFqnSyntax(this ITypeSymbol t) => SyntaxFactory.ParseTypeName(t.ToDisplayString()); public static MemberOptions GetMemberOptions(ISymbol member) { diff --git a/src/generator/WellKnownTypes.cs b/src/generator/WellKnownTypes.cs index de0ee583..ef9a966b 100644 --- a/src/generator/WellKnownTypes.cs +++ b/src/generator/WellKnownTypes.cs @@ -9,6 +9,7 @@ namespace Serde { + [Closed] internal enum WellKnownType { ImmutableArray_1, diff --git a/src/serde-xml/XmlSerializer.cs b/src/serde-xml/XmlSerializer.cs index b3960af9..48e69072 100644 --- a/src/serde-xml/XmlSerializer.cs +++ b/src/serde-xml/XmlSerializer.cs @@ -270,10 +270,10 @@ public void SerializeField(ReadOnlySpan name, T value, ReadOnlySpan(string name, T value, U serialize) + void ISerializeType.SerializeField(string name, T value) { _parent._writer.WriteStartElement(name); - serialize.Serialize(value, _parent); + default(U).Serialize(value, _parent); _parent._writer.WriteEndElement(); } diff --git a/src/serde/ISerialize.cs b/src/serde/ISerialize.cs index 1592270a..6153bfe3 100644 --- a/src/serde/ISerialize.cs +++ b/src/serde/ISerialize.cs @@ -8,7 +8,7 @@ public interface ISerialize void Serialize(ISerializer serializer); } -public interface ISerialize +public interface ISerialize { void Serialize(T value, ISerializer serializer); } @@ -27,7 +27,9 @@ public interface ISerializeType void SkipField(string name) { SkipField(Encoding.UTF8.GetBytes(name)); } void SkipField(Utf8Span name) { } - void SerializeField(string name, T value, U serialize) where U : ISerialize; + void SerializeField(string name, T value) where U : struct, ISerialize; + void SerializeField(string name, T value, ReadOnlySpan attributes) where U : struct, ISerialize + => SerializeField(name, value); void End(); } @@ -82,6 +84,31 @@ public static class ISerializeTypeExt } } +public static class ISerializeTypeExt2 +{ + public static void SerializeFieldIfNotNull( + this ISerializeType serializeType, + string name, + T value) where U : struct, ISerialize + => SerializeFieldIfNotNull(serializeType, name, value, ReadOnlySpan.Empty); + + public static void SerializeFieldIfNotNull( + this ISerializeType serializeType, + string name, + T value, + ReadOnlySpan attributes) where U : struct, ISerialize + { + if (value is null) + { + serializeType.SkipField(name); + } + else + { + serializeType.SerializeField(name, value, attributes); + } + } +} + public interface ISerializeEnumerable { void SerializeElement(T value) where T : ISerialize; diff --git a/src/serde/Wrappers.Dictionary.cs b/src/serde/Wrappers.Dictionary.cs index 16b89af7..0885e78e 100644 --- a/src/serde/Wrappers.Dictionary.cs +++ b/src/serde/Wrappers.Dictionary.cs @@ -1,14 +1,17 @@ using System.Collections.Generic; +using System.ComponentModel; +using System.Net.Http.Headers; namespace Serde { public static class DictWrap { - public readonly struct SerializeImpl : ISerialize, - ISerializeWrap, SerializeImpl> + public readonly struct SerializeImpl + : ISerialize, ISerialize>, + ISerializeWrap, SerializeImpl> where TKey : notnull - where TKeyWrap : struct, ISerializeWrap, ISerialize - where TValueWrap : struct, ISerializeWrap, ISerialize + where TKeyWrap : struct, ISerializeWrap, ISerialize, ISerialize + where TValueWrap : struct, ISerializeWrap, ISerialize, ISerialize { public static SerializeImpl Create(Dictionary t) => new SerializeImpl(t); @@ -29,6 +32,17 @@ void ISerialize.Serialize(ISerializer serializer) } sd.End(); } + + void ISerialize>.Serialize(Dictionary value, ISerializer serializer) + { + var sd = serializer.SerializeDictionary(value.Count); + foreach (var (k, v) in value) + { + sd.SerializeKey(k, TKeyWrap.Create(k)); + sd.SerializeValue(v, TValueWrap.Create(v)); + } + sd.End(); + } } public readonly struct DeserializeImpl : IDeserialize> @@ -73,14 +87,25 @@ private struct Visitor : IDeserializeVisitor> public static class IDictWrap { public readonly record struct SerializeImpl(IDictionary Value) - : ISerialize, ISerializeWrap, SerializeImpl> + : ISerialize, ISerializeWrap, SerializeImpl>, + ISerialize> where TKey : notnull - where TKeyWrap : struct, ISerializeWrap, ISerialize - where TValueWrap : struct, ISerializeWrap, ISerialize + where TKeyWrap : struct, ISerializeWrap, ISerialize, ISerialize + where TValueWrap : struct, ISerializeWrap, ISerialize, ISerialize { public static SerializeImpl Create(IDictionary t) => new SerializeImpl(t); + void ISerialize>.Serialize(IDictionary value, ISerializer serializer) + { + var sd = serializer.SerializeDictionary(value.Count); + foreach (var (k, v) in value) + { + sd.SerializeKey(k, TKeyWrap.Create(k)); + sd.SerializeValue(v, TValueWrap.Create(v)); + } + sd.End(); + } void ISerialize.Serialize(ISerializer serializer) { var sd = serializer.SerializeDictionary(Value.Count); diff --git a/src/serde/Wrappers.List.cs b/src/serde/Wrappers.List.cs index cc7c537f..1e50e4a8 100644 --- a/src/serde/Wrappers.List.cs +++ b/src/serde/Wrappers.List.cs @@ -9,6 +9,17 @@ namespace Serde { public static class EnumerableHelpers { + public static void SerializeSpan(string typeName, ReadOnlySpan arr, U serializeImpl, ISerializer serializer) + where U : ISerialize + { + var enumerable = serializer.SerializeEnumerable(typeName, arr.Length); + foreach (var item in arr) + { + enumerable.SerializeElement(item, serializeImpl); + } + enumerable.End(); + } + public static void SerializeSpan(string typeName, ReadOnlySpan arr, ISerializer serializer) where TWrap : struct, ISerializeWrap, ISerialize { @@ -46,22 +57,17 @@ public static class EnumerableHelpers } } - public readonly record struct IdWrap(T Value) : ISerialize, ISerializeWrap> - where T : ISerialize - { - public static IdWrap Create(T t) => new IdWrap(t); - - void ISerialize.Serialize(ISerializer serializer) => Value.Serialize(serializer); - } - public static class ArrayWrap { public readonly record struct SerializeImpl(T[] Value) - : ISerialize, ISerializeWrap> + : ISerialize, ISerialize, ISerializeWrap> where TWrap : struct, ISerializeWrap, ISerialize { public static SerializeImpl Create(T[] t) => new SerializeImpl(t); + void ISerialize.Serialize(T[] value, ISerializer serializer) + => EnumerableHelpers.SerializeSpan(typeof(T[]).ToString(), value, serializer); + void ISerialize.Serialize(ISerializer serializer) => EnumerableHelpers.SerializeSpan(typeof(T[]).ToString(), Value, serializer); } @@ -109,13 +115,16 @@ private struct SerdeVisitor : IDeserializeVisitor public static class ListWrap { public readonly record struct SerializeImpl(List Value) - : ISerialize, ISerializeWrap, SerializeImpl> + : ISerialize, ISerialize>, ISerializeWrap, SerializeImpl> where TWrap : struct, ISerializeWrap, ISerialize { public static SerializeImpl Create(List t) => new SerializeImpl(t); void ISerialize.Serialize(ISerializer serializer) => EnumerableHelpers.SerializeList(typeof(List).ToString(), Value, serializer); + + void ISerialize>.Serialize(List value, ISerializer serializer) + => EnumerableHelpers.SerializeList(typeof(List).ToString(), value, serializer); } public readonly struct DeserializeImpl : IDeserialize> @@ -158,13 +167,16 @@ List IDeserializeVisitor>.VisitEnumerable(ref D d) public static class ImmutableArrayWrap { public readonly record struct SerializeImpl(ImmutableArray Value) - : ISerialize, ISerializeWrap, SerializeImpl> + : ISerialize, ISerialize>, ISerializeWrap, SerializeImpl> where TWrap : struct, ISerializeWrap, ISerialize { public static SerializeImpl Create(ImmutableArray t) => new SerializeImpl(t); void ISerialize.Serialize(ISerializer serializer) => EnumerableHelpers.SerializeSpan(typeof(ImmutableArray).ToString(), Value.AsSpan(), serializer); + + void ISerialize>.Serialize(ImmutableArray value, ISerializer serializer) + => EnumerableHelpers.SerializeSpan(typeof(ImmutableArray).ToString(), value.AsSpan(), serializer); } public readonly struct DeserializeImpl : IDeserialize> diff --git a/src/serde/Wrappers.cs b/src/serde/Wrappers.cs index cd0f9414..f53ca847 100644 --- a/src/serde/Wrappers.cs +++ b/src/serde/Wrappers.cs @@ -11,11 +11,23 @@ public interface ISerializeWrap where TWrap : ISerialize abstract static TWrap Create(T t); // Should be abstract static } + public readonly record struct IdWrap(T Value) : ISerialize, ISerialize, ISerializeWrap> + where T : ISerialize + { + public static IdWrap Create(T t) => new IdWrap(t); + + void ISerialize.Serialize(ISerializer serializer) => Value.Serialize(serializer); + + void ISerialize.Serialize(T value, ISerializer serializer) => value.Serialize(serializer); + } + public readonly partial record struct BoolWrap(bool Value) - : ISerializeWrap, ISerialize, IDeserialize + : ISerializeWrap, ISerialize, ISerialize, IDeserialize { private const string s_typeName = "bool"; public static BoolWrap Create(bool t) => new BoolWrap(t); + void ISerialize.Serialize(bool value, ISerializer serializer) + => serializer.SerializeBool(value); void Serde.ISerialize.Serialize(ISerializer serializer) { serializer.SerializeBool(Value); @@ -34,10 +46,12 @@ private sealed class SerdeVisitor : Serde.IDeserializeVisitor } public readonly partial record struct CharWrap(char Value) - : ISerializeWrap, ISerialize, IDeserialize + : ISerializeWrap, ISerialize, ISerialize, IDeserialize { private const string s_typeName = "char"; public static CharWrap Create(char c) => new CharWrap(c); + void ISerialize.Serialize(char value, ISerializer serializer) + => serializer.SerializeChar(value); void Serde.ISerialize.Serialize(ISerializer serializer) { serializer.SerializeChar(Value); @@ -69,7 +83,7 @@ char IDeserializeVisitor.VisitUtf8Span(ReadOnlySpan s) } public readonly partial record struct ByteWrap(byte Value) - : ISerializeWrap, ISerialize, IDeserialize + : ISerializeWrap, ISerialize, ISerialize, IDeserialize { private const string s_typeName = "byte"; public static ByteWrap Create(byte b) => new ByteWrap(b); @@ -77,6 +91,10 @@ void Serde.ISerialize.Serialize(ISerializer serializer) { serializer.SerializeByte(Value); } + public void Serialize(byte value, ISerializer serializer) + { + serializer.SerializeByte(value); + } static byte Serde.IDeserialize.Deserialize(ref D deserializer) { var visitor = new SerdeVisitor(); @@ -98,10 +116,14 @@ private sealed class SerdeVisitor : Serde.IDeserializeVisitor } public readonly partial record struct UInt16Wrap(ushort Value) - : ISerializeWrap, ISerialize, IDeserialize + : ISerializeWrap, ISerialize, ISerialize, IDeserialize { private const string s_typeName = "ushort"; public static UInt16Wrap Create(ushort i) => new UInt16Wrap(i); + void ISerialize.Serialize(ushort value, ISerializer serializer) + { + serializer.SerializeU16(value); + } void Serde.ISerialize.Serialize(ISerializer serializer) { serializer.SerializeU16(Value); @@ -127,10 +149,12 @@ private sealed class SerdeVisitor : Serde.IDeserializeVisitor } public readonly partial record struct UInt32Wrap(uint Value) - : ISerializeWrap, ISerialize, IDeserialize + : ISerializeWrap, ISerialize, ISerialize, IDeserialize { private const string s_typeName = "uint"; public static UInt32Wrap Create(uint i) => new UInt32Wrap(i); + void ISerialize.Serialize(uint value, ISerializer serializer) + => serializer.SerializeU32(value); void Serde.ISerialize.Serialize(ISerializer serializer) { serializer.SerializeU32(Value); @@ -156,10 +180,12 @@ private sealed class SerdeVisitor : Serde.IDeserializeVisitor } public readonly partial record struct UInt64Wrap(ulong Value) - : ISerializeWrap, ISerialize, IDeserialize + : ISerializeWrap, ISerialize, ISerialize, IDeserialize { private const string s_typeName = "ulong"; public static UInt64Wrap Create(ulong i) => new UInt64Wrap(i); + void ISerialize.Serialize(ulong value, ISerializer serializer) + => serializer.SerializeU64(value); void Serde.ISerialize.Serialize(ISerializer serializer) { serializer.SerializeU64(Value); @@ -185,10 +211,12 @@ private sealed class SerdeVisitor : Serde.IDeserializeVisitor } public readonly partial record struct SByteWrap(sbyte Value) - : ISerializeWrap, ISerialize, IDeserialize + : ISerializeWrap, ISerialize, ISerialize, IDeserialize { private const string s_typeName = "sbyte"; public static SByteWrap Create(sbyte i) => new SByteWrap(i); + void ISerialize.Serialize(sbyte value, ISerializer serializer) + => serializer.SerializeSByte(value); void Serde.ISerialize.Serialize(ISerializer serializer) { serializer.SerializeSByte(Value); @@ -214,10 +242,14 @@ private sealed class SerdeVisitor : Serde.IDeserializeVisitor } public readonly partial record struct Int16Wrap(short Value) - : ISerializeWrap, ISerialize, IDeserialize + : ISerializeWrap, ISerialize, ISerialize, IDeserialize { private const string s_typeName = "short"; public static Int16Wrap Create(short i) => new Int16Wrap(i); + void ISerialize.Serialize(short value, ISerializer serializer) + { + serializer.SerializeI16(value); + } void Serde.ISerialize.Serialize(ISerializer serializer) { serializer.SerializeI16(Value); @@ -243,7 +275,7 @@ private sealed class SerdeVisitor : Serde.IDeserializeVisitor } public readonly partial record struct Int32Wrap(int Value) - : ISerializeWrap, ISerialize, IDeserialize + : ISerializeWrap, ISerialize, ISerialize, IDeserialize { private const string s_typeName = "int"; public static Int32Wrap Create(int i) => new Int32Wrap(i); @@ -251,6 +283,10 @@ void Serde.ISerialize.Serialize(ISerializer serializer) { serializer.SerializeI32(Value); } + void ISerialize.Serialize(int value, ISerializer serializer) + { + serializer.SerializeI32(value); + } static int Serde.IDeserialize.Deserialize(ref D deserializer) { var visitor = new SerdeVisitor(); @@ -272,10 +308,12 @@ private sealed class SerdeVisitor : Serde.IDeserializeVisitor } public readonly partial record struct Int64Wrap(long Value) - : ISerializeWrap, ISerialize, IDeserialize + : ISerializeWrap, ISerialize, ISerialize, IDeserialize { private const string s_typeName = "long"; public static Int64Wrap Create(long i) => new Int64Wrap(i); + void ISerialize.Serialize(long value, ISerializer serializer) + => serializer.SerializeI64(value); void Serde.ISerialize.Serialize(ISerializer serializer) { serializer.SerializeI64(Value); @@ -301,13 +339,17 @@ private sealed class SerdeVisitor : Serde.IDeserializeVisitor } public readonly partial record struct DoubleWrap(double Value) - : ISerializeWrap, ISerialize, IDeserialize + : ISerializeWrap, ISerialize, ISerialize, IDeserialize { public static DoubleWrap Create(double d) => new DoubleWrap(d); void Serde.ISerialize.Serialize(ISerializer serializer) { serializer.SerializeDouble(Value); } + void ISerialize.Serialize(double value, ISerializer serializer) + { + serializer.SerializeDouble(value); + } static double Serde.IDeserialize.Deserialize(ref D deserializer) { var visitor = new SerdeVisitor(); @@ -331,13 +373,17 @@ private sealed class SerdeVisitor : Serde.IDeserializeVisitor } public readonly partial record struct DecimalWrap(decimal Value) - : ISerializeWrap, ISerialize, IDeserialize + : ISerializeWrap, ISerialize, ISerialize, IDeserialize { public static DecimalWrap Create(decimal d) => new DecimalWrap(d); void Serde.ISerialize.Serialize(ISerializer serializer) { serializer.SerializeDecimal(Value); } + void Serde.ISerialize.Serialize(decimal value, ISerializer serializer) + { + serializer.SerializeDecimal(value); + } static decimal Serde.IDeserialize.Deserialize(ref D deserializer) { var visitor = new SerdeVisitor(); @@ -361,7 +407,7 @@ private sealed class SerdeVisitor : Serde.IDeserializeVisitor } } public readonly partial record struct StringWrap(string Value) - : ISerializeWrap, ISerialize, IDeserialize + : ISerializeWrap, ISerialize, ISerialize, IDeserialize { private const string s_typeName = "string"; public static StringWrap Create(string s) => new StringWrap(s); @@ -369,7 +415,10 @@ void Serde.ISerialize.Serialize(ISerializer serializer) { serializer.SerializeString(Value); } - + void ISerialize.Serialize(string value, ISerializer serializer) + { + serializer.SerializeString(value); + } public static string Deserialize(ref D deserializer) where D : IDeserializer { @@ -388,12 +437,23 @@ private class SerdeVisitor : IDeserializeVisitor public static class NullableWrap { public readonly partial record struct SerializeImpl(T? Value) - : ISerializeWrap>, ISerialize + : ISerializeWrap>, ISerialize, ISerialize where T : struct - where TWrap : struct, ISerializeWrap, ISerialize + where TWrap : struct, ISerializeWrap, ISerialize, ISerialize { public static SerializeImpl Create(T? t) => new(t); + void ISerialize.Serialize(T? value, ISerializer serializer) + { + if (value is {} notnull) + { + serializer.SerializeNotNull(notnull, TWrap.Create(notnull)); + } + else + { + serializer.SerializeNull(); + } + } void ISerialize.Serialize(ISerializer serializer) { if (Value is {} notnull) @@ -437,12 +497,23 @@ private sealed class Visitor : IDeserializeVisitor public static class NullableRefWrap { public readonly partial record struct SerializeImpl(T? Value) - : ISerializeWrap>, ISerialize + : ISerializeWrap>, ISerialize, ISerialize where T : class - where TWrap : struct, ISerializeWrap, ISerialize + where TWrap : struct, ISerializeWrap, ISerialize, ISerialize { public static SerializeImpl Create(T? t) => new SerializeImpl(t); + void ISerialize.Serialize(T? value, ISerializer serializer) + { + if (value is null) + { + serializer.SerializeNull(); + } + else + { + serializer.SerializeNotNull(default(TWrap)); + } + } void ISerialize.Serialize(ISerializer serializer) { if (Value is null) diff --git a/src/serde/json/JsonSerializer.cs b/src/serde/json/JsonSerializer.cs index 6ea9e0fb..de26895b 100644 --- a/src/serde/json/JsonSerializer.cs +++ b/src/serde/json/JsonSerializer.cs @@ -13,7 +13,7 @@ public sealed partial class JsonSerializer : ISerializer /// /// Serialize the given type to a string. /// - public static string Serialize(T s) where T : ISerialize + public static string Serialize(T s) where T : ISerialize, ISerialize { using var bufferWriter = new PooledByteBufferWriter(16 * 1024); using var writer = new Utf8JsonWriter(bufferWriter, new JsonWriterOptions @@ -27,6 +27,21 @@ public sealed partial class JsonSerializer : ISerializer return Encoding.UTF8.GetString(bufferWriter.WrittenMemory.Span); } + public static string Serialize(T s) + where TWrap : struct, ISerialize + { + using var bufferWriter = new PooledByteBufferWriter(16 * 1024); + using var writer = new Utf8JsonWriter(bufferWriter, new JsonWriterOptions + { + Indented = false, + SkipValidation = true + }); + var serializer = new JsonSerializer(writer); + default(TWrap).Serialize(s, serializer); + writer.Flush(); + return Encoding.UTF8.GetString(bufferWriter.WrittenMemory.Span); + } + public static T Deserialize(string source) where T : IDeserialize => Deserialize(source); diff --git a/src/serde/json/JsonSerializerImpl.cs b/src/serde/json/JsonSerializerImpl.cs index 856dcdfd..35637971 100644 --- a/src/serde/json/JsonSerializerImpl.cs +++ b/src/serde/json/JsonSerializerImpl.cs @@ -125,9 +125,10 @@ void ISerializeType.SerializeField(Utf8Span name, T value) value.Serialize(this); } - void ISerializeType.SerializeField(string name, T value, U serialize) + void ISerializeType.SerializeField(string name, T value) { _writer.WritePropertyName(name); + var serialize = new U(); serialize.Serialize(value, this); } diff --git a/src/serde/json/JsonValue.Serialize.cs b/src/serde/json/JsonValue.Serialize.cs index 9c76b723..acd68c67 100644 --- a/src/serde/json/JsonValue.Serialize.cs +++ b/src/serde/json/JsonValue.Serialize.cs @@ -6,10 +6,14 @@ namespace Serde.Json { - partial record JsonValue : ISerialize + partial record JsonValue : ISerialize, ISerialize { public abstract void Serialize(ISerializer serializer); + void ISerialize.Serialize(JsonValue value, ISerializer serializer) + { + value.Serialize(serializer); + } partial record Number { diff --git a/test/Serde.Generation.Test/SerializeTests.cs b/test/Serde.Generation.Test/SerializeTests.cs index ac3cf7e1..bd072f16 100644 --- a/test/Serde.Generation.Test/SerializeTests.cs +++ b/test/Serde.Generation.Test/SerializeTests.cs @@ -124,10 +124,10 @@ public Task NullableRefFields() [GenerateSerialize] partial struct S - where T1 : ISerialize - where T2 : ISerialize? - where T3 : class, ISerialize - where T4 : class?, ISerialize + where T1 : ISerialize, ISerialize + where T2 : ISerialize?, ISerialize? + where T3 : class, ISerialize, ISerialize + where T4 : class?, ISerialize, ISerialize { public string? FS; public T1 F1; @@ -147,7 +147,7 @@ public Task NullableFields() partial struct S where T1 : int? where T2 : TSerialize? - where TSerialize : struct, ISerialize + where TSerialize : struct, ISerialize, ISerialize { public int? FI; public T1 F1; @@ -392,7 +392,7 @@ public S(int x, int y) Y = y; } } -public struct SWrap : ISerialize +public struct SWrap : ISerialize, ISerialize { private readonly S _s; public SWrap(S s) @@ -404,6 +404,11 @@ void ISerialize.Serialize(ISerializer serializer) serializer.SerializeI32(_s.X); serializer.SerializeI32(_s.Y); } + void ISerialize.Serialize(S value, ISerializer serializer) + { + serializer.SerializeI32(value.X); + serializer.SerializeI32(value.Y); + } } [GenerateSerialize] partial class C @@ -430,8 +435,10 @@ public S(T f) } public static class SWrap { - public readonly struct SerializeImpl : ISerialize, ISerializeWrap, SerializeImpl> - where TWrap : struct, ISerialize, ISerializeWrap + public readonly struct SerializeImpl + : ISerialize, ISerialize>, + ISerializeWrap, SerializeImpl> + where TWrap : struct, ISerialize, ISerialize, ISerializeWrap { public static SerializeImpl Create(S t) => new(t); private readonly S _s; @@ -439,6 +446,12 @@ public SerializeImpl(S s) { _s = s; } + void ISerialize>.Serialize(S value, ISerializer serializer) + { + var type = serializer.SerializeType(""S"", 1); + type.SerializeField(""s"", value.Field); + type.End(); + } void ISerialize.Serialize(ISerializer serializer) { var type = serializer.SerializeType(""S"", 1); @@ -470,8 +483,9 @@ public S(T f) Field = f; } } -public readonly struct SWrap : ISerialize, ISerializeWrap, SWrap> - where TWrap : struct, ISerialize, ISerializeWrap +public readonly struct SWrap + : ISerialize, ISerialize, ISerializeWrap, SWrap> + where TWrap : struct, ISerialize, ISerialize, ISerializeWrap { public static SWrap Create(S t) => new SWrap(t); private readonly S _s; @@ -479,6 +493,12 @@ public SWrap(S s) { _s = s; } + void ISerialize.Serialize(T value, ISerializer serializer) + { + var type = serializer.SerializeType(""S"", 1); + type.SerializeField(""s"", value); + type.End(); + } void ISerialize.Serialize(ISerializer serializer) { var type = serializer.SerializeType(""S"", 1); diff --git a/test/Serde.Generation.Test/test_output/AllInOneTest.GeneratorTest/Serde.Test.AllInOne.ColorEnumWrap.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/AllInOneTest.GeneratorTest/Serde.Test.AllInOne.ColorEnumWrap.ISerialize`1.verified.cs new file mode 100644 index 00000000..aa0f919a --- /dev/null +++ b/test/Serde.Generation.Test/test_output/AllInOneTest.GeneratorTest/Serde.Test.AllInOne.ColorEnumWrap.ISerialize`1.verified.cs @@ -0,0 +1,26 @@ +//HintName: Serde.Test.AllInOne.ColorEnumWrap.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +namespace Serde.Test +{ + partial record AllInOne + { + partial record struct ColorEnumWrap : Serde.ISerialize + { + void ISerialize.Serialize(Serde.Test.AllInOne.ColorEnum value, ISerializer serializer) + { + var name = value switch + { + Serde.Test.AllInOne.ColorEnum.Red => "red", + Serde.Test.AllInOne.ColorEnum.Blue => "blue", + Serde.Test.AllInOne.ColorEnum.Green => "green", + _ => null + }; + serializer.SerializeEnumValue("ColorEnum", name, new Int32Wrap((int)value)); + } + } + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/AllInOneTest.GeneratorTest/Serde.Test.AllInOne.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/AllInOneTest.GeneratorTest/Serde.Test.AllInOne.ISerialize`1.verified.cs new file mode 100644 index 00000000..f4f47208 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/AllInOneTest.GeneratorTest/Serde.Test.AllInOne.ISerialize`1.verified.cs @@ -0,0 +1,33 @@ +//HintName: Serde.Test.AllInOne.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +namespace Serde.Test +{ + partial record AllInOne : Serde.ISerialize + { + void ISerialize.Serialize(Serde.Test.AllInOne value, ISerializer serializer) + { + var type = serializer.SerializeType("AllInOne", 16); + type.SerializeField("boolField", value.BoolField); + type.SerializeField("charField", value.CharField); + type.SerializeField("byteField", value.ByteField); + type.SerializeField("uShortField", value.UShortField); + type.SerializeField("uIntField", value.UIntField); + type.SerializeField("uLongField", value.ULongField); + type.SerializeField("sByteField", value.SByteField); + type.SerializeField("shortField", value.ShortField); + type.SerializeField("intField", value.IntField); + type.SerializeField("longField", value.LongField); + type.SerializeField("stringField", value.StringField); + type.SerializeFieldIfNotNull>("nullStringField", value.NullStringField); + type.SerializeField>("uIntArr", value.UIntArr); + type.SerializeField>>("nestedArr", value.NestedArr); + type.SerializeField, Serde.ImmutableArrayWrap.SerializeImpl>("intImm", value.IntImm); + type.SerializeField("color", value.Color); + type.End(); + } + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/MemberFormatTests.CamelCase/S.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/MemberFormatTests.CamelCase/S.ISerialize`1.verified.cs new file mode 100644 index 00000000..991b19fe --- /dev/null +++ b/test/Serde.Generation.Test/test_output/MemberFormatTests.CamelCase/S.ISerialize`1.verified.cs @@ -0,0 +1,16 @@ +//HintName: S.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial struct S : Serde.ISerialize +{ + void ISerialize.Serialize(S value, ISerializer serializer) + { + var type = serializer.SerializeType("S", 2); + type.SerializeField("one", value.One); + type.SerializeField("twoWord", value.TwoWord); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/MemberFormatTests.Default/S.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/MemberFormatTests.Default/S.ISerialize`1.verified.cs new file mode 100644 index 00000000..991b19fe --- /dev/null +++ b/test/Serde.Generation.Test/test_output/MemberFormatTests.Default/S.ISerialize`1.verified.cs @@ -0,0 +1,16 @@ +//HintName: S.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial struct S : Serde.ISerialize +{ + void ISerialize.Serialize(S value, ISerializer serializer) + { + var type = serializer.SerializeType("S", 2); + type.SerializeField("one", value.One); + type.SerializeField("twoWord", value.TwoWord); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/MemberFormatTests.EnumValues/ColorEnumWrap.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/MemberFormatTests.EnumValues/ColorEnumWrap.ISerialize`1.verified.cs new file mode 100644 index 00000000..434d2263 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/MemberFormatTests.EnumValues/ColorEnumWrap.ISerialize`1.verified.cs @@ -0,0 +1,20 @@ +//HintName: ColorEnumWrap.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial record struct ColorEnumWrap : Serde.ISerialize +{ + void ISerialize.Serialize(ColorEnum value, ISerializer serializer) + { + var name = value switch + { + ColorEnum.Red => "red", + ColorEnum.Green => "green", + ColorEnum.Blue => "blue", + _ => null + }; + serializer.SerializeEnumValue("ColorEnum", name, new Int32Wrap((int)value)); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/MemberFormatTests.EnumValues/S.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/MemberFormatTests.EnumValues/S.ISerialize`1.verified.cs new file mode 100644 index 00000000..488d9f51 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/MemberFormatTests.EnumValues/S.ISerialize`1.verified.cs @@ -0,0 +1,15 @@ +//HintName: S.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial struct S : Serde.ISerialize +{ + void ISerialize.Serialize(S value, ISerializer serializer) + { + var type = serializer.SerializeType("S", 1); + type.SerializeField("e", value.E); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/MemberFormatTests.EnumValues/S2.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/MemberFormatTests.EnumValues/S2.ISerialize`1.verified.cs new file mode 100644 index 00000000..a19e0978 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/MemberFormatTests.EnumValues/S2.ISerialize`1.verified.cs @@ -0,0 +1,15 @@ +//HintName: S2.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial struct S2 : Serde.ISerialize +{ + void ISerialize.Serialize(S2 value, ISerializer serializer) + { + var type = serializer.SerializeType("S2", 1); + type.SerializeField("E", value.E); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/MemberFormatTests.KebabCase/S.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/MemberFormatTests.KebabCase/S.ISerialize`1.verified.cs new file mode 100644 index 00000000..405b8271 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/MemberFormatTests.KebabCase/S.ISerialize`1.verified.cs @@ -0,0 +1,16 @@ +//HintName: S.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial struct S : Serde.ISerialize +{ + void ISerialize.Serialize(S value, ISerializer serializer) + { + var type = serializer.SerializeType("S", 2); + type.SerializeField("one", value.One); + type.SerializeField("two-word", value.TwoWord); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests.ArrayOfGenerateSerialize/TestCase15.Class0.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests.ArrayOfGenerateSerialize/TestCase15.Class0.ISerialize`1.verified.cs new file mode 100644 index 00000000..96a843ad --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests.ArrayOfGenerateSerialize/TestCase15.Class0.ISerialize`1.verified.cs @@ -0,0 +1,19 @@ +//HintName: TestCase15.Class0.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial class TestCase15 +{ + partial class Class0 : Serde.ISerialize + { + void ISerialize.Serialize(TestCase15.Class0 value, ISerializer serializer) + { + var type = serializer.SerializeType("Class0", 2); + type.SerializeField>>("field0", value.Field0); + type.SerializeField>("field1", value.Field1); + type.End(); + } + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests.ArrayOfGenerateSerialize/TestCase15.Class1.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests.ArrayOfGenerateSerialize/TestCase15.Class1.ISerialize`1.verified.cs new file mode 100644 index 00000000..222b4f22 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests.ArrayOfGenerateSerialize/TestCase15.Class1.ISerialize`1.verified.cs @@ -0,0 +1,19 @@ +//HintName: TestCase15.Class1.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial class TestCase15 +{ + partial class Class1 : Serde.ISerialize + { + void ISerialize.Serialize(TestCase15.Class1 value, ISerializer serializer) + { + var type = serializer.SerializeType("Class1", 2); + type.SerializeField("field0", value.Field0); + type.SerializeField("field1", value.Field1); + type.End(); + } + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests.DictionaryGenerate2/C.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests.DictionaryGenerate2/C.ISerialize`1.verified.cs new file mode 100644 index 00000000..9e84bd5e --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests.DictionaryGenerate2/C.ISerialize`1.verified.cs @@ -0,0 +1,15 @@ +//HintName: C.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial record C : Serde.ISerialize +{ + void ISerialize.Serialize(C value, ISerializer serializer) + { + var type = serializer.SerializeType("C", 1); + type.SerializeField("x", value.X); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests.DictionaryGenerate2/C2.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests.DictionaryGenerate2/C2.ISerialize`1.verified.cs new file mode 100644 index 00000000..7705b4b0 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests.DictionaryGenerate2/C2.ISerialize`1.verified.cs @@ -0,0 +1,15 @@ +//HintName: C2.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial class C2 : Serde.ISerialize +{ + void ISerialize.Serialize(C2 value, ISerializer serializer) + { + var type = serializer.SerializeType("C2", 1); + type.SerializeField, Serde.DictWrap.SerializeImpl>>("map", value.Map); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests.EnumMember/Some.Nested.Namespace.C.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests.EnumMember/Some.Nested.Namespace.C.ISerialize`1.verified.cs new file mode 100644 index 00000000..7e4ea2f8 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests.EnumMember/Some.Nested.Namespace.C.ISerialize`1.verified.cs @@ -0,0 +1,21 @@ +//HintName: Some.Nested.Namespace.C.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +namespace Some.Nested.Namespace +{ + partial class C : Serde.ISerialize + { + void ISerialize.Serialize(Some.Nested.Namespace.C value, ISerializer serializer) + { + var type = serializer.SerializeType("C", 4); + type.SerializeField("colorInt", value.ColorInt); + type.SerializeField("colorByte", value.ColorByte); + type.SerializeField("colorLong", value.ColorLong); + type.SerializeField("colorULong", value.ColorULong); + type.End(); + } + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests.EnumMember/Some.Nested.Namespace.ColorByteWrap.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests.EnumMember/Some.Nested.Namespace.ColorByteWrap.ISerialize`1.verified.cs new file mode 100644 index 00000000..70edc180 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests.EnumMember/Some.Nested.Namespace.ColorByteWrap.ISerialize`1.verified.cs @@ -0,0 +1,23 @@ +//HintName: Some.Nested.Namespace.ColorByteWrap.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +namespace Some.Nested.Namespace +{ + partial record struct ColorByteWrap : Serde.ISerialize + { + void ISerialize.Serialize(Some.Nested.Namespace.ColorByte value, ISerializer serializer) + { + var name = value switch + { + Some.Nested.Namespace.ColorByte.Red => "red", + Some.Nested.Namespace.ColorByte.Green => "green", + Some.Nested.Namespace.ColorByte.Blue => "blue", + _ => null + }; + serializer.SerializeEnumValue("ColorByte", name, new ByteWrap((byte)value)); + } + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests.EnumMember/Some.Nested.Namespace.ColorIntWrap.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests.EnumMember/Some.Nested.Namespace.ColorIntWrap.ISerialize`1.verified.cs new file mode 100644 index 00000000..411c0b31 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests.EnumMember/Some.Nested.Namespace.ColorIntWrap.ISerialize`1.verified.cs @@ -0,0 +1,23 @@ +//HintName: Some.Nested.Namespace.ColorIntWrap.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +namespace Some.Nested.Namespace +{ + partial record struct ColorIntWrap : Serde.ISerialize + { + void ISerialize.Serialize(Some.Nested.Namespace.ColorInt value, ISerializer serializer) + { + var name = value switch + { + Some.Nested.Namespace.ColorInt.Red => "red", + Some.Nested.Namespace.ColorInt.Green => "green", + Some.Nested.Namespace.ColorInt.Blue => "blue", + _ => null + }; + serializer.SerializeEnumValue("ColorInt", name, new Int32Wrap((int)value)); + } + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests.EnumMember/Some.Nested.Namespace.ColorLongWrap.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests.EnumMember/Some.Nested.Namespace.ColorLongWrap.ISerialize`1.verified.cs new file mode 100644 index 00000000..89604a96 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests.EnumMember/Some.Nested.Namespace.ColorLongWrap.ISerialize`1.verified.cs @@ -0,0 +1,23 @@ +//HintName: Some.Nested.Namespace.ColorLongWrap.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +namespace Some.Nested.Namespace +{ + partial record struct ColorLongWrap : Serde.ISerialize + { + void ISerialize.Serialize(Some.Nested.Namespace.ColorLong value, ISerializer serializer) + { + var name = value switch + { + Some.Nested.Namespace.ColorLong.Red => "red", + Some.Nested.Namespace.ColorLong.Green => "green", + Some.Nested.Namespace.ColorLong.Blue => "blue", + _ => null + }; + serializer.SerializeEnumValue("ColorLong", name, new Int64Wrap((long)value)); + } + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests.EnumMember/Some.Nested.Namespace.ColorULongWrap.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests.EnumMember/Some.Nested.Namespace.ColorULongWrap.ISerialize`1.verified.cs new file mode 100644 index 00000000..ff7f9123 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests.EnumMember/Some.Nested.Namespace.ColorULongWrap.ISerialize`1.verified.cs @@ -0,0 +1,23 @@ +//HintName: Some.Nested.Namespace.ColorULongWrap.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +namespace Some.Nested.Namespace +{ + partial record struct ColorULongWrap : Serde.ISerialize + { + void ISerialize.Serialize(Some.Nested.Namespace.ColorULong value, ISerializer serializer) + { + var name = value switch + { + Some.Nested.Namespace.ColorULong.Red => "red", + Some.Nested.Namespace.ColorULong.Green => "green", + Some.Nested.Namespace.ColorULong.Blue => "blue", + _ => null + }; + serializer.SerializeEnumValue("ColorULong", name, new UInt64Wrap((ulong)value)); + } + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests.NestedEnumWrapper/C.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests.NestedEnumWrapper/C.ISerialize`1.verified.cs new file mode 100644 index 00000000..d85ab66b --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests.NestedEnumWrapper/C.ISerialize`1.verified.cs @@ -0,0 +1,15 @@ +//HintName: C.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial class C : Serde.ISerialize +{ + void ISerialize.Serialize(C value, ISerializer serializer) + { + var type = serializer.SerializeType("C", 1); + type.SerializeFieldIfNotNull>("colorOpt", value.ColorOpt); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests.NestedEnumWrapper/RgbWrap.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests.NestedEnumWrapper/RgbWrap.ISerialize`1.verified.cs new file mode 100644 index 00000000..a71aa8ad --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests.NestedEnumWrapper/RgbWrap.ISerialize`1.verified.cs @@ -0,0 +1,20 @@ +//HintName: RgbWrap.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial record struct RgbWrap : Serde.ISerialize +{ + void ISerialize.Serialize(Rgb value, ISerializer serializer) + { + var name = value switch + { + Rgb.Red => "red", + Rgb.Green => "green", + Rgb.Blue => "blue", + _ => null + }; + serializer.SerializeEnumValue("Rgb", name, new Int32Wrap((int)value)); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests.NestedExplicitSerializeWrapper/OPTSWrap.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests.NestedExplicitSerializeWrapper/OPTSWrap.ISerialize`1.verified.cs new file mode 100644 index 00000000..06184def --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests.NestedExplicitSerializeWrapper/OPTSWrap.ISerialize`1.verified.cs @@ -0,0 +1,18 @@ +//HintName: OPTSWrap.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial record struct OPTSWrap : Serde.ISerialize +{ + void ISerialize.Serialize(System.Runtime.InteropServices.ComTypes.BIND_OPTS value, ISerializer serializer) + { + var type = serializer.SerializeType("BIND_OPTS", 4); + type.SerializeField("cbStruct", value.cbStruct); + type.SerializeField("dwTickCountDeadline", value.dwTickCountDeadline); + type.SerializeField("grfFlags", value.grfFlags); + type.SerializeField("grfMode", value.grfMode); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests.NestedExplicitSerializeWrapper/S.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests.NestedExplicitSerializeWrapper/S.ISerialize`1.verified.cs new file mode 100644 index 00000000..43c868db --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests.NestedExplicitSerializeWrapper/S.ISerialize`1.verified.cs @@ -0,0 +1,15 @@ +//HintName: S.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial struct S : Serde.ISerialize +{ + void ISerialize.Serialize(S value, ISerializer serializer) + { + var type = serializer.SerializeType("S", 1); + type.SerializeField, Serde.ImmutableArrayWrap.SerializeImpl>("opts", value.Opts); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests.SerializeOnlyWrapper/SectionWrap.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests.SerializeOnlyWrapper/SectionWrap.ISerialize`1.verified.cs new file mode 100644 index 00000000..b2c8d6b3 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests.SerializeOnlyWrapper/SectionWrap.ISerialize`1.verified.cs @@ -0,0 +1,16 @@ +//HintName: SectionWrap.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial record struct SectionWrap : Serde.ISerialize +{ + void ISerialize.Serialize(System.Collections.Specialized.BitVector32.Section value, ISerializer serializer) + { + var type = serializer.SerializeType("Section", 2); + type.SerializeField("mask", value.Mask); + type.SerializeField("offset", value.Offset); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests/DictionaryGenerate#C.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests/DictionaryGenerate#C.ISerialize`1.verified.cs new file mode 100644 index 00000000..565295e9 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests/DictionaryGenerate#C.ISerialize`1.verified.cs @@ -0,0 +1,15 @@ +//HintName: C.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial class C : Serde.ISerialize +{ + void ISerialize.Serialize(C value, ISerializer serializer) + { + var type = serializer.SerializeType("C", 1); + type.SerializeField, Serde.DictWrap.SerializeImpl>("map", value.Map); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests/ExplicitGenericWrapper#C.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests/ExplicitGenericWrapper#C.ISerialize`1.verified.cs new file mode 100644 index 00000000..d1835bcb --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests/ExplicitGenericWrapper#C.ISerialize`1.verified.cs @@ -0,0 +1,15 @@ +//HintName: C.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial class C : Serde.ISerialize +{ + void ISerialize.Serialize(C value, ISerializer serializer) + { + var type = serializer.SerializeType("C", 1); + type.SerializeField, SWrap.SerializeImpl>("s", value.S); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests/ExplicitWrapper#C.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests/ExplicitWrapper#C.ISerialize`1.verified.cs new file mode 100644 index 00000000..6e7203b6 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests/ExplicitWrapper#C.ISerialize`1.verified.cs @@ -0,0 +1,15 @@ +//HintName: C.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial class C : Serde.ISerialize +{ + void ISerialize.Serialize(C value, ISerializer serializer) + { + var type = serializer.SerializeType("C", 1); + type.SerializeField("s", value.S); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests/IDictionaryImplGenerate#C.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests/IDictionaryImplGenerate#C.ISerialize`1.verified.cs new file mode 100644 index 00000000..8af66c89 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests/IDictionaryImplGenerate#C.ISerialize`1.verified.cs @@ -0,0 +1,15 @@ +//HintName: C.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial class C : Serde.ISerialize +{ + void ISerialize.Serialize(C value, ISerializer serializer) + { + var type = serializer.SerializeType("C", 1); + type.SerializeField>("rDictionary", value.RDictionary); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests/MemberSkip#Rgb.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests/MemberSkip#Rgb.ISerialize`1.verified.cs new file mode 100644 index 00000000..098514d9 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests/MemberSkip#Rgb.ISerialize`1.verified.cs @@ -0,0 +1,16 @@ +//HintName: Rgb.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial struct Rgb : Serde.ISerialize +{ + void ISerialize.Serialize(Rgb value, ISerializer serializer) + { + var type = serializer.SerializeType("Rgb", 2); + type.SerializeField("red", value.Red); + type.SerializeField("blue", value.Blue); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests/MemberSkipDeserialize#Rgb.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests/MemberSkipDeserialize#Rgb.ISerialize`1.verified.cs new file mode 100644 index 00000000..05dee29b --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests/MemberSkipDeserialize#Rgb.ISerialize`1.verified.cs @@ -0,0 +1,17 @@ +//HintName: Rgb.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial struct Rgb : Serde.ISerialize +{ + void ISerialize.Serialize(Rgb value, ISerializer serializer) + { + var type = serializer.SerializeType("Rgb", 3); + type.SerializeField("red", value.Red); + type.SerializeField("green", value.Green); + type.SerializeField("blue", value.Blue); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests/MemberSkipSerialize#Rgb.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests/MemberSkipSerialize#Rgb.ISerialize`1.verified.cs new file mode 100644 index 00000000..098514d9 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests/MemberSkipSerialize#Rgb.ISerialize`1.verified.cs @@ -0,0 +1,16 @@ +//HintName: Rgb.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial struct Rgb : Serde.ISerialize +{ + void ISerialize.Serialize(Rgb value, ISerializer serializer) + { + var type = serializer.SerializeType("Rgb", 2); + type.SerializeField("red", value.Red); + type.SerializeField("blue", value.Blue); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests/NestedArray#C.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests/NestedArray#C.ISerialize`1.verified.cs new file mode 100644 index 00000000..639683f8 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests/NestedArray#C.ISerialize`1.verified.cs @@ -0,0 +1,15 @@ +//HintName: C.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial class C : Serde.ISerialize +{ + void ISerialize.Serialize(C value, ISerializer serializer) + { + var type = serializer.SerializeType("C", 1); + type.SerializeField>>("nestedArr", value.NestedArr); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests/NestedArray2#C.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests/NestedArray2#C.ISerialize`1.verified.cs new file mode 100644 index 00000000..639683f8 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests/NestedArray2#C.ISerialize`1.verified.cs @@ -0,0 +1,15 @@ +//HintName: C.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial class C : Serde.ISerialize +{ + void ISerialize.Serialize(C value, ISerializer serializer) + { + var type = serializer.SerializeType("C", 1); + type.SerializeField>>("nestedArr", value.NestedArr); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests/NullableFields#S.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests/NullableFields#S.ISerialize`1.verified.cs new file mode 100644 index 00000000..58d369bc --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests/NullableFields#S.ISerialize`1.verified.cs @@ -0,0 +1,16 @@ +//HintName: S.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial struct S : Serde.ISerialize> +{ + void ISerialize>.Serialize(S value, ISerializer serializer) + { + var type = serializer.SerializeType("S", 4); + type.SerializeFieldIfNotNull>("fI", value.FI); + type.SerializeFieldIfNotNull>>("f3", value.F3); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests/NullableRefFields#S.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests/NullableRefFields#S.ISerialize`1.verified.cs new file mode 100644 index 00000000..5fe0cd7e --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests/NullableRefFields#S.ISerialize`1.verified.cs @@ -0,0 +1,19 @@ +//HintName: S.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial struct S : Serde.ISerialize> +{ + void ISerialize>.Serialize(S value, ISerializer serializer) + { + var type = serializer.SerializeType("S", 5); + type.SerializeFieldIfNotNull>("fS", value.FS); + type.SerializeField>("f1", value.F1); + type.SerializeFieldIfNotNull>("f2", value.F2); + type.SerializeFieldIfNotNull>>("f3", value.F3); + type.SerializeFieldIfNotNull>("f4", value.F4); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests/Rgb#Rgb.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests/Rgb#Rgb.ISerialize`1.verified.cs new file mode 100644 index 00000000..05dee29b --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests/Rgb#Rgb.ISerialize`1.verified.cs @@ -0,0 +1,17 @@ +//HintName: Rgb.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial struct Rgb : Serde.ISerialize +{ + void ISerialize.Serialize(Rgb value, ISerializer serializer) + { + var type = serializer.SerializeType("Rgb", 3); + type.SerializeField("red", value.Red); + type.SerializeField("green", value.Green); + type.SerializeField("blue", value.Blue); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests/TypeDoesntImplementISerialize#S1.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests/TypeDoesntImplementISerialize#S1.ISerialize`1.verified.cs new file mode 100644 index 00000000..15a1cc61 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests/TypeDoesntImplementISerialize#S1.ISerialize`1.verified.cs @@ -0,0 +1,14 @@ +//HintName: S1.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial struct S1 : Serde.ISerialize +{ + void ISerialize.Serialize(S1 value, ISerializer serializer) + { + var type = serializer.SerializeType("S1", 1); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests/TypeWithArray#C.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests/TypeWithArray#C.ISerialize`1.verified.cs new file mode 100644 index 00000000..18a91dd8 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests/TypeWithArray#C.ISerialize`1.verified.cs @@ -0,0 +1,15 @@ +//HintName: C.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial class C : Serde.ISerialize +{ + void ISerialize.Serialize(C value, ISerializer serializer) + { + var type = serializer.SerializeType("C", 1); + type.SerializeField>("intArr", value.IntArr); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests/WrongGenericWrapperForm#C.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests/WrongGenericWrapperForm#C.ISerialize`1.verified.cs new file mode 100644 index 00000000..2a634761 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests/WrongGenericWrapperForm#C.ISerialize`1.verified.cs @@ -0,0 +1,14 @@ +//HintName: C.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial class C : Serde.ISerialize +{ + void ISerialize.Serialize(C value, ISerializer serializer) + { + var type = serializer.SerializeType("C", 1); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests/WrongGenericWrapperForm.verified.txt b/test/Serde.Generation.Test/test_output/SerializeTests/WrongGenericWrapperForm.verified.txt index ca36d25f..0bc84757 100644 --- a/test/Serde.Generation.Test/test_output/SerializeTests/WrongGenericWrapperForm.verified.txt +++ b/test/Serde.Generation.Test/test_output/SerializeTests/WrongGenericWrapperForm.verified.txt @@ -5,7 +5,7 @@ Title: , Severity: Error, WarningLevel: 0, - Location: : (31,18)-(31,19), + Location: : (38,18)-(38,19), Description: , HelpLink: , MessageFormat: Could not find nested type named 'SerializeImpl' inside type 'SWrap<,>'. The wrapped type 'S' is generic, so the expected wrapper is a parent type with SerializeImpl and DeserializeImpl nested wrappers., @@ -17,7 +17,7 @@ Title: , Severity: Error, WarningLevel: 0, - Location: : (31,18)-(31,19), + Location: : (38,18)-(38,19), Description: , HelpLink: , MessageFormat: The member 'C.S's return type 'S' doesn't implement Serde.ISerialize. Either implement the interface, or use a wrapper., diff --git a/test/Serde.Generation.Test/test_output/WrapperTests.AttributeWrapperTest/Address.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/WrapperTests.AttributeWrapperTest/Address.ISerialize`1.verified.cs new file mode 100644 index 00000000..6eba74e5 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/WrapperTests.AttributeWrapperTest/Address.ISerialize`1.verified.cs @@ -0,0 +1,19 @@ +//HintName: Address.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial class Address : Serde.ISerialize
+{ + void ISerialize
.Serialize(Address value, ISerializer serializer) + { + var type = serializer.SerializeType("Address", 5); + type.SerializeField("name", value.Name, new System.Attribute[] { new System.Xml.Serialization.XmlAttributeAttribute() { }, new Serde.SerdeMemberOptions() { ProvideAttributes = true } }); + type.SerializeField("line1", value.Line1); + type.SerializeField("city", value.City); + type.SerializeField("state", value.State); + type.SerializeField("zip", value.Zip); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/WrapperTests.GenerateSerdeWrap/OPTSWrap.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/WrapperTests.GenerateSerdeWrap/OPTSWrap.ISerialize`1.verified.cs new file mode 100644 index 00000000..06184def --- /dev/null +++ b/test/Serde.Generation.Test/test_output/WrapperTests.GenerateSerdeWrap/OPTSWrap.ISerialize`1.verified.cs @@ -0,0 +1,18 @@ +//HintName: OPTSWrap.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial record struct OPTSWrap : Serde.ISerialize +{ + void ISerialize.Serialize(System.Runtime.InteropServices.ComTypes.BIND_OPTS value, ISerializer serializer) + { + var type = serializer.SerializeType("BIND_OPTS", 4); + type.SerializeField("cbStruct", value.cbStruct); + type.SerializeField("dwTickCountDeadline", value.dwTickCountDeadline); + type.SerializeField("grfFlags", value.grfFlags); + type.SerializeField("grfMode", value.grfMode); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/WrapperTests.NestedDeserializeWrap/OPTSWrap.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/WrapperTests.NestedDeserializeWrap/OPTSWrap.ISerialize`1.verified.cs new file mode 100644 index 00000000..fc4cfa3b --- /dev/null +++ b/test/Serde.Generation.Test/test_output/WrapperTests.NestedDeserializeWrap/OPTSWrap.ISerialize`1.verified.cs @@ -0,0 +1,18 @@ +//HintName: OPTSWrap.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial record struct OPTSWrap : Serde.ISerialize +{ + void ISerialize.Serialize(System.Runtime.InteropServices.ComTypes.BIND_OPTS value, ISerializer serializer) + { + var type = serializer.SerializeType("BIND_OPTS", 4); + type.SerializeField("cbStruct", Value.cbStruct); + type.SerializeField("dwTickCountDeadline", Value.dwTickCountDeadline); + type.SerializeField("grfFlags", Value.grfFlags); + type.SerializeField("grfMode", Value.grfMode); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/WrapperTests.NestedExplicitWrapper/Outer.SectionWrap.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/WrapperTests.NestedExplicitWrapper/Outer.SectionWrap.ISerialize`1.verified.cs new file mode 100644 index 00000000..6075d4bb --- /dev/null +++ b/test/Serde.Generation.Test/test_output/WrapperTests.NestedExplicitWrapper/Outer.SectionWrap.ISerialize`1.verified.cs @@ -0,0 +1,19 @@ +//HintName: Outer.SectionWrap.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial class Outer +{ + partial record struct SectionWrap : Serde.ISerialize + { + void ISerialize.Serialize(System.Collections.Specialized.BitVector32.Section value, ISerializer serializer) + { + var type = serializer.SerializeType("Section", 2); + type.SerializeField("mask", value.Mask); + type.SerializeField("offset", value.Offset); + type.End(); + } + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/WrapperTests.NestedExplicitWrapper/S.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/WrapperTests.NestedExplicitWrapper/S.ISerialize`1.verified.cs new file mode 100644 index 00000000..993ab77c --- /dev/null +++ b/test/Serde.Generation.Test/test_output/WrapperTests.NestedExplicitWrapper/S.ISerialize`1.verified.cs @@ -0,0 +1,15 @@ +//HintName: S.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial struct S : Serde.ISerialize +{ + void ISerialize.Serialize(S value, ISerializer serializer) + { + var type = serializer.SerializeType("S", 1); + type.SerializeField, Serde.ImmutableArrayWrap.SerializeImpl>("sections", value.Sections); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/WrapperTests.PointWrap/PointWrap.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/WrapperTests.PointWrap/PointWrap.ISerialize`1.verified.cs new file mode 100644 index 00000000..56a99294 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/WrapperTests.PointWrap/PointWrap.ISerialize`1.verified.cs @@ -0,0 +1,16 @@ +//HintName: PointWrap.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial struct PointWrap : Serde.ISerialize +{ + void ISerialize.Serialize(Point value, ISerializer serializer) + { + var type = serializer.SerializeType("Point", 2); + type.SerializeField("x", _point.X); + type.SerializeField("y", _point.Y); + type.End(); + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/WrapperTests.RecursiveType/Test.Parent.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/WrapperTests.RecursiveType/Test.Parent.ISerialize`1.verified.cs new file mode 100644 index 00000000..a84929c2 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/WrapperTests.RecursiveType/Test.Parent.ISerialize`1.verified.cs @@ -0,0 +1,18 @@ +//HintName: Test.Parent.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +namespace Test +{ + partial record Parent : Serde.ISerialize + { + void ISerialize.Serialize(Test.Parent value, ISerializer serializer) + { + var type = serializer.SerializeType("Parent", 1); + type.SerializeField("r", value.R); + type.End(); + } + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/WrapperTests.RecursiveType/Test.RecursiveWrap.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/WrapperTests.RecursiveType/Test.RecursiveWrap.ISerialize`1.verified.cs new file mode 100644 index 00000000..ae4c4a7e --- /dev/null +++ b/test/Serde.Generation.Test/test_output/WrapperTests.RecursiveType/Test.RecursiveWrap.ISerialize`1.verified.cs @@ -0,0 +1,18 @@ +//HintName: Test.RecursiveWrap.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +namespace Test +{ + partial record struct RecursiveWrap : Serde.ISerialize + { + void ISerialize.Serialize(Recursive value, ISerializer serializer) + { + var type = serializer.SerializeType("Recursive", 1); + type.SerializeFieldIfNotNull("next", Value.Next); + type.End(); + } + } +} \ No newline at end of file diff --git a/test/Serde.Test/GenericWrapperTests.cs b/test/Serde.Test/GenericWrapperTests.cs index 14e94e1b..4034c071 100644 --- a/test/Serde.Test/GenericWrapperTests.cs +++ b/test/Serde.Test/GenericWrapperTests.cs @@ -95,11 +95,13 @@ public void CustomEnumerableSerializeExplicitWrapOnType() internal static partial class CustomImArrayWrap { public readonly record struct SerializeImpl(CustomImArray cia) - : ISerialize, ISerializeWrap, SerializeImpl> + : ISerialize, ISerialize>, ISerializeWrap, SerializeImpl> where TWrap : struct, ISerializeWrap, ISerialize { public static SerializeImpl Create(CustomImArray t) => new(t); + void ISerialize>.Serialize(CustomImArray value, ISerializer serializer) + => EnumerableHelpers.SerializeSpan(typeof(CustomImArray).ToString(), value.Backing.AsSpan(), serializer); void ISerialize.Serialize(ISerializer serializer) => EnumerableHelpers.SerializeSpan(typeof(CustomImArray).ToString(), cia.Backing.AsSpan(), serializer); } @@ -142,11 +144,13 @@ CustomImArray IDeserializeVisitor>.VisitEnumerable(ref D internal static partial class CustomImArray2Wrap { public readonly record struct SerializeImpl(CustomImArray2 cia) - : ISerialize, ISerializeWrap, SerializeImpl> + : ISerialize, ISerialize>, ISerializeWrap, SerializeImpl> where TWrap : struct, ISerializeWrap, ISerialize { public static SerializeImpl Create(CustomImArray2 t) => new(t); + void ISerialize>.Serialize(CustomImArray2 value, ISerializer serializer) + => EnumerableHelpers.SerializeSpan(typeof(CustomImArray2).ToString(), value.Backing.AsSpan(), serializer); void ISerialize.Serialize(ISerializer serializer) => EnumerableHelpers.SerializeSpan(typeof(CustomImArray2).ToString(), cia.Backing.AsSpan(), serializer); } diff --git a/test/Serde.Test/JsonSerializerTests.cs b/test/Serde.Test/JsonSerializerTests.cs index 9911b9fc..f1d04b1b 100644 --- a/test/Serde.Test/JsonSerializerTests.cs +++ b/test/Serde.Test/JsonSerializerTests.cs @@ -95,13 +95,23 @@ public void NestedEnumerable() ]"); } - private struct JsonDictionaryWrapper : ISerialize + private struct JsonDictionaryWrapper : ISerialize, ISerialize { private readonly Dictionary _d; public JsonDictionaryWrapper(Dictionary d) { _d = d; } + public void Serialize(JsonDictionaryWrapper value, ISerializer serializer) + { + var sd = serializer.SerializeDictionary(value._d.Count); + foreach (var (k,v) in value._d) + { + sd.SerializeKey(new StringWrap(k.ToString())); + sd.SerializeValue(new Int32Wrap(v)); + } + sd.End(); + } public void Serialize(ISerializer serializer) { var sd = serializer.SerializeDictionary(_d.Count); @@ -135,7 +145,7 @@ public void TestCustomDictionary() public void NullableString() { string? s = null; - var js = Serde.Json.JsonSerializer.Serialize(new NullableRefWrap.SerializeImpl(s)); + var js = Serde.Json.JsonSerializer.Serialize>(s); Assert.Equal("null", js); js = Serde.Json.JsonSerializer.Serialize(JsonValue.Null.Instance); Assert.Equal("null", js); diff --git a/test/Serde.Test/RoundtripTests.cs b/test/Serde.Test/RoundtripTests.cs index 2ce08c6c..7a24c361 100644 --- a/test/Serde.Test/RoundtripTests.cs +++ b/test/Serde.Test/RoundtripTests.cs @@ -13,7 +13,7 @@ public void MaxSizeTypeTest() AssertRoundTrip(t); } - private static void AssertRoundTrip(T t) where T : ISerialize, IDeserialize + private static void AssertRoundTrip(T t) where T : ISerialize, ISerialize, IDeserialize { var result = JsonSerializer.Deserialize(JsonSerializer.Serialize(t)); Assert.Equal(t, result); diff --git a/test/Serde.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.AllInOne.ColorEnumWrap.ISerialize`1.cs b/test/Serde.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.AllInOne.ColorEnumWrap.ISerialize`1.cs new file mode 100644 index 00000000..7ce6656a --- /dev/null +++ b/test/Serde.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.AllInOne.ColorEnumWrap.ISerialize`1.cs @@ -0,0 +1,25 @@ + +#nullable enable +using System; +using Serde; + +namespace Serde.Test +{ + partial record AllInOne + { + partial record struct ColorEnumWrap : Serde.ISerialize + { + void ISerialize.Serialize(Serde.Test.AllInOne.ColorEnum value, ISerializer serializer) + { + var name = value switch + { + Serde.Test.AllInOne.ColorEnum.Red => "red", + Serde.Test.AllInOne.ColorEnum.Blue => "blue", + Serde.Test.AllInOne.ColorEnum.Green => "green", + _ => null + }; + serializer.SerializeEnumValue("ColorEnum", name, new Int32Wrap((int)value)); + } + } + } +} \ No newline at end of file diff --git a/test/Serde.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.AllInOne.ISerialize`1.cs b/test/Serde.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.AllInOne.ISerialize`1.cs new file mode 100644 index 00000000..167d22f6 --- /dev/null +++ b/test/Serde.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.AllInOne.ISerialize`1.cs @@ -0,0 +1,32 @@ + +#nullable enable +using System; +using Serde; + +namespace Serde.Test +{ + partial record AllInOne : Serde.ISerialize + { + void ISerialize.Serialize(Serde.Test.AllInOne value, ISerializer serializer) + { + var type = serializer.SerializeType("AllInOne", 16); + type.SerializeField("boolField", value.BoolField); + type.SerializeField("charField", value.CharField); + type.SerializeField("byteField", value.ByteField); + type.SerializeField("uShortField", value.UShortField); + type.SerializeField("uIntField", value.UIntField); + type.SerializeField("uLongField", value.ULongField); + type.SerializeField("sByteField", value.SByteField); + type.SerializeField("shortField", value.ShortField); + type.SerializeField("intField", value.IntField); + type.SerializeField("longField", value.LongField); + type.SerializeField("stringField", value.StringField); + type.SerializeFieldIfNotNull>("nullStringField", value.NullStringField); + type.SerializeField>("uIntArr", value.UIntArr); + type.SerializeField>>("nestedArr", value.NestedArr); + type.SerializeField, Serde.ImmutableArrayWrap.SerializeImpl>("intImm", value.IntImm); + type.SerializeField("color", value.Color); + type.End(); + } + } +} \ No newline at end of file diff --git a/test/Serde.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.GenericWrapperTests.CustomArrayWrapExplicitOnType.ISerialize`1.cs b/test/Serde.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.GenericWrapperTests.CustomArrayWrapExplicitOnType.ISerialize`1.cs new file mode 100644 index 00000000..eb27ee39 --- /dev/null +++ b/test/Serde.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.GenericWrapperTests.CustomArrayWrapExplicitOnType.ISerialize`1.cs @@ -0,0 +1,20 @@ + +#nullable enable +using System; +using Serde; + +namespace Serde.Test +{ + partial class GenericWrapperTests + { + partial record struct CustomArrayWrapExplicitOnType : Serde.ISerialize + { + void ISerialize.Serialize(Serde.Test.GenericWrapperTests.CustomArrayWrapExplicitOnType value, ISerializer serializer) + { + var type = serializer.SerializeType("CustomArrayWrapExplicitOnType", 1); + type.SerializeField, Serde.Test.GenericWrapperTests.CustomImArray2Wrap.SerializeImpl>("a", value.A); + type.End(); + } + } + } +} \ No newline at end of file diff --git a/test/Serde.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.GenericWrapperTests.CustomImArrayExplicitWrapOnMember.ISerialize`1.cs b/test/Serde.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.GenericWrapperTests.CustomImArrayExplicitWrapOnMember.ISerialize`1.cs new file mode 100644 index 00000000..214d7c73 --- /dev/null +++ b/test/Serde.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.GenericWrapperTests.CustomImArrayExplicitWrapOnMember.ISerialize`1.cs @@ -0,0 +1,20 @@ + +#nullable enable +using System; +using Serde; + +namespace Serde.Test +{ + partial class GenericWrapperTests + { + partial record struct CustomImArrayExplicitWrapOnMember : Serde.ISerialize + { + void ISerialize.Serialize(Serde.Test.GenericWrapperTests.CustomImArrayExplicitWrapOnMember value, ISerializer serializer) + { + var type = serializer.SerializeType("CustomImArrayExplicitWrapOnMember", 1); + type.SerializeField, Serde.Test.GenericWrapperTests.CustomImArrayWrap.SerializeImpl>("a", value.A); + type.End(); + } + } + } +} \ No newline at end of file diff --git a/test/Serde.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.JsonSerializerTests.NullableFields.ISerialize`1.cs b/test/Serde.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.JsonSerializerTests.NullableFields.ISerialize`1.cs new file mode 100644 index 00000000..76fe9789 --- /dev/null +++ b/test/Serde.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.JsonSerializerTests.NullableFields.ISerialize`1.cs @@ -0,0 +1,21 @@ + +#nullable enable +using System; +using Serde; + +namespace Serde.Test +{ + partial class JsonSerializerTests + { + partial class NullableFields : Serde.ISerialize + { + void ISerialize.Serialize(Serde.Test.JsonSerializerTests.NullableFields value, ISerializer serializer) + { + var type = serializer.SerializeType("NullableFields", 2); + type.SerializeFieldIfNotNull>("s", value.S); + type.SerializeField, Serde.DictWrap.SerializeImpl>>("d", value.D); + type.End(); + } + } + } +} \ No newline at end of file diff --git a/test/Serde.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.MaxSizeType.ISerialize`1.cs b/test/Serde.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.MaxSizeType.ISerialize`1.cs new file mode 100644 index 00000000..ceb95135 --- /dev/null +++ b/test/Serde.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.MaxSizeType.ISerialize`1.cs @@ -0,0 +1,80 @@ + +#nullable enable +using System; +using Serde; + +namespace Serde.Test +{ + partial struct MaxSizeType : Serde.ISerialize + { + void ISerialize.Serialize(Serde.Test.MaxSizeType value, ISerializer serializer) + { + var type = serializer.SerializeType("MaxSizeType", 64); + type.SerializeField("field1", value.Field1); + type.SerializeField("field2", value.Field2); + type.SerializeField("field3", value.Field3); + type.SerializeField("field4", value.Field4); + type.SerializeField("field5", value.Field5); + type.SerializeField("field6", value.Field6); + type.SerializeField("field7", value.Field7); + type.SerializeField("field8", value.Field8); + type.SerializeField("field9", value.Field9); + type.SerializeField("field10", value.Field10); + type.SerializeField("field11", value.Field11); + type.SerializeField("field12", value.Field12); + type.SerializeField("field13", value.Field13); + type.SerializeField("field14", value.Field14); + type.SerializeField("field15", value.Field15); + type.SerializeField("field16", value.Field16); + type.SerializeField("field17", value.Field17); + type.SerializeField("field18", value.Field18); + type.SerializeField("field19", value.Field19); + type.SerializeField("field20", value.Field20); + type.SerializeField("field21", value.Field21); + type.SerializeField("field22", value.Field22); + type.SerializeField("field23", value.Field23); + type.SerializeField("field24", value.Field24); + type.SerializeField("field25", value.Field25); + type.SerializeField("field26", value.Field26); + type.SerializeField("field27", value.Field27); + type.SerializeField("field28", value.Field28); + type.SerializeField("field29", value.Field29); + type.SerializeField("field30", value.Field30); + type.SerializeField("field31", value.Field31); + type.SerializeField("field32", value.Field32); + type.SerializeField("field33", value.Field33); + type.SerializeField("field34", value.Field34); + type.SerializeField("field35", value.Field35); + type.SerializeField("field36", value.Field36); + type.SerializeField("field37", value.Field37); + type.SerializeField("field38", value.Field38); + type.SerializeField("field39", value.Field39); + type.SerializeField("field40", value.Field40); + type.SerializeField("field41", value.Field41); + type.SerializeField("field42", value.Field42); + type.SerializeField("field43", value.Field43); + type.SerializeField("field44", value.Field44); + type.SerializeField("field45", value.Field45); + type.SerializeField("field46", value.Field46); + type.SerializeField("field47", value.Field47); + type.SerializeField("field48", value.Field48); + type.SerializeField("field49", value.Field49); + type.SerializeField("field50", value.Field50); + type.SerializeField("field51", value.Field51); + type.SerializeField("field52", value.Field52); + type.SerializeField("field53", value.Field53); + type.SerializeField("field54", value.Field54); + type.SerializeField("field55", value.Field55); + type.SerializeField("field56", value.Field56); + type.SerializeField("field57", value.Field57); + type.SerializeField("field58", value.Field58); + type.SerializeField("field59", value.Field59); + type.SerializeField("field60", value.Field60); + type.SerializeField("field61", value.Field61); + type.SerializeField("field62", value.Field62); + type.SerializeField("field63", value.Field63); + type.SerializeField("field64", value.Field64); + type.End(); + } + } +} \ No newline at end of file diff --git a/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.AllInOne.ColorEnumWrap.ISerialize`1.cs b/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.AllInOne.ColorEnumWrap.ISerialize`1.cs new file mode 100644 index 00000000..7ce6656a --- /dev/null +++ b/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.AllInOne.ColorEnumWrap.ISerialize`1.cs @@ -0,0 +1,25 @@ + +#nullable enable +using System; +using Serde; + +namespace Serde.Test +{ + partial record AllInOne + { + partial record struct ColorEnumWrap : Serde.ISerialize + { + void ISerialize.Serialize(Serde.Test.AllInOne.ColorEnum value, ISerializer serializer) + { + var name = value switch + { + Serde.Test.AllInOne.ColorEnum.Red => "red", + Serde.Test.AllInOne.ColorEnum.Blue => "blue", + Serde.Test.AllInOne.ColorEnum.Green => "green", + _ => null + }; + serializer.SerializeEnumValue("ColorEnum", name, new Int32Wrap((int)value)); + } + } + } +} \ No newline at end of file diff --git a/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.AllInOne.ISerialize`1.cs b/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.AllInOne.ISerialize`1.cs new file mode 100644 index 00000000..167d22f6 --- /dev/null +++ b/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.AllInOne.ISerialize`1.cs @@ -0,0 +1,32 @@ + +#nullable enable +using System; +using Serde; + +namespace Serde.Test +{ + partial record AllInOne : Serde.ISerialize + { + void ISerialize.Serialize(Serde.Test.AllInOne value, ISerializer serializer) + { + var type = serializer.SerializeType("AllInOne", 16); + type.SerializeField("boolField", value.BoolField); + type.SerializeField("charField", value.CharField); + type.SerializeField("byteField", value.ByteField); + type.SerializeField("uShortField", value.UShortField); + type.SerializeField("uIntField", value.UIntField); + type.SerializeField("uLongField", value.ULongField); + type.SerializeField("sByteField", value.SByteField); + type.SerializeField("shortField", value.ShortField); + type.SerializeField("intField", value.IntField); + type.SerializeField("longField", value.LongField); + type.SerializeField("stringField", value.StringField); + type.SerializeFieldIfNotNull>("nullStringField", value.NullStringField); + type.SerializeField>("uIntArr", value.UIntArr); + type.SerializeField>>("nestedArr", value.NestedArr); + type.SerializeField, Serde.ImmutableArrayWrap.SerializeImpl>("intImm", value.IntImm); + type.SerializeField("color", value.Color); + type.End(); + } + } +} \ No newline at end of file diff --git a/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.SampleTest.Address.ISerialize`1.cs b/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.SampleTest.Address.ISerialize`1.cs new file mode 100644 index 00000000..3082bf90 --- /dev/null +++ b/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.SampleTest.Address.ISerialize`1.cs @@ -0,0 +1,24 @@ + +#nullable enable +using System; +using Serde; + +namespace Serde.Test +{ + partial class SampleTest + { + partial record Address : Serde.ISerialize + { + void ISerialize.Serialize(Serde.Test.SampleTest.Address value, ISerializer serializer) + { + var type = serializer.SerializeType("Address", 5); + type.SerializeField("Name", value.Name, new System.Attribute[] { new System.Xml.Serialization.XmlAttributeAttribute() { }, new Serde.SerdeMemberOptions() { ProvideAttributes = true } }); + type.SerializeField("Line1", value.Line1); + type.SerializeFieldIfNotNull>("City", value.City); + type.SerializeField("State", value.State); + type.SerializeField("Zip", value.Zip); + type.End(); + } + } + } +} \ No newline at end of file diff --git a/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.SampleTest.OrderedItem.ISerialize`1.cs b/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.SampleTest.OrderedItem.ISerialize`1.cs new file mode 100644 index 00000000..17213da2 --- /dev/null +++ b/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.SampleTest.OrderedItem.ISerialize`1.cs @@ -0,0 +1,24 @@ + +#nullable enable +using System; +using Serde; + +namespace Serde.Test +{ + partial class SampleTest + { + partial record OrderedItem : Serde.ISerialize + { + void ISerialize.Serialize(Serde.Test.SampleTest.OrderedItem value, ISerializer serializer) + { + var type = serializer.SerializeType("OrderedItem", 5); + type.SerializeField("ItemName", value.ItemName); + type.SerializeField("Description", value.Description); + type.SerializeField("UnitPrice", value.UnitPrice); + type.SerializeField("Quantity", value.Quantity); + type.SerializeField("LineTotal", value.LineTotal); + type.End(); + } + } + } +} \ No newline at end of file diff --git a/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.SampleTest.PurchaseOrder.ISerialize`1.cs b/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.SampleTest.PurchaseOrder.ISerialize`1.cs new file mode 100644 index 00000000..1526f324 --- /dev/null +++ b/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.SampleTest.PurchaseOrder.ISerialize`1.cs @@ -0,0 +1,25 @@ + +#nullable enable +using System; +using Serde; + +namespace Serde.Test +{ + partial class SampleTest + { + partial record PurchaseOrder : Serde.ISerialize + { + void ISerialize.Serialize(Serde.Test.SampleTest.PurchaseOrder value, ISerializer serializer) + { + var type = serializer.SerializeType("PurchaseOrder", 6); + type.SerializeField>("ShipTo", value.ShipTo); + type.SerializeField("OrderDate", value.OrderDate); + type.SerializeField>>("Items", value.OrderedItems); + type.SerializeField("SubTotal", value.SubTotal); + type.SerializeField("ShipCost", value.ShipCost); + type.SerializeField("TotalCost", value.TotalCost); + type.End(); + } + } + } +} \ No newline at end of file diff --git a/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.XmlTests.BoolStruct.ISerialize`1.cs b/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.XmlTests.BoolStruct.ISerialize`1.cs new file mode 100644 index 00000000..5c81e6fc --- /dev/null +++ b/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.XmlTests.BoolStruct.ISerialize`1.cs @@ -0,0 +1,20 @@ + +#nullable enable +using System; +using Serde; + +namespace Serde.Test +{ + partial class XmlTests + { + partial struct BoolStruct : Serde.ISerialize + { + void ISerialize.Serialize(Serde.Test.XmlTests.BoolStruct value, ISerializer serializer) + { + var type = serializer.SerializeType("BoolStruct", 1); + type.SerializeField("BoolField", value.BoolField); + type.End(); + } + } + } +} \ No newline at end of file diff --git a/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.XmlTests.MapTest1.ISerialize`1.cs b/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.XmlTests.MapTest1.ISerialize`1.cs new file mode 100644 index 00000000..aa1e1c2c --- /dev/null +++ b/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.XmlTests.MapTest1.ISerialize`1.cs @@ -0,0 +1,20 @@ + +#nullable enable +using System; +using Serde; + +namespace Serde.Test +{ + partial class XmlTests + { + partial class MapTest1 : Serde.ISerialize + { + void ISerialize.Serialize(Serde.Test.XmlTests.MapTest1 value, ISerializer serializer) + { + var type = serializer.SerializeType("MapTest1", 1); + type.SerializeField, Serde.DictWrap.SerializeImpl>("MapField", value.MapField); + type.End(); + } + } + } +} \ No newline at end of file diff --git a/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.XmlTests.NestedArrays.ISerialize`1.cs b/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.XmlTests.NestedArrays.ISerialize`1.cs new file mode 100644 index 00000000..b888a57c --- /dev/null +++ b/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.XmlTests.NestedArrays.ISerialize`1.cs @@ -0,0 +1,20 @@ + +#nullable enable +using System; +using Serde; + +namespace Serde.Test +{ + partial class XmlTests + { + partial class NestedArrays : Serde.ISerialize + { + void ISerialize.Serialize(Serde.Test.XmlTests.NestedArrays value, ISerializer serializer) + { + var type = serializer.SerializeType("NestedArrays", 1); + type.SerializeField>>>("A", value.A); + type.End(); + } + } + } +} \ No newline at end of file diff --git a/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.XmlTests.StructWithIntField.ISerialize`1.cs b/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.XmlTests.StructWithIntField.ISerialize`1.cs new file mode 100644 index 00000000..c923a8e4 --- /dev/null +++ b/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.XmlTests.StructWithIntField.ISerialize`1.cs @@ -0,0 +1,20 @@ + +#nullable enable +using System; +using Serde; + +namespace Serde.Test +{ + partial class XmlTests + { + partial record StructWithIntField : Serde.ISerialize + { + void ISerialize.Serialize(Serde.Test.XmlTests.StructWithIntField value, ISerializer serializer) + { + var type = serializer.SerializeType("StructWithIntField", 1); + type.SerializeField("X", value.X); + type.End(); + } + } + } +} \ No newline at end of file diff --git a/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.XmlTests.TypeWithArrayField.ISerialize`1.cs b/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.XmlTests.TypeWithArrayField.ISerialize`1.cs new file mode 100644 index 00000000..ee4d8734 --- /dev/null +++ b/test/Serde.Xml.Test/generated/SerdeGenerator/Serde.SerdeImplRoslynGenerator/Serde.Test.XmlTests.TypeWithArrayField.ISerialize`1.cs @@ -0,0 +1,20 @@ + +#nullable enable +using System; +using Serde; + +namespace Serde.Test +{ + partial class XmlTests + { + partial class TypeWithArrayField : Serde.ISerialize + { + void ISerialize.Serialize(Serde.Test.XmlTests.TypeWithArrayField value, ISerializer serializer) + { + var type = serializer.SerializeType("TypeWithArrayField", 1); + type.SerializeField>>("ArrayField", value.ArrayField); + type.End(); + } + } + } +} \ No newline at end of file