// // PacketListIndexAttributeGenerator.cs // // Copyright (c) František Boháček. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.CodeDom.Compiler; using System.Reflection; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using NosSmooth.PacketSerializersGenerator.Data; using NosSmooth.PacketSerializersGenerator.Errors; using NosSmooth.PacketSerializersGenerator.Extensions; using ParameterInfo = NosSmooth.PacketSerializersGenerator.Data.ParameterInfo; namespace NosSmooth.PacketSerializersGenerator.AttributeGenerators; /// public class PacketListIndexAttributeGenerator : IParameterGenerator { private readonly InlineTypeConverterGenerator _inlineTypeConverterGenerators; /// /// Initializes a new instance of the class. /// /// The generator for types. public PacketListIndexAttributeGenerator(InlineTypeConverterGenerator inlineTypeConverterGenerators) { _inlineTypeConverterGenerators = inlineTypeConverterGenerators; } /// /// Gets the full name of the packet index attribute. /// public string PacketListIndexAttributeFullName { get; set; } = "NosSmooth.PacketSerializer.Abstractions.Attributes.PacketListIndexAttribute"; /// public bool ShouldHandle(ParameterInfo parameter) => parameter.Attributes.Any(x => x.FullName == PacketListIndexAttributeFullName); /// public IError? CheckParameter(PacketInfo packet, ParameterInfo parameter) { var error = ParameterChecker.CheckHasOneAttribute(packet, parameter); if (error is not null) { return error; } return ParameterChecker.CheckOptionalIsNullable(packet, parameter); } /// public IError? GenerateSerializerPart(IndentedTextWriter textWriter, PacketInfo packetInfo) { var generator = new ConverterSerializationGenerator(textWriter); var parameter = packetInfo.Parameters.Current; var attribute = parameter.Attributes.First(x => x.FullName == PacketListIndexAttributeFullName); if (parameter.IsOptional()) { textWriter.WriteLine($"if (obj.{parameter.GetVariableName()} is not null)"); textWriter.WriteLine("{"); textWriter.Indent++; } var afterSeparator = attribute.GetNamedValue("AfterSeparator", null); if (afterSeparator is not null) { generator.SetAfterSeparatorOnce((char)afterSeparator); } var listSeparator = attribute.GetNamedValue("ListSeparator", '|'); generator.PushLevel(listSeparator); var innerSeparator = attribute.GetNamedValue("InnerSeparator", '.'); generator.PrepareLevel(innerSeparator); _inlineTypeConverterGenerators.Serialize(textWriter, packetInfo); generator.RemovePreparedLevel(); generator.PopLevel(); // end optional if if (parameter.IsOptional()) { textWriter.Indent--; textWriter.WriteLine("}"); } return null; } /// public IError? GenerateDeserializerPart(IndentedTextWriter textWriter, PacketInfo packetInfo) => GenerateDeserializerPart(textWriter, packetInfo, true); /// /// Generate part for the Deserializer method to deserialize the given parameter. /// /// The text writer to write the code to. /// The packet info to generate for. /// Whether to declare the local variable. /// The generated source code. public IError? GenerateDeserializerPart(IndentedTextWriter textWriter, PacketInfo packetInfo, bool declare) { var generator = new ConverterDeserializationGenerator(textWriter); var parameter = packetInfo.Parameters.Current; var attribute = parameter.Attributes.First(x => x.FullName == PacketListIndexAttributeFullName); if (declare) { generator.DeclareLocalVariable(parameter); } // add optional if if (parameter.IsOptional()) { generator.StartOptionalCheck(parameter, packetInfo.Name); } var afterSeparator = attribute.GetNamedValue("AfterSeparator", null); if (afterSeparator is not null) { generator.SetAfterSeparatorOnce((char)afterSeparator); } var listSeparator = attribute.GetNamedValue("ListSeparator", '|'); var length = attribute.GetNamedValue("Length", 0); generator.PushLevel(listSeparator, length != 0 ? (uint?)length : (uint?)null); var innerSeparator = attribute.GetNamedValue("InnerSeparator", '.'); generator.PrepareLevel(innerSeparator); generator.DeserializeAndCheck(parameter, packetInfo, _inlineTypeConverterGenerators); generator.RemovePreparedLevel(); generator.PopLevel(); if (!parameter.Nullable) { generator.CheckNullError (parameter.GetNullableVariableName(), parameter.GetResultVariableName(), parameter.Name); } generator.AssignLocalVariable(parameter, false); // end is last token if body if (parameter.IsOptional()) { generator.EndOptionalCheck(parameter); } return null; } }