// // ConverterDeserializationGenerator.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 NosSmooth.PacketSerializersGenerator.Data; using NosSmooth.PacketSerializersGenerator.Errors; using NosSmooth.PacketSerializersGenerator.Extensions; namespace NosSmooth.PacketSerializersGenerator; /// /// Various templates for converter deserialization. /// public class ConverterDeserializationGenerator { private readonly string _stringEnumeratorVariable = "stringEnumerator"; private readonly IndentedTextWriter _textWriter; /// /// Initializes a new instance of the class. /// /// The text writer. public ConverterDeserializationGenerator(IndentedTextWriter textWriter) { _textWriter = textWriter; } /// /// Push level to the string enumerator. /// /// The separator. public void SetAfterSeparatorOnce(char separator) { _textWriter.WriteLine(@$"{_stringEnumeratorVariable}.SetAfterSeparatorOnce('{separator}');"); } /// /// Sets that the next token should be read to the last entry in the level. /// public void SetReadToLast() { _textWriter.WriteLine(@$"{_stringEnumeratorVariable}.SetReadToLast();"); } /// /// Push level to the string enumerator. /// /// The separator. /// The maximum number of tokens to read. public void PushLevel(char separator, uint? maxTokens = default) { _textWriter.WriteLine(@$"{_stringEnumeratorVariable}.PushLevel('{separator}', {maxTokens?.ToString() ?? "null"});"); } /// /// Pop level from the string enumerator. /// public void PopLevel() { _textWriter.WriteLine($"{_stringEnumeratorVariable}.PopLevel();"); } /// /// Prepare the level to the string enumerator. /// /// The separator. /// The maximum number of tokens to read. public void PrepareLevel(char separator, uint? maxTokens = default) { _textWriter.WriteLine($@"{_stringEnumeratorVariable}.PrepareLevel('{separator}', {maxTokens?.ToString() ?? "null"});"); } /// /// Prepare the level to the string enumerator. /// public void RemovePreparedLevel() { _textWriter.WriteLine($@"{_stringEnumeratorVariable}.RemovePreparedLevel();"); } /// /// Try to read to the last token of the level. /// /// /// If we know that we are not on the last token in the item level, just skip to the end of the item. /// Note that if this is the case, then that means the converter is either corrupted /// or the packet has more fields. /// public void ReadToLastToken() { _textWriter.WriteLine($@"while ({_stringEnumeratorVariable}.IsOnLastToken() == false)"); _textWriter.WriteLine("{"); _textWriter.Indent++; _textWriter.WriteLine($"{_stringEnumeratorVariable}.GetNextToken(out _);"); _textWriter.Indent--; _textWriter.WriteLine("}"); } /// /// Check taht the given variable is not null, if it is, return an error. /// /// The variable to check for null. /// The result variable to use for the error. /// The parameter that is being parsed. /// The reason for the error. public void CheckNullError(string nullableVariableName, string resultVariableName, string parameterName, string reason = "The converter has returned null even though it was not expected.") { _textWriter.WriteMultiline($@" if ({nullableVariableName} is null) {{ return new PacketParameterSerializerError(this, ""{parameterName}"", {resultVariableName}, ""{reason}""); }} "); } /// /// Assign local variable with the result of the parameter deserialization. /// /// The parameter. public void DeclareLocalVariable(ParameterInfo parameter) { _textWriter.WriteLine($"{parameter.GetActualType()} {parameter.GetVariableName()};"); } /// /// Assign local variable with the result of the parameter deserialization. /// /// The parameter. /// Whether to also declare the local variable. public void AssignLocalVariable(ParameterInfo parameter, bool declare = true) { _textWriter.WriteLine($"{(declare ? "var " : string.Empty)}{parameter.Name} = ({parameter.GetActualType()}){parameter.GetNullableVariableName()};"); } /// /// Begins the if for optionals, check if the parameter is not nullable. /// /// The parameter information. /// The name of the packet. public void StartOptionalCheck(ParameterInfo parameter, string packetName) { // serialize this parameter only if we are not on the last token. _textWriter.WriteLine($"if (!(stringEnumerator.IsOnLastToken() ?? true))"); _textWriter.WriteLine("{"); _textWriter.Indent++; } /// /// Ends the if for optionals. /// /// The parameter information. public void EndOptionalCheck(ParameterInfo parameter) { _textWriter.Indent--; _textWriter.WriteLine("}"); _textWriter.WriteLine("else"); _textWriter.WriteLine("{"); _textWriter.Indent++; _textWriter.WriteLine($"{parameter.GetVariableName()} = null;"); _textWriter.Indent--; _textWriter.WriteLine("}"); } /// /// Validates that the string enumerator is currently not at the last token. /// /// The parameter that is being converted. public void ValidateNotLast(string parameterName) { _textWriter.WriteLine($"if ({_stringEnumeratorVariable}.IsOnLastToken() ?? false)"); _textWriter.WriteLine("{"); _textWriter.Indent++; _textWriter.WriteLine($"return new PacketEndNotExpectedError(this, \"{parameterName}\");"); _textWriter.Indent--; _textWriter.WriteLine("}"); } /// /// Call deserializer and check the result. /// /// The parameter. /// The packet. /// The inline converter generator. public void DeserializeAndCheck(ParameterInfo parameter, PacketInfo packet, InlineTypeConverterGenerator inlineTypeConverter) { _textWriter.WriteLine($"var {parameter.GetResultVariableName()} = "); inlineTypeConverter.CallDeserialize(_textWriter, packet); _textWriter.WriteLine($"if (!{parameter.GetResultVariableName()}.IsSuccess)"); _textWriter.Indent++; _textWriter.WriteLine ( $"return Result<{packet.Name}?>.FromError(new PacketParameterSerializerError(this, \"{parameter.Name}\", {parameter.GetResultVariableName()}), {parameter.GetResultVariableName()});" ); _textWriter.Indent--; _textWriter.WriteLine ( $"{parameter.GetNullableType()} {parameter.GetNullableVariableName()} = {parameter.GetResultVariableName()}.Entity;" ); } }