diff --git a/Projects/SerializationGenerator/SerializableEntityGeneration/SerializationEntityGeneration.ContentStruct.cs b/Projects/SerializationGenerator/SerializableEntityGeneration/SerializationEntityGeneration.ContentStruct.cs index 7e664920e..56544ed60 100644 --- a/Projects/SerializationGenerator/SerializableEntityGeneration/SerializationEntityGeneration.ContentStruct.cs +++ b/Projects/SerializationGenerator/SerializableEntityGeneration/SerializationEntityGeneration.ContentStruct.cs @@ -37,12 +37,9 @@ namespace SerializationGenerator foreach (var serializableProperty in properties) { - var propertyType = serializableProperty.Type; - var type = compilation.GetTypeByMetadataName(propertyType)?.IsValueType == true - || SymbolMetadata.IsPrimitiveFromTypeDisplayString(propertyType) && propertyType != "bool" - ? $"{propertyType}{(serializableProperty.UsesSaveFlag == true ? "?" : "")}" : propertyType; - - source.AppendLine($"{indent} internal readonly {type} {serializableProperty.Name};"); + SerializableMigrationRulesEngine.Rules[serializableProperty.Rule].GenerateMigrationProperty( + source, compilation, $"{indent} ", serializableProperty + ); } var innerIndent = $"{indent} "; @@ -100,7 +97,8 @@ namespace SerializationGenerator source, $"{innerIndent} ", property, - "entity" + "entity", + true ); source.AppendLine($"{innerIndent}}}\n{innerIndent}else\n{innerIndent}{{"); @@ -114,7 +112,8 @@ namespace SerializationGenerator source, innerIndent, property, - "entity" + "entity", + true ); } } diff --git a/Projects/SerializationGenerator/SerializableMigration/ISerializableMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/ISerializableMigrationRule.cs index 1f944c4fa..a64453e33 100644 --- a/Projects/SerializationGenerator/SerializableMigration/ISerializableMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/ISerializableMigrationRule.cs @@ -23,6 +23,13 @@ namespace SerializableMigration { string RuleName { get; } + void GenerateMigrationProperty( + StringBuilder source, + Compilation compilation, + string indent, + SerializableProperty serializableProperty + ); + bool GenerateRuleState( Compilation compilation, ISymbol symbol, @@ -37,7 +44,8 @@ namespace SerializableMigration StringBuilder source, string indent, SerializableProperty property, - string? parentReference + string? parentReference, + bool isMigration = false ); void GenerateSerializationMethod( diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/ArrayMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/ArrayMigrationRule.cs index 54b63cc1c..99a1e911e 100644 --- a/Projects/SerializationGenerator/SerializableMigration/Rules/ArrayMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/ArrayMigrationRule.cs @@ -18,117 +18,118 @@ using System.Collections.Immutable; using System.Text; using Microsoft.CodeAnalysis; -namespace SerializableMigration +namespace SerializableMigration; + +public class ArrayMigrationRule : MigrationRule { - public class ArrayMigrationRule : ISerializableMigrationRule + public override string RuleName => nameof(ArrayMigrationRule); + + public override bool GenerateRuleState( + Compilation compilation, + ISymbol symbol, + ImmutableArray attributes, + ImmutableArray serializableTypes, + ImmutableArray embeddedSerializableTypes, + ISymbol? parentSymbol, + out string[] ruleArguments + ) { - public string RuleName => nameof(ArrayMigrationRule); - - public bool GenerateRuleState( - Compilation compilation, - ISymbol symbol, - ImmutableArray attributes, - ImmutableArray serializableTypes, - ImmutableArray embeddedSerializableTypes, - ISymbol? parentSymbol, - out string[] ruleArguments - ) + if (symbol is not IArrayTypeSymbol arrayTypeSymbol) { - if (symbol is not IArrayTypeSymbol arrayTypeSymbol) - { - ruleArguments = null; - return false; - } - - var serializableArrayType = SerializableMigrationRulesEngine.GenerateSerializableProperty( - compilation, - "ArrayEntry", - arrayTypeSymbol.ElementType, - 0, - attributes, - serializableTypes, - embeddedSerializableTypes, - parentSymbol, - null - ); - - var length = serializableArrayType.RuleArguments?.Length?? 0; - ruleArguments = new string[length + 2]; - ruleArguments[0] = arrayTypeSymbol.ElementType.ToDisplayString(); - ruleArguments[1] = serializableArrayType.Rule; - if (length > 0) - { - Array.Copy(serializableArrayType.RuleArguments!, 0, ruleArguments, 2, length); - } - - return true; + ruleArguments = null; + return false; } - public void GenerateDeserializationMethod(StringBuilder source, string indent, SerializableProperty property, string? parentReference) + var serializableArrayType = SerializableMigrationRulesEngine.GenerateSerializableProperty( + compilation, + "ArrayEntry", + arrayTypeSymbol.ElementType, + 0, + attributes, + serializableTypes, + embeddedSerializableTypes, + parentSymbol, + null + ); + + var length = serializableArrayType.RuleArguments?.Length?? 0; + ruleArguments = new string[length + 2]; + ruleArguments[0] = arrayTypeSymbol.ElementType.ToDisplayString(); + ruleArguments[1] = serializableArrayType.Rule; + if (length > 0) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - var ruleArguments = property.RuleArguments; - var arrayElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments![1]]; - var arrayElementRuleArguments = new string[ruleArguments.Length - 2]; - Array.Copy(ruleArguments, 2, arrayElementRuleArguments, 0, ruleArguments.Length - 2); - - var propertyIndex = $"{property.Name}Index"; - source.AppendLine($"{indent}{property.Name} = new {ruleArguments[0]}[reader.ReadEncodedInt()];"); - source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {property.Name}.Length; {propertyIndex}++)"); - source.AppendLine($"{indent}{{"); - - var serializableArrayElement = new SerializableProperty - { - Name = $"{property.Name}[{propertyIndex}]", - Type = ruleArguments[0], - Rule = arrayElementRule.RuleName, - RuleArguments = arrayElementRuleArguments - }; - - arrayElementRule.GenerateDeserializationMethod(source, $"{indent} ", serializableArrayElement, parentReference); - - source.AppendLine($"{indent}}}"); + Array.Copy(serializableArrayType.RuleArguments!, 0, ruleArguments, 2, length); } - public void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + return true; + } + + public override void GenerateDeserializationMethod( + StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false + ) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var ruleArguments = property.RuleArguments; - var arrayElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments![1]]; - var arrayElementRuleArguments = new string[ruleArguments.Length - 2]; - Array.Copy(ruleArguments, 2, arrayElementRuleArguments, 0, ruleArguments.Length - 2); - - var propertyName = property.Name; - var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; - var propertyIndex = $"{propertyVarPrefix}Index"; - var propertyLength = $"{propertyVarPrefix}Length"; - source.AppendLine($"{indent}var {propertyLength} = {property.Name}?.Length ?? 0;"); - source.AppendLine($"{indent}writer.WriteEncodedInt({propertyLength});"); - source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {propertyLength}; {propertyIndex}++)"); - source.AppendLine($"{indent}{{"); - - var serializableArrayElement = new SerializableProperty - { - Name = $"{property.Name}![{propertyIndex}]", - Type = ruleArguments[0], - Rule = arrayElementRule.RuleName, - RuleArguments = arrayElementRuleArguments - }; - - arrayElementRule.GenerateSerializationMethod(source, $"{indent} ", serializableArrayElement); - - source.AppendLine($"{indent}}}"); + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); } + var ruleArguments = property.RuleArguments; + var arrayElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments![1]]; + var arrayElementRuleArguments = new string[ruleArguments.Length - 2]; + Array.Copy(ruleArguments, 2, arrayElementRuleArguments, 0, ruleArguments.Length - 2); + + var propertyIndex = $"{property.Name}Index"; + source.AppendLine($"{indent}{property.Name} = new {ruleArguments[0]}[reader.ReadEncodedInt()];"); + source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {property.Name}.Length; {propertyIndex}++)"); + source.AppendLine($"{indent}{{"); + + var serializableArrayElement = new SerializableProperty + { + Name = $"{property.Name}[{propertyIndex}]", + Type = ruleArguments[0], + Rule = arrayElementRule.RuleName, + RuleArguments = arrayElementRuleArguments + }; + + arrayElementRule.GenerateDeserializationMethod(source, $"{indent} ", serializableArrayElement, parentReference); + + source.AppendLine($"{indent}}}"); + } + + public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); + } + + var ruleArguments = property.RuleArguments; + var arrayElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments![1]]; + var arrayElementRuleArguments = new string[ruleArguments.Length - 2]; + Array.Copy(ruleArguments, 2, arrayElementRuleArguments, 0, ruleArguments.Length - 2); + + var propertyName = property.Name; + var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; + var propertyIndex = $"{propertyVarPrefix}Index"; + var propertyLength = $"{propertyVarPrefix}Length"; + source.AppendLine($"{indent}var {propertyLength} = {property.Name}?.Length ?? 0;"); + source.AppendLine($"{indent}writer.WriteEncodedInt({propertyLength});"); + source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {propertyLength}; {propertyIndex}++)"); + source.AppendLine($"{indent}{{"); + + var serializableArrayElement = new SerializableProperty + { + Name = $"{property.Name}![{propertyIndex}]", + Type = ruleArguments[0], + Rule = arrayElementRule.RuleName, + RuleArguments = arrayElementRuleArguments + }; + + arrayElementRule.GenerateSerializationMethod(source, $"{indent} ", serializableArrayElement); + + source.AppendLine($"{indent}}}"); } } diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/DictionaryMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/DictionaryMigrationRule.cs index 309e4c461..caf0d1dc8 100644 --- a/Projects/SerializationGenerator/SerializableMigration/Rules/DictionaryMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/DictionaryMigrationRule.cs @@ -20,230 +20,231 @@ using System.Text; using Microsoft.CodeAnalysis; using SerializationGenerator; -namespace SerializableMigration +namespace SerializableMigration; + +public class DictionaryMigrationRule : MigrationRule { - public class DictionaryMigrationRule : ISerializableMigrationRule + public override string RuleName => nameof(DictionaryMigrationRule); + + public override bool GenerateRuleState( + Compilation compilation, + ISymbol symbol, + ImmutableArray attributes, + ImmutableArray serializableTypes, + ImmutableArray embeddedSerializableTypes, + ISymbol? parentSymbol, + out string[] ruleArguments + ) { - public string RuleName => nameof(DictionaryMigrationRule); - - public bool GenerateRuleState( - Compilation compilation, - ISymbol symbol, - ImmutableArray attributes, - ImmutableArray serializableTypes, - ImmutableArray embeddedSerializableTypes, - ISymbol? parentSymbol, - out string[] ruleArguments - ) + if (symbol is not INamedTypeSymbol namedTypeSymbol || !symbol.IsDictionary(compilation)) { - if (symbol is not INamedTypeSymbol namedTypeSymbol || !symbol.IsDictionary(compilation)) - { - ruleArguments = null; - return false; - } - - var keySymbolType = namedTypeSymbol.TypeArguments[0]; - - var serializableKeyProperty = SerializableMigrationRulesEngine.GenerateSerializableProperty( - compilation, - "KeyEntry", - keySymbolType, - 0, - attributes, - serializableTypes, - embeddedSerializableTypes, - parentSymbol, - null - ); - - var valueSymbolType = namedTypeSymbol.TypeArguments[1]; - - var serializableValueProperty = SerializableMigrationRulesEngine.GenerateSerializableProperty( - compilation, - "ValueEntry", - valueSymbolType, - 0, - attributes, - serializableTypes, - embeddedSerializableTypes, - parentSymbol, - null - ); - - var extraOptions = ""; - if (attributes.Any(a => a.IsTidy(compilation))) - { - extraOptions += "@Tidy"; - } - - var keyArgumentsLength = serializableKeyProperty.RuleArguments?.Length ?? 0; - var valueArgumentsLength = serializableValueProperty.RuleArguments?.Length ?? 0; - var index = 0; - - ruleArguments = new string[7 + keyArgumentsLength + valueArgumentsLength]; - ruleArguments[index++] = extraOptions; - ruleArguments[index++] = keySymbolType.ToDisplayString(); - ruleArguments[index++] = serializableKeyProperty.Rule; - ruleArguments[index++] = keyArgumentsLength.ToString(); - - if (keyArgumentsLength > 0) - { - Array.Copy(serializableKeyProperty.RuleArguments!, 0, ruleArguments, index, keyArgumentsLength); - index += keyArgumentsLength; - } - - ruleArguments[index++] = valueSymbolType.ToDisplayString(); - ruleArguments[index++] = serializableValueProperty.Rule; - ruleArguments[index++] = valueArgumentsLength.ToString(); - - if (valueArgumentsLength > 0) - { - Array.Copy(serializableValueProperty.RuleArguments!, 0, ruleArguments, index, valueArgumentsLength); - } - - return true; + ruleArguments = null; + return false; } - public void GenerateDeserializationMethod(StringBuilder source, string indent, SerializableProperty property, string? parentReference) + var keySymbolType = namedTypeSymbol.TypeArguments[0]; + + var serializableKeyProperty = SerializableMigrationRulesEngine.GenerateSerializableProperty( + compilation, + "KeyEntry", + keySymbolType, + 0, + attributes, + serializableTypes, + embeddedSerializableTypes, + parentSymbol, + null + ); + + var valueSymbolType = namedTypeSymbol.TypeArguments[1]; + + var serializableValueProperty = SerializableMigrationRulesEngine.GenerateSerializableProperty( + compilation, + "ValueEntry", + valueSymbolType, + 0, + attributes, + serializableTypes, + embeddedSerializableTypes, + parentSymbol, + null + ); + + var extraOptions = ""; + if (attributes.Any(a => a.IsTidy(compilation))) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var ruleArguments = property.RuleArguments; - var index = 1; - var keyType = ruleArguments![index++]; - - var keyElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; - var keyRuleArguments = new string[int.Parse(ruleArguments[index++])]; - - if (keyRuleArguments.Length > 0) - { - Array.Copy(ruleArguments, index, keyRuleArguments, 0, keyRuleArguments.Length); - index += keyRuleArguments.Length; - } - - var valueType = ruleArguments[index++]; - var valueElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; - var valueRuleArguments = new string[int.Parse(ruleArguments[index++])]; - - if (valueRuleArguments.Length > 0) - { - Array.Copy(ruleArguments, index, valueRuleArguments, 0, valueRuleArguments.Length); - } - - var propertyName = property.Name; - var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; - var propertyIndex = $"{propertyVarPrefix}Index"; - var propertyKeyEntry = $"{propertyVarPrefix}Key"; - var propertyValueEntry = $"{propertyVarPrefix}Value"; - var propertyCount = $"{propertyVarPrefix}Count"; - - source.AppendLine($"{indent}{ruleArguments[1]} {propertyKeyEntry};"); - source.AppendLine($"{indent}{valueType} {propertyValueEntry};"); - source.AppendLine($"{indent}var {propertyCount} = reader.ReadEncodedInt();"); - source.AppendLine($"{indent}{propertyName} = new System.Collections.Generic.Dictionary<{keyType}, {valueType}>({propertyCount});"); - source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {propertyCount}; {propertyIndex}++)"); - source.AppendLine($"{indent}{{"); - - var serializableKeyElement = new SerializableProperty - { - Name = propertyKeyEntry, - Type = keyType, - Rule = keyElementRule.RuleName, - RuleArguments = keyRuleArguments - }; - - keyElementRule.GenerateDeserializationMethod(source, $"{indent} ", serializableKeyElement, parentReference); - - var serializableValueElement = new SerializableProperty - { - Name = propertyValueEntry, - Type = valueType, - Rule = valueElementRule.RuleName, - RuleArguments = valueRuleArguments - }; - - valueElementRule.GenerateDeserializationMethod(source, $"{indent} ", serializableValueElement, parentReference); - source.AppendLine($"{indent} {propertyName}.Add({propertyKeyEntry}, {propertyValueEntry});"); - - source.AppendLine($"{indent}}}"); + extraOptions += "@Tidy"; } - public void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + var keyArgumentsLength = serializableKeyProperty.RuleArguments?.Length ?? 0; + var valueArgumentsLength = serializableValueProperty.RuleArguments?.Length ?? 0; + var index = 0; + + ruleArguments = new string[7 + keyArgumentsLength + valueArgumentsLength]; + ruleArguments[index++] = extraOptions; + ruleArguments[index++] = keySymbolType.ToDisplayString(); + ruleArguments[index++] = serializableKeyProperty.Rule; + ruleArguments[index++] = keyArgumentsLength.ToString(); + + if (keyArgumentsLength > 0) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var ruleArguments = property.RuleArguments; - var index = 0; - var shouldTidy = ruleArguments![index++].Contains("@Tidy"); - var keyType = ruleArguments![index++]; - - var keyElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments![index++]]; - var keyRuleArguments = new string[int.Parse(ruleArguments[index++])]; - - if (keyRuleArguments.Length > 0) - { - Array.Copy(ruleArguments, index, keyRuleArguments, 0, keyRuleArguments.Length); - index += keyRuleArguments.Length; - } - - var valueType = ruleArguments[index++]; - var valueElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; - var valueRuleArguments = new string[int.Parse(ruleArguments[index++])]; - - if (valueRuleArguments.Length > 0) - { - Array.Copy(ruleArguments, index, valueRuleArguments, 0, valueRuleArguments.Length); - } - - var propertyName = property.Name; - var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; - var propertyKeyEntry = $"{propertyVarPrefix}Key"; - var propertyValueEntry = $"{propertyVarPrefix}Value"; - var propertyCount = $"{propertyVarPrefix}Count"; - - if (shouldTidy) - { - source.AppendLine($"{indent}{property.Name}?.Tidy();"); - } - source.AppendLine($"{indent}var {propertyCount} = {property.Name}?.Count ?? 0;"); - source.AppendLine($"{indent}writer.WriteEncodedInt({propertyCount});"); - source.AppendLine($"{indent}if ({propertyCount} > 0)"); - source.AppendLine($"{indent}{{"); - source.AppendLine($"{indent} foreach (var ({propertyKeyEntry}, {propertyValueEntry}) in {property.Name}!)"); - source.AppendLine($"{indent} {{"); - - var serializableKeyElement = new SerializableProperty - { - Name = propertyKeyEntry, - Type = keyType, - Rule = keyElementRule.RuleName, - RuleArguments = keyRuleArguments - }; - - keyElementRule.GenerateSerializationMethod(source, $"{indent} ", serializableKeyElement); - - var serializableValueElement = new SerializableProperty - { - Name = propertyValueEntry, - Type = valueType, - Rule = valueElementRule.RuleName, - RuleArguments = valueRuleArguments - }; - - valueElementRule.GenerateSerializationMethod(source, $"{indent} ", serializableValueElement); - - source.AppendLine($"{indent} }}"); - source.AppendLine($"{indent}}}"); + Array.Copy(serializableKeyProperty.RuleArguments!, 0, ruleArguments, index, keyArgumentsLength); + index += keyArgumentsLength; } + + ruleArguments[index++] = valueSymbolType.ToDisplayString(); + ruleArguments[index++] = serializableValueProperty.Rule; + ruleArguments[index++] = valueArgumentsLength.ToString(); + + if (valueArgumentsLength > 0) + { + Array.Copy(serializableValueProperty.RuleArguments!, 0, ruleArguments, index, valueArgumentsLength); + } + + return true; + } + + public override void GenerateDeserializationMethod( + StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false + ) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); + } + + var ruleArguments = property.RuleArguments; + var index = 1; + var keyType = ruleArguments![index++]; + + var keyElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; + var keyRuleArguments = new string[int.Parse(ruleArguments[index++])]; + + if (keyRuleArguments.Length > 0) + { + Array.Copy(ruleArguments, index, keyRuleArguments, 0, keyRuleArguments.Length); + index += keyRuleArguments.Length; + } + + var valueType = ruleArguments[index++]; + var valueElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; + var valueRuleArguments = new string[int.Parse(ruleArguments[index++])]; + + if (valueRuleArguments.Length > 0) + { + Array.Copy(ruleArguments, index, valueRuleArguments, 0, valueRuleArguments.Length); + } + + var propertyName = property.Name; + var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; + var propertyIndex = $"{propertyVarPrefix}Index"; + var propertyKeyEntry = $"{propertyVarPrefix}Key"; + var propertyValueEntry = $"{propertyVarPrefix}Value"; + var propertyCount = $"{propertyVarPrefix}Count"; + + source.AppendLine($"{indent}{ruleArguments[1]} {propertyKeyEntry};"); + source.AppendLine($"{indent}{valueType} {propertyValueEntry};"); + source.AppendLine($"{indent}var {propertyCount} = reader.ReadEncodedInt();"); + source.AppendLine($"{indent}{propertyName} = new System.Collections.Generic.Dictionary<{keyType}, {valueType}>({propertyCount});"); + source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {propertyCount}; {propertyIndex}++)"); + source.AppendLine($"{indent}{{"); + + var serializableKeyElement = new SerializableProperty + { + Name = propertyKeyEntry, + Type = keyType, + Rule = keyElementRule.RuleName, + RuleArguments = keyRuleArguments + }; + + keyElementRule.GenerateDeserializationMethod(source, $"{indent} ", serializableKeyElement, parentReference); + + var serializableValueElement = new SerializableProperty + { + Name = propertyValueEntry, + Type = valueType, + Rule = valueElementRule.RuleName, + RuleArguments = valueRuleArguments + }; + + valueElementRule.GenerateDeserializationMethod(source, $"{indent} ", serializableValueElement, parentReference); + source.AppendLine($"{indent} {propertyName}.Add({propertyKeyEntry}, {propertyValueEntry});"); + + source.AppendLine($"{indent}}}"); + } + + public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); + } + + var ruleArguments = property.RuleArguments; + var index = 0; + var shouldTidy = ruleArguments![index++].Contains("@Tidy"); + var keyType = ruleArguments![index++]; + + var keyElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments![index++]]; + var keyRuleArguments = new string[int.Parse(ruleArguments[index++])]; + + if (keyRuleArguments.Length > 0) + { + Array.Copy(ruleArguments, index, keyRuleArguments, 0, keyRuleArguments.Length); + index += keyRuleArguments.Length; + } + + var valueType = ruleArguments[index++]; + var valueElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; + var valueRuleArguments = new string[int.Parse(ruleArguments[index++])]; + + if (valueRuleArguments.Length > 0) + { + Array.Copy(ruleArguments, index, valueRuleArguments, 0, valueRuleArguments.Length); + } + + var propertyName = property.Name; + var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; + var propertyKeyEntry = $"{propertyVarPrefix}Key"; + var propertyValueEntry = $"{propertyVarPrefix}Value"; + var propertyCount = $"{propertyVarPrefix}Count"; + + if (shouldTidy) + { + source.AppendLine($"{indent}{property.Name}?.Tidy();"); + } + source.AppendLine($"{indent}var {propertyCount} = {property.Name}?.Count ?? 0;"); + source.AppendLine($"{indent}writer.WriteEncodedInt({propertyCount});"); + source.AppendLine($"{indent}if ({propertyCount} > 0)"); + source.AppendLine($"{indent}{{"); + source.AppendLine($"{indent} foreach (var ({propertyKeyEntry}, {propertyValueEntry}) in {property.Name}!)"); + source.AppendLine($"{indent} {{"); + + var serializableKeyElement = new SerializableProperty + { + Name = propertyKeyEntry, + Type = keyType, + Rule = keyElementRule.RuleName, + RuleArguments = keyRuleArguments + }; + + keyElementRule.GenerateSerializationMethod(source, $"{indent} ", serializableKeyElement); + + var serializableValueElement = new SerializableProperty + { + Name = propertyValueEntry, + Type = valueType, + Rule = valueElementRule.RuleName, + RuleArguments = valueRuleArguments + }; + + valueElementRule.GenerateSerializationMethod(source, $"{indent} ", serializableValueElement); + + source.AppendLine($"{indent} }}"); + source.AppendLine($"{indent}}}"); } } diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/EnumMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/EnumMigrationRule.cs index 18ebc3678..5e8d7fd45 100644 --- a/Projects/SerializationGenerator/SerializableMigration/Rules/EnumMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/EnumMigrationRule.cs @@ -19,54 +19,55 @@ using System.Text; using Microsoft.CodeAnalysis; using SerializationGenerator; -namespace SerializableMigration +namespace SerializableMigration; + +public class EnumMigrationRule : MigrationRule { - public class EnumMigrationRule : ISerializableMigrationRule + public override string RuleName => nameof(EnumMigrationRule); + + public override bool GenerateRuleState( + Compilation compilation, + ISymbol symbol, + ImmutableArray attributes, + ImmutableArray serializableTypes, + ImmutableArray embeddedSerializableTypes, + ISymbol? parentSymbol, + out string[] ruleArguments + ) { - public string RuleName => nameof(EnumMigrationRule); - - public bool GenerateRuleState( - Compilation compilation, - ISymbol symbol, - ImmutableArray attributes, - ImmutableArray serializableTypes, - ImmutableArray embeddedSerializableTypes, - ISymbol? parentSymbol, - out string[] ruleArguments - ) + if (symbol is not ITypeSymbol typeSymbol || !typeSymbol.IsEnum()) { - if (symbol is not ITypeSymbol typeSymbol || !typeSymbol.IsEnum()) - { - ruleArguments = null; - return false; - } - - ruleArguments = Array.Empty(); - return true; + ruleArguments = null; + return false; } - public void GenerateDeserializationMethod(StringBuilder source, string indent, SerializableProperty property, string? parentReference) - { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } + ruleArguments = Array.Empty(); + return true; + } - source.AppendLine($"{indent}{property.Name} = reader.ReadEnum<{property.Type}>();"); + public override void GenerateDeserializationMethod( + StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false + ) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); } - public void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) - { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } + source.AppendLine($"{indent}{property.Name} = reader.ReadEnum<{property.Type}>();"); + } - source.AppendLine($"{indent}writer.WriteEnum<{property.Type}>({property.Name});"); + public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); } + + source.AppendLine($"{indent}writer.WriteEnum<{property.Type}>({property.Name});"); } } diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/HashSetMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/HashSetMigrationRule.cs index d670ae01f..20fe03d08 100644 --- a/Projects/SerializationGenerator/SerializableMigration/Rules/HashSetMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/HashSetMigrationRule.cs @@ -20,151 +20,152 @@ using System.Text; using Microsoft.CodeAnalysis; using SerializationGenerator; -namespace SerializableMigration +namespace SerializableMigration; + +public class HashSetMigrationRule : MigrationRule { - public class HashSetMigrationRule : ISerializableMigrationRule + public override string RuleName => nameof(HashSetMigrationRule); + + public override bool GenerateRuleState( + Compilation compilation, + ISymbol symbol, + ImmutableArray attributes, + ImmutableArray serializableTypes, + ImmutableArray embeddedSerializableTypes, + ISymbol? parentSymbol, + out string[] ruleArguments + ) { - public string RuleName => nameof(HashSetMigrationRule); - - public bool GenerateRuleState( - Compilation compilation, - ISymbol symbol, - ImmutableArray attributes, - ImmutableArray serializableTypes, - ImmutableArray embeddedSerializableTypes, - ISymbol? parentSymbol, - out string[] ruleArguments - ) + if (symbol is not INamedTypeSymbol namedTypeSymbol || !symbol.IsHashSet(compilation)) { - if (symbol is not INamedTypeSymbol namedTypeSymbol || !symbol.IsHashSet(compilation)) - { - ruleArguments = null; - return false; - } - - var setTypeSymbol = namedTypeSymbol.TypeArguments[0]; - - var serializableSetType = SerializableMigrationRulesEngine.GenerateSerializableProperty( - compilation, - "SetEntry", - setTypeSymbol, - 0, - attributes, - serializableTypes, - embeddedSerializableTypes, - parentSymbol, - null - ); - - var extraOptions = ""; - if (attributes.Any(a => a.IsTidy(compilation))) - { - extraOptions += "@Tidy"; - } - - var length = serializableSetType.RuleArguments?.Length ?? 0; - ruleArguments = new string[length + 3]; - ruleArguments[0] = extraOptions; - ruleArguments[1] = setTypeSymbol.ToDisplayString(); - ruleArguments[2] = serializableSetType.Rule; - - if (length > 0) - { - Array.Copy(serializableSetType.RuleArguments, 0, ruleArguments, 3, length); - } - - return true; + ruleArguments = null; + return false; } - public void GenerateDeserializationMethod(StringBuilder source, string indent, SerializableProperty property, string? parentReference) + var setTypeSymbol = namedTypeSymbol.TypeArguments[0]; + + var serializableSetType = SerializableMigrationRulesEngine.GenerateSerializableProperty( + compilation, + "SetEntry", + setTypeSymbol, + 0, + attributes, + serializableTypes, + embeddedSerializableTypes, + parentSymbol, + null + ); + + var extraOptions = ""; + if (attributes.Any(a => a.IsTidy(compilation))) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var ruleArguments = property.RuleArguments; - var hasExtraOptions = ruleArguments![0] == "" || ruleArguments[0].StartsWith("@", StringComparison.Ordinal); - var argumentsOffset = hasExtraOptions ? 1 : 0; - - var setElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[1 + argumentsOffset]]; - var setElementRuleArguments = new string[ruleArguments.Length - 2 - argumentsOffset]; - Array.Copy(ruleArguments, 2 + argumentsOffset, setElementRuleArguments, 0, ruleArguments.Length - 2 - argumentsOffset); - - var propertyName = property.Name; - var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; - var propertyIndex = $"{propertyVarPrefix}Index"; - var propertyEntry = $"{propertyVarPrefix}Entry"; - var propertyCount = $"{propertyVarPrefix}Count"; - - source.AppendLine($"{indent}{ruleArguments[argumentsOffset]} {propertyEntry};"); - source.AppendLine($"{indent}var {propertyCount} = reader.ReadEncodedInt();"); - source.AppendLine($"{indent}{property.Name} = new System.Collections.Generic.HashSet<{ruleArguments[argumentsOffset]}>({propertyCount});"); - source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {propertyCount}; {propertyIndex}++)"); - source.AppendLine($"{indent}{{"); - - var serializableSetElement = new SerializableProperty - { - Name = propertyEntry, - Type = ruleArguments[argumentsOffset], - Rule = setElementRule.RuleName, - RuleArguments = setElementRuleArguments - }; - - setElementRule.GenerateDeserializationMethod(source, $"{indent} ", serializableSetElement, parentReference); - source.AppendLine($"{indent} {property.Name}.Add({propertyEntry});"); - - source.AppendLine($"{indent}}}"); + extraOptions += "@Tidy"; } - public void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + var length = serializableSetType.RuleArguments?.Length ?? 0; + ruleArguments = new string[length + 3]; + ruleArguments[0] = extraOptions; + ruleArguments[1] = setTypeSymbol.ToDisplayString(); + ruleArguments[2] = serializableSetType.Rule; + + if (length > 0) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var ruleArguments = property.RuleArguments; - var hasExtraOptions = ruleArguments![0] == "" || ruleArguments[0].StartsWith("@", StringComparison.Ordinal); - var shouldTidy = hasExtraOptions && ruleArguments[0].Contains("@Tidy"); - var argumentsOffset = hasExtraOptions ? 1 : 0; - - var setElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[1 + argumentsOffset]]; - var setElementRuleArguments = new string[ruleArguments.Length - 2 - argumentsOffset]; - Array.Copy(ruleArguments, 2 + argumentsOffset, setElementRuleArguments, 0, ruleArguments.Length - 2 - argumentsOffset); - - var propertyName = property.Name; - var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; - var propertyEntry = $"{propertyVarPrefix}Entry"; - var propertyCount = $"{propertyVarPrefix}Count"; - - if (shouldTidy) - { - source.AppendLine($"{indent}{property.Name}?.Tidy();"); - } - source.AppendLine($"{indent}var {propertyCount} = {property.Name}?.Count ?? 0;"); - source.AppendLine($"{indent}writer.WriteEncodedInt({propertyCount});"); - source.AppendLine($"{indent}if ({propertyCount} > 0)"); - source.AppendLine($"{indent}{{"); - source.AppendLine($"{indent} foreach (var {propertyEntry} in {property.Name}!)"); - source.AppendLine($"{indent} {{"); - - var serializableSetElement = new SerializableProperty - { - Name = propertyEntry, - Type = ruleArguments[argumentsOffset], - Rule = setElementRule.RuleName, - RuleArguments = setElementRuleArguments - }; - - setElementRule.GenerateSerializationMethod(source, $"{indent} ", serializableSetElement); - - source.AppendLine($"{indent} }}"); - source.AppendLine($"{indent}}}"); + Array.Copy(serializableSetType.RuleArguments, 0, ruleArguments, 3, length); } + + return true; + } + + public override void GenerateDeserializationMethod( + StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false + ) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); + } + + var ruleArguments = property.RuleArguments; + var hasExtraOptions = ruleArguments![0] == "" || ruleArguments[0].StartsWith("@", StringComparison.Ordinal); + var argumentsOffset = hasExtraOptions ? 1 : 0; + + var setElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[1 + argumentsOffset]]; + var setElementRuleArguments = new string[ruleArguments.Length - 2 - argumentsOffset]; + Array.Copy(ruleArguments, 2 + argumentsOffset, setElementRuleArguments, 0, ruleArguments.Length - 2 - argumentsOffset); + + var propertyName = property.Name; + var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; + var propertyIndex = $"{propertyVarPrefix}Index"; + var propertyEntry = $"{propertyVarPrefix}Entry"; + var propertyCount = $"{propertyVarPrefix}Count"; + + source.AppendLine($"{indent}{ruleArguments[argumentsOffset]} {propertyEntry};"); + source.AppendLine($"{indent}var {propertyCount} = reader.ReadEncodedInt();"); + source.AppendLine($"{indent}{property.Name} = new System.Collections.Generic.HashSet<{ruleArguments[argumentsOffset]}>({propertyCount});"); + source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {propertyCount}; {propertyIndex}++)"); + source.AppendLine($"{indent}{{"); + + var serializableSetElement = new SerializableProperty + { + Name = propertyEntry, + Type = ruleArguments[argumentsOffset], + Rule = setElementRule.RuleName, + RuleArguments = setElementRuleArguments + }; + + setElementRule.GenerateDeserializationMethod(source, $"{indent} ", serializableSetElement, parentReference); + source.AppendLine($"{indent} {property.Name}.Add({propertyEntry});"); + + source.AppendLine($"{indent}}}"); + } + + public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); + } + + var ruleArguments = property.RuleArguments; + var hasExtraOptions = ruleArguments![0] == "" || ruleArguments[0].StartsWith("@", StringComparison.Ordinal); + var shouldTidy = hasExtraOptions && ruleArguments[0].Contains("@Tidy"); + var argumentsOffset = hasExtraOptions ? 1 : 0; + + var setElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[1 + argumentsOffset]]; + var setElementRuleArguments = new string[ruleArguments.Length - 2 - argumentsOffset]; + Array.Copy(ruleArguments, 2 + argumentsOffset, setElementRuleArguments, 0, ruleArguments.Length - 2 - argumentsOffset); + + var propertyName = property.Name; + var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; + var propertyEntry = $"{propertyVarPrefix}Entry"; + var propertyCount = $"{propertyVarPrefix}Count"; + + if (shouldTidy) + { + source.AppendLine($"{indent}{property.Name}?.Tidy();"); + } + source.AppendLine($"{indent}var {propertyCount} = {property.Name}?.Count ?? 0;"); + source.AppendLine($"{indent}writer.WriteEncodedInt({propertyCount});"); + source.AppendLine($"{indent}if ({propertyCount} > 0)"); + source.AppendLine($"{indent}{{"); + source.AppendLine($"{indent} foreach (var {propertyEntry} in {property.Name}!)"); + source.AppendLine($"{indent} {{"); + + var serializableSetElement = new SerializableProperty + { + Name = propertyEntry, + Type = ruleArguments[argumentsOffset], + Rule = setElementRule.RuleName, + RuleArguments = setElementRuleArguments + }; + + setElementRule.GenerateSerializationMethod(source, $"{indent} ", serializableSetElement); + + source.AppendLine($"{indent} }}"); + source.AppendLine($"{indent}}}"); } } diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/KeyValuePairMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/KeyValuePairMigrationRule.cs index 1797764c1..5b7c4fbef 100644 --- a/Projects/SerializationGenerator/SerializableMigration/Rules/KeyValuePairMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/KeyValuePairMigrationRule.cs @@ -19,206 +19,207 @@ using System.Text; using Microsoft.CodeAnalysis; using SerializationGenerator; -namespace SerializableMigration +namespace SerializableMigration; + +public class KeyValuePairMigrationRule : MigrationRule { - public class KeyValuePairMigrationRule : ISerializableMigrationRule + public override string RuleName => nameof(KeyValuePairMigrationRule); + + public override bool GenerateRuleState( + Compilation compilation, + ISymbol symbol, + ImmutableArray attributes, + ImmutableArray serializableTypes, + ImmutableArray embeddedSerializableTypes, + ISymbol? parentSymbol, + out string[] ruleArguments + ) { - public string RuleName => nameof(KeyValuePairMigrationRule); - - public bool GenerateRuleState( - Compilation compilation, - ISymbol symbol, - ImmutableArray attributes, - ImmutableArray serializableTypes, - ImmutableArray embeddedSerializableTypes, - ISymbol? parentSymbol, - out string[] ruleArguments - ) + if (symbol is not INamedTypeSymbol namedTypeSymbol || !symbol.IsKeyValuePair(compilation)) { - if (symbol is not INamedTypeSymbol namedTypeSymbol || !symbol.IsKeyValuePair(compilation)) - { - ruleArguments = null; - return false; - } - - var keySymbolType = namedTypeSymbol.TypeArguments[0]; - - var keySerializedProperty = SerializableMigrationRulesEngine.GenerateSerializableProperty( - compilation, - "key", - keySymbolType, - 0, - attributes, - serializableTypes, - embeddedSerializableTypes, - parentSymbol, - null - ); - - var valueSymbolType = namedTypeSymbol.TypeArguments[1]; - - var valueSerializedProperty = SerializableMigrationRulesEngine.GenerateSerializableProperty( - compilation, - "value", - valueSymbolType, - 1, - attributes, - serializableTypes, - embeddedSerializableTypes, - parentSymbol, - null - ); - - var keyArgumentsLength = keySerializedProperty.RuleArguments?.Length ?? 0; - var valueArgumentsLength = valueSerializedProperty.RuleArguments?.Length ?? 0; - var index = 0; - - // Key - ruleArguments = new string[6 + keyArgumentsLength + valueArgumentsLength]; - ruleArguments[index++] = ""; // Extra options - ruleArguments[index++] = keySymbolType.ToDisplayString(); - ruleArguments[index++] = keySerializedProperty.Rule; - ruleArguments[index++] = keyArgumentsLength.ToString(); - if (keyArgumentsLength > 0) - { - Array.Copy(keySerializedProperty.RuleArguments!, 0, ruleArguments, index, keyArgumentsLength); - index += keyArgumentsLength; - } - - // Value - ruleArguments[index++] = valueSymbolType.ToDisplayString(); - ruleArguments[index++] = valueSerializedProperty.Rule; - - if (valueArgumentsLength > 0) - { - Array.Copy(valueSerializedProperty.RuleArguments!, 0, ruleArguments, index, valueArgumentsLength); - } - - return true; + ruleArguments = null; + return false; } - public void GenerateDeserializationMethod(StringBuilder source, string indent, SerializableProperty property, string? parentReference) + var keySymbolType = namedTypeSymbol.TypeArguments[0]; + + var keySerializedProperty = SerializableMigrationRulesEngine.GenerateSerializableProperty( + compilation, + "key", + keySymbolType, + 0, + attributes, + serializableTypes, + embeddedSerializableTypes, + parentSymbol, + null + ); + + var valueSymbolType = namedTypeSymbol.TypeArguments[1]; + + var valueSerializedProperty = SerializableMigrationRulesEngine.GenerateSerializableProperty( + compilation, + "value", + valueSymbolType, + 1, + attributes, + serializableTypes, + embeddedSerializableTypes, + parentSymbol, + null + ); + + var keyArgumentsLength = keySerializedProperty.RuleArguments?.Length ?? 0; + var valueArgumentsLength = valueSerializedProperty.RuleArguments?.Length ?? 0; + var index = 0; + + // Key + ruleArguments = new string[6 + keyArgumentsLength + valueArgumentsLength]; + ruleArguments[index++] = ""; // Extra options + ruleArguments[index++] = keySymbolType.ToDisplayString(); + ruleArguments[index++] = keySerializedProperty.Rule; + ruleArguments[index++] = keyArgumentsLength.ToString(); + if (keyArgumentsLength > 0) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var ruleArguments = property.RuleArguments; - var index = 1; // skip extra options - var keyType = ruleArguments![index++]; - var keyRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; - var keyRuleArguments = new string[int.Parse(ruleArguments[index++])]; - - if (keyRuleArguments.Length > 0) - { - Array.Copy(ruleArguments, index, keyRuleArguments, 0, keyRuleArguments.Length); - index += keyRuleArguments.Length; - } - - var serializableKeyProperty = new SerializableProperty - { - Name = "key", - Type = keyType, - Rule = keyRule.RuleName, - RuleArguments = keyRuleArguments - }; - - keyRule.GenerateDeserializationMethod( - source, - indent, - serializableKeyProperty, - parentReference - ); - - var valueType = ruleArguments[index++]; - var valueRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; - var valueRuleArguments = new string[int.Parse(ruleArguments[index++])]; - - if (valueRuleArguments.Length > 0) - { - Array.Copy(ruleArguments, index, valueRuleArguments, 0, valueRuleArguments.Length); - } - - var serializableValueProperty = new SerializableProperty - { - Name = "value", - Type = valueType, - Rule = valueRule.RuleName, - RuleArguments = valueRuleArguments - }; - - valueRule.GenerateDeserializationMethod( - source, - indent, - serializableValueProperty, - parentReference - ); - - source.AppendLine( - $"{indent}{property.Name} = new {SymbolMetadata.KEYVALUEPAIR_STRUCT}<{keyType}, {valueType}>(key, value);" - ); + Array.Copy(keySerializedProperty.RuleArguments!, 0, ruleArguments, index, keyArgumentsLength); + index += keyArgumentsLength; } - public void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + // Value + ruleArguments[index++] = valueSymbolType.ToDisplayString(); + ruleArguments[index++] = valueSerializedProperty.Rule; + + if (valueArgumentsLength > 0) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var ruleArguments = property.RuleArguments; - var index = 1; // skip extra options - var keyType = ruleArguments![index++]; - var keyRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; - var keyRuleArguments = new string[int.Parse(ruleArguments[index++])]; - - if (keyRuleArguments.Length > 0) - { - Array.Copy(ruleArguments, index, keyRuleArguments, 0, keyRuleArguments.Length); - index += keyRuleArguments.Length; - } - - var serializableKeyProperty = new SerializableProperty - { - Name = $"{property.Name}.Key", - Type = keyType, - Rule = keyRule.RuleName, - RuleArguments = keyRuleArguments - }; - - keyRule.GenerateSerializationMethod( - source, - indent, - serializableKeyProperty - ); - - var valueType = ruleArguments[index++]; - var valueRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; - var valueRuleArguments = new string[int.Parse(ruleArguments[index++])]; - - if (valueRuleArguments.Length > 0) - { - Array.Copy(ruleArguments, index, valueRuleArguments, 0, valueRuleArguments.Length); - } - - var serializableValueProperty = new SerializableProperty - { - Name = $"{property.Name}.Value", - Type = valueType, - Rule = valueRule.RuleName, - RuleArguments = valueRuleArguments - }; - - valueRule.GenerateSerializationMethod( - source, - indent, - serializableValueProperty - ); + Array.Copy(valueSerializedProperty.RuleArguments!, 0, ruleArguments, index, valueArgumentsLength); } + + return true; + } + + public override void GenerateDeserializationMethod( + StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false + ) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); + } + + var ruleArguments = property.RuleArguments; + var index = 1; // skip extra options + var keyType = ruleArguments![index++]; + var keyRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; + var keyRuleArguments = new string[int.Parse(ruleArguments[index++])]; + + if (keyRuleArguments.Length > 0) + { + Array.Copy(ruleArguments, index, keyRuleArguments, 0, keyRuleArguments.Length); + index += keyRuleArguments.Length; + } + + var serializableKeyProperty = new SerializableProperty + { + Name = "key", + Type = keyType, + Rule = keyRule.RuleName, + RuleArguments = keyRuleArguments + }; + + keyRule.GenerateDeserializationMethod( + source, + indent, + serializableKeyProperty, + parentReference + ); + + var valueType = ruleArguments[index++]; + var valueRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; + var valueRuleArguments = new string[int.Parse(ruleArguments[index++])]; + + if (valueRuleArguments.Length > 0) + { + Array.Copy(ruleArguments, index, valueRuleArguments, 0, valueRuleArguments.Length); + } + + var serializableValueProperty = new SerializableProperty + { + Name = "value", + Type = valueType, + Rule = valueRule.RuleName, + RuleArguments = valueRuleArguments + }; + + valueRule.GenerateDeserializationMethod( + source, + indent, + serializableValueProperty, + parentReference + ); + + source.AppendLine( + $"{indent}{property.Name} = new {SymbolMetadata.KEYVALUEPAIR_STRUCT}<{keyType}, {valueType}>(key, value);" + ); + } + + public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); + } + + var ruleArguments = property.RuleArguments; + var index = 1; // skip extra options + var keyType = ruleArguments![index++]; + var keyRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; + var keyRuleArguments = new string[int.Parse(ruleArguments[index++])]; + + if (keyRuleArguments.Length > 0) + { + Array.Copy(ruleArguments, index, keyRuleArguments, 0, keyRuleArguments.Length); + index += keyRuleArguments.Length; + } + + var serializableKeyProperty = new SerializableProperty + { + Name = $"{property.Name}.Key", + Type = keyType, + Rule = keyRule.RuleName, + RuleArguments = keyRuleArguments + }; + + keyRule.GenerateSerializationMethod( + source, + indent, + serializableKeyProperty + ); + + var valueType = ruleArguments[index++]; + var valueRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; + var valueRuleArguments = new string[int.Parse(ruleArguments[index++])]; + + if (valueRuleArguments.Length > 0) + { + Array.Copy(ruleArguments, index, valueRuleArguments, 0, valueRuleArguments.Length); + } + + var serializableValueProperty = new SerializableProperty + { + Name = $"{property.Name}.Value", + Type = valueType, + Rule = valueRule.RuleName, + RuleArguments = valueRuleArguments + }; + + valueRule.GenerateSerializationMethod( + source, + indent, + serializableValueProperty + ); } } diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/ListMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/ListMigrationRule.cs index f11e3f369..53d2d2c44 100644 --- a/Projects/SerializationGenerator/SerializableMigration/Rules/ListMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/ListMigrationRule.cs @@ -20,152 +20,153 @@ using System.Text; using Microsoft.CodeAnalysis; using SerializationGenerator; -namespace SerializableMigration +namespace SerializableMigration; + +public class ListMigrationRule : MigrationRule { - public class ListMigrationRule : ISerializableMigrationRule + public override string RuleName => nameof(ListMigrationRule); + + public override bool GenerateRuleState( + Compilation compilation, + ISymbol symbol, + ImmutableArray attributes, + ImmutableArray serializableTypes, + ImmutableArray embeddedSerializableTypes, + ISymbol? parentSymbol, + out string[] ruleArguments + ) { - public string RuleName => nameof(ListMigrationRule); - - public bool GenerateRuleState( - Compilation compilation, - ISymbol symbol, - ImmutableArray attributes, - ImmutableArray serializableTypes, - ImmutableArray embeddedSerializableTypes, - ISymbol? parentSymbol, - out string[] ruleArguments - ) + if (symbol is not INamedTypeSymbol namedTypeSymbol || !symbol.IsList(compilation)) { - if (symbol is not INamedTypeSymbol namedTypeSymbol || !symbol.IsList(compilation)) - { - ruleArguments = null; - return false; - } - - var listTypeSymbol = namedTypeSymbol.TypeArguments[0]; - - var serializableListType = SerializableMigrationRulesEngine.GenerateSerializableProperty( - compilation, - "ListEntry", - listTypeSymbol, - 0, - attributes, - serializableTypes, - embeddedSerializableTypes, - parentSymbol, - null - ); - - var extraOptions = ""; - if (attributes.Any(a => a.IsTidy(compilation))) - { - extraOptions += "@Tidy"; - } - - var length = serializableListType.RuleArguments?.Length ?? 0; - ruleArguments = new string[length + 3]; - ruleArguments[0] = extraOptions; - ruleArguments[1] = listTypeSymbol.ToDisplayString(); - ruleArguments[2] = serializableListType.Rule; - - if (length > 0) - { - Array.Copy(serializableListType.RuleArguments!, 0, ruleArguments, 3, length); - } - - return true; + ruleArguments = null; + return false; } - public void GenerateDeserializationMethod(StringBuilder source, string indent, SerializableProperty property, string? parentReference) + var listTypeSymbol = namedTypeSymbol.TypeArguments[0]; + + var serializableListType = SerializableMigrationRulesEngine.GenerateSerializableProperty( + compilation, + "ListEntry", + listTypeSymbol, + 0, + attributes, + serializableTypes, + embeddedSerializableTypes, + parentSymbol, + null + ); + + var extraOptions = ""; + if (attributes.Any(a => a.IsTidy(compilation))) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var ruleArguments = property.RuleArguments; - var hasExtraOptions = ruleArguments![0] == "" || ruleArguments[0].StartsWith("@", StringComparison.Ordinal); - var argumentsOffset = hasExtraOptions ? 1 : 0; - - var listElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[argumentsOffset + 1]]; - - var listElementRuleArguments = new string[ruleArguments.Length - 2 - argumentsOffset]; - Array.Copy(ruleArguments, 2 + argumentsOffset, listElementRuleArguments, 0, ruleArguments.Length - 2 - argumentsOffset); - - var propertyName = property.Name; - var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; - var propertyIndex = $"{propertyVarPrefix}Index"; - var propertyEntry = $"{propertyVarPrefix}Entry"; - var propertyCount = $"{propertyVarPrefix}Count"; - - source.AppendLine($"{indent}{ruleArguments[argumentsOffset]} {propertyEntry};"); - source.AppendLine($"{indent}var {propertyCount} = reader.ReadEncodedInt();"); - source.AppendLine($"{indent}{propertyName} = new System.Collections.Generic.List<{ruleArguments[argumentsOffset]}>({propertyCount});"); - source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {propertyCount}; {propertyIndex}++)"); - source.AppendLine($"{indent}{{"); - - var serializableListElement = new SerializableProperty - { - Name = propertyEntry, - Type = ruleArguments[argumentsOffset], - Rule = listElementRule.RuleName, - RuleArguments = listElementRuleArguments - }; - - listElementRule.GenerateDeserializationMethod(source, $"{indent} ", serializableListElement, parentReference); - source.AppendLine($"{indent} {propertyName}.Add({propertyEntry});"); - - source.AppendLine($"{indent}}}"); + extraOptions += "@Tidy"; } - public void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + var length = serializableListType.RuleArguments?.Length ?? 0; + ruleArguments = new string[length + 3]; + ruleArguments[0] = extraOptions; + ruleArguments[1] = listTypeSymbol.ToDisplayString(); + ruleArguments[2] = serializableListType.Rule; + + if (length > 0) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var ruleArguments = property.RuleArguments; - var hasExtraOptions = ruleArguments![0] == "" || ruleArguments[0].StartsWith("@", StringComparison.Ordinal); - var shouldTidy = hasExtraOptions && ruleArguments[0].Contains("@Tidy"); - var argumentsOffset = hasExtraOptions ? 1 : 0; - - var listElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[1 + argumentsOffset]]; - var listElementRuleArguments = new string[ruleArguments.Length - 2 - argumentsOffset]; - Array.Copy(ruleArguments, 2 + argumentsOffset, listElementRuleArguments, 0, ruleArguments.Length - 2 - argumentsOffset); - - var propertyName = property.Name; - var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; - var propertyEntry = $"{propertyVarPrefix}Entry"; - var propertyCount = $"{propertyVarPrefix}Count"; - - if (shouldTidy) - { - source.AppendLine($"{indent}{property.Name}?.Tidy();"); - } - source.AppendLine($"{indent}var {propertyCount} = {property.Name}?.Count ?? 0;"); - source.AppendLine($"{indent}writer.WriteEncodedInt({propertyCount});"); - source.AppendLine($"{indent}if ({propertyCount} > 0)"); - source.AppendLine($"{indent}{{"); - source.AppendLine($"{indent} foreach (var {propertyEntry} in {property.Name}!)"); - source.AppendLine($"{indent} {{"); - - var serializableListElement = new SerializableProperty - { - Name = propertyEntry, - Type = ruleArguments[argumentsOffset], - Rule = listElementRule.RuleName, - RuleArguments = listElementRuleArguments - }; - - listElementRule.GenerateSerializationMethod(source, $"{indent} ", serializableListElement); - - source.AppendLine($"{indent} }}"); - source.AppendLine($"{indent}}}"); + Array.Copy(serializableListType.RuleArguments!, 0, ruleArguments, 3, length); } + + return true; + } + + public override void GenerateDeserializationMethod( + StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false + ) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); + } + + var ruleArguments = property.RuleArguments; + var hasExtraOptions = ruleArguments![0] == "" || ruleArguments[0].StartsWith("@", StringComparison.Ordinal); + var argumentsOffset = hasExtraOptions ? 1 : 0; + + var listElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[argumentsOffset + 1]]; + + var listElementRuleArguments = new string[ruleArguments.Length - 2 - argumentsOffset]; + Array.Copy(ruleArguments, 2 + argumentsOffset, listElementRuleArguments, 0, ruleArguments.Length - 2 - argumentsOffset); + + var propertyName = property.Name; + var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; + var propertyIndex = $"{propertyVarPrefix}Index"; + var propertyEntry = $"{propertyVarPrefix}Entry"; + var propertyCount = $"{propertyVarPrefix}Count"; + + source.AppendLine($"{indent}{ruleArguments[argumentsOffset]} {propertyEntry};"); + source.AppendLine($"{indent}var {propertyCount} = reader.ReadEncodedInt();"); + source.AppendLine($"{indent}{propertyName} = new System.Collections.Generic.List<{ruleArguments[argumentsOffset]}>({propertyCount});"); + source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {propertyCount}; {propertyIndex}++)"); + source.AppendLine($"{indent}{{"); + + var serializableListElement = new SerializableProperty + { + Name = propertyEntry, + Type = ruleArguments[argumentsOffset], + Rule = listElementRule.RuleName, + RuleArguments = listElementRuleArguments + }; + + listElementRule.GenerateDeserializationMethod(source, $"{indent} ", serializableListElement, parentReference); + source.AppendLine($"{indent} {propertyName}.Add({propertyEntry});"); + + source.AppendLine($"{indent}}}"); + } + + public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); + } + + var ruleArguments = property.RuleArguments; + var hasExtraOptions = ruleArguments![0] == "" || ruleArguments[0].StartsWith("@", StringComparison.Ordinal); + var shouldTidy = hasExtraOptions && ruleArguments[0].Contains("@Tidy"); + var argumentsOffset = hasExtraOptions ? 1 : 0; + + var listElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[1 + argumentsOffset]]; + var listElementRuleArguments = new string[ruleArguments.Length - 2 - argumentsOffset]; + Array.Copy(ruleArguments, 2 + argumentsOffset, listElementRuleArguments, 0, ruleArguments.Length - 2 - argumentsOffset); + + var propertyName = property.Name; + var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; + var propertyEntry = $"{propertyVarPrefix}Entry"; + var propertyCount = $"{propertyVarPrefix}Count"; + + if (shouldTidy) + { + source.AppendLine($"{indent}{property.Name}?.Tidy();"); + } + source.AppendLine($"{indent}var {propertyCount} = {property.Name}?.Count ?? 0;"); + source.AppendLine($"{indent}writer.WriteEncodedInt({propertyCount});"); + source.AppendLine($"{indent}if ({propertyCount} > 0)"); + source.AppendLine($"{indent}{{"); + source.AppendLine($"{indent} foreach (var {propertyEntry} in {property.Name}!)"); + source.AppendLine($"{indent} {{"); + + var serializableListElement = new SerializableProperty + { + Name = propertyEntry, + Type = ruleArguments[argumentsOffset], + Rule = listElementRule.RuleName, + RuleArguments = listElementRuleArguments + }; + + listElementRule.GenerateSerializationMethod(source, $"{indent} ", serializableListElement); + + source.AppendLine($"{indent} }}"); + source.AppendLine($"{indent}}}"); } } diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/MigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/MigrationRule.cs new file mode 100644 index 000000000..848812b54 --- /dev/null +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/MigrationRule.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Immutable; +using System.Text; +using Microsoft.CodeAnalysis; +using SerializationGenerator; + +namespace SerializableMigration; + +public abstract class MigrationRule : ISerializableMigrationRule +{ + public abstract string RuleName { get; } + + public virtual void GenerateMigrationProperty( + StringBuilder source, Compilation compilation, string indent, SerializableProperty serializableProperty + ) + { + var propertyType = serializableProperty.Type; + var type = compilation.GetTypeByMetadataName(propertyType)?.IsValueType == true + || SymbolMetadata.IsPrimitiveFromTypeDisplayString(propertyType) && propertyType != "bool" + ? $"{propertyType}{(serializableProperty.UsesSaveFlag == true ? "?" : "")}" : propertyType; + + source.AppendLine($"{indent}internal readonly {type} {serializableProperty.Name};"); + } + + public abstract bool GenerateRuleState( + Compilation compilation, ISymbol symbol, ImmutableArray attributes, + ImmutableArray serializableTypes, + ImmutableArray embeddedSerializableTypes, ISymbol? parentSymbol, out string[] ruleArguments + ); + + public abstract void GenerateDeserializationMethod( + StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false + ); + + public abstract void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property); +} diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/PrimitiveTypeMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/PrimitiveTypeMigrationRule.cs index f3d8135bd..70b34ce06 100644 --- a/Projects/SerializationGenerator/SerializableMigration/Rules/PrimitiveTypeMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/PrimitiveTypeMigrationRule.cs @@ -20,129 +20,130 @@ using System.Text; using Microsoft.CodeAnalysis; using SerializationGenerator; -namespace SerializableMigration +namespace SerializableMigration; + +public class PrimitiveTypeMigrationRule : MigrationRule { - public class PrimitiveTypeMigrationRule : ISerializableMigrationRule + public override string RuleName => nameof(PrimitiveTypeMigrationRule); + + public override bool GenerateRuleState( + Compilation compilation, + ISymbol symbol, + ImmutableArray attributes, + ImmutableArray serializableTypes, + ImmutableArray embeddedSerializableTypes, + ISymbol? parentSymbol, + out string[] ruleArguments + ) { - public string RuleName => nameof(PrimitiveTypeMigrationRule); - - public bool GenerateRuleState( - Compilation compilation, - ISymbol symbol, - ImmutableArray attributes, - ImmutableArray serializableTypes, - ImmutableArray embeddedSerializableTypes, - ISymbol? parentSymbol, - out string[] ruleArguments - ) + if (symbol.IsIpAddress(compilation) || symbol.IsTimeSpan(compilation)) { - if (symbol.IsIpAddress(compilation) || symbol.IsTimeSpan(compilation)) - { - ruleArguments = Array.Empty(); - return true; - } - - if ( - symbol is not ITypeSymbol { - SpecialType: not (not - SpecialType.System_Boolean and not - SpecialType.System_SByte and not - SpecialType.System_Int16 and not - SpecialType.System_Int32 and not - SpecialType.System_Int64 and not - SpecialType.System_Byte and not - SpecialType.System_UInt16 and not - SpecialType.System_UInt32 and not - SpecialType.System_UInt64 and not - SpecialType.System_Single and not - SpecialType.System_Double and not - SpecialType.System_String and not - SpecialType.System_Decimal and not - SpecialType.System_DateTime) - } typeSymbol - ) - { - ruleArguments = null; - return false; - } - - ruleArguments = typeSymbol.SpecialType switch - { - SpecialType.System_Int32 when attributes.Any(a => a.IsEncodedInt(compilation)) => - new[] { "EncodedInt" }, - SpecialType.System_DateTime when attributes.Any(a => a.IsDeltaDateTime(compilation)) => - new[] { "DeltaTime" }, - SpecialType.System_String when attributes.Any(a => a.IsInternString(compilation)) => - new[] { "InternString" }, - _ => new[] { "" } - }; - + ruleArguments = Array.Empty(); return true; } - public void GenerateDeserializationMethod(StringBuilder source, string indent, SerializableProperty property, string? parentReference) + if ( + symbol is not ITypeSymbol { + SpecialType: not (not + SpecialType.System_Boolean and not + SpecialType.System_SByte and not + SpecialType.System_Int16 and not + SpecialType.System_Int32 and not + SpecialType.System_Int64 and not + SpecialType.System_Byte and not + SpecialType.System_UInt16 and not + SpecialType.System_UInt32 and not + SpecialType.System_UInt64 and not + SpecialType.System_Single and not + SpecialType.System_Double and not + SpecialType.System_String and not + SpecialType.System_Decimal and not + SpecialType.System_DateTime) + } typeSymbol + ) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var propertyName = property.Name; - var argument = property.RuleArguments?.Length >= 1 ? property.RuleArguments[0] : null; - - const string ipAddress = SymbolMetadata.IPADDRESS_CLASS; - const string timeSpan = SymbolMetadata.TIMESPAN_STRUCT; - const string date = "System.DateTime"; - - var readMethod = property.Type switch - { - "bool" => "ReadBool", - "sbyte" => "ReadSByte", - "short" => "ReadShort", - "int" when argument == "EncodedInt" => "ReadEncodedInt", - "int" => "ReadInt", - "long" => "ReadLong", - "byte" => "ReadByte", - "ushort" => "ReadUShort", - "uint" => "ReadUInt", - "ulong" => "ReadULong", - "float" => "ReadFloat", - "double" => "ReadDouble", - "string" => "ReadString", - "decimal" => "ReadDecimal", - date when argument == "DeltaTime" => "ReadDeltaTime", - date => "ReadDateTime", - ipAddress => "ReadIPAddress", - timeSpan => "ReadTimeSpan" - }; - - var readArgument = readMethod == "ReadString" && argument == "InternString" ? "true" : ""; - - source.AppendLine($"{indent}{propertyName} = reader.{readMethod}({readArgument});"); + ruleArguments = null; + return false; } - public void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + ruleArguments = typeSymbol.SpecialType switch { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } + SpecialType.System_Int32 when attributes.Any(a => a.IsEncodedInt(compilation)) => + new[] { "EncodedInt" }, + SpecialType.System_DateTime when attributes.Any(a => a.IsDeltaDateTime(compilation)) => + new[] { "DeltaTime" }, + SpecialType.System_String when attributes.Any(a => a.IsInternString(compilation)) => + new[] { "InternString" }, + _ => new[] { "" } + }; - var propertyName = property.Name; - var argument = property.RuleArguments?.Length >= 1 ? property.RuleArguments[0] : null; + return true; + } - var writeMethod = property.Type switch - { - "System.DateTime" when argument == "DeltaTime" => "WriteDeltaTime", - "int" when argument == "EncodedInt" => "WriteEncodedInt", - _ => "Write" - }; - - source.AppendLine($"{indent}writer.{writeMethod}({propertyName});"); + public override void GenerateDeserializationMethod( + StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false + ) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); } + + var propertyName = property.Name; + var argument = property.RuleArguments?.Length >= 1 ? property.RuleArguments[0] : null; + + const string ipAddress = SymbolMetadata.IPADDRESS_CLASS; + const string timeSpan = SymbolMetadata.TIMESPAN_STRUCT; + const string date = "System.DateTime"; + + var readMethod = property.Type switch + { + "bool" => "ReadBool", + "sbyte" => "ReadSByte", + "short" => "ReadShort", + "int" when argument == "EncodedInt" => "ReadEncodedInt", + "int" => "ReadInt", + "long" => "ReadLong", + "byte" => "ReadByte", + "ushort" => "ReadUShort", + "uint" => "ReadUInt", + "ulong" => "ReadULong", + "float" => "ReadFloat", + "double" => "ReadDouble", + "string" => "ReadString", + "decimal" => "ReadDecimal", + date when argument == "DeltaTime" => "ReadDeltaTime", + date => "ReadDateTime", + ipAddress => "ReadIPAddress", + timeSpan => "ReadTimeSpan" + }; + + var readArgument = readMethod == "ReadString" && argument == "InternString" ? "true" : ""; + + source.AppendLine($"{indent}{propertyName} = reader.{readMethod}({readArgument});"); + } + + public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); + } + + var propertyName = property.Name; + var argument = property.RuleArguments?.Length >= 1 ? property.RuleArguments[0] : null; + + var writeMethod = property.Type switch + { + "System.DateTime" when argument == "DeltaTime" => "WriteDeltaTime", + "int" when argument == "EncodedInt" => "WriteEncodedInt", + _ => "Write" + }; + + source.AppendLine($"{indent}writer.{writeMethod}({propertyName});"); } } diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/PrimitiveUOTypeMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/PrimitiveUOTypeMigrationRule.cs index 9d60ca27e..ec2ea15d3 100644 --- a/Projects/SerializationGenerator/SerializableMigration/Rules/PrimitiveUOTypeMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/PrimitiveUOTypeMigrationRule.cs @@ -19,61 +19,62 @@ using System.Text; using Microsoft.CodeAnalysis; using SerializationGenerator; -namespace SerializableMigration +namespace SerializableMigration; + +public class PrimitiveUOTypeMigrationRule : MigrationRule { - public class PrimitiveUOTypeMigrationRule : ISerializableMigrationRule + public override string RuleName => nameof(PrimitiveUOTypeMigrationRule); + + public override bool GenerateRuleState( + Compilation compilation, + ISymbol symbol, + ImmutableArray attributes, + ImmutableArray serializableTypes, + ImmutableArray embeddedSerializableTypes, + ISymbol? parentSymbol, + out string[] ruleArguments + ) { - public string RuleName => nameof(PrimitiveUOTypeMigrationRule); - - public bool GenerateRuleState( - Compilation compilation, - ISymbol symbol, - ImmutableArray attributes, - ImmutableArray serializableTypes, - ImmutableArray embeddedSerializableTypes, - ISymbol? parentSymbol, - out string[] ruleArguments - ) + ruleArguments = symbol switch { - ruleArguments = symbol switch - { - _ when symbol.IsPoint2D(compilation) => new[] { "Point2D" }, - _ when symbol.IsPoint3D(compilation) => new[] { "Point3D" }, - _ when symbol.IsRectangle2D(compilation) => new[] { "Rect2D" }, - _ when symbol.IsRectangle3D(compilation) => new[] { "Rect3D" }, - _ when symbol.IsRace(compilation) => new[] { "Race" }, - _ when symbol.IsMap(compilation) => new[] { "Map" }, - _ when symbol.IsBitArray(compilation) => new[] { "BitArray" }, - _ => null - }; + _ when symbol.IsPoint2D(compilation) => new[] { "Point2D" }, + _ when symbol.IsPoint3D(compilation) => new[] { "Point3D" }, + _ when symbol.IsRectangle2D(compilation) => new[] { "Rect2D" }, + _ when symbol.IsRectangle3D(compilation) => new[] { "Rect3D" }, + _ when symbol.IsRace(compilation) => new[] { "Race" }, + _ when symbol.IsMap(compilation) => new[] { "Map" }, + _ when symbol.IsBitArray(compilation) => new[] { "BitArray" }, + _ => null + }; - return ruleArguments != null; + return ruleArguments != null; + } + + public override void GenerateDeserializationMethod( + StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false + ) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); } - public void GenerateDeserializationMethod(StringBuilder source, string indent, SerializableProperty property, string? parentReference) - { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } + var propertyName = property.Name; + source.AppendLine($"{indent}{propertyName} = reader.Read{property.RuleArguments?[0] ?? ""}();"); + } - var propertyName = property.Name; - source.AppendLine($"{indent}{propertyName} = reader.Read{property.RuleArguments?[0] ?? ""}();"); + public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); } - public void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) - { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var propertyName = property.Name; - source.AppendLine($"{indent}writer.Write({propertyName});"); - } + var propertyName = property.Name; + source.AppendLine($"{indent}writer.Write({propertyName});"); } } diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/RawSerializableMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/RawSerializableMigrationRule.cs index e5ee8c725..8f0944f1d 100644 --- a/Projects/SerializationGenerator/SerializableMigration/Rules/RawSerializableMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/RawSerializableMigrationRule.cs @@ -19,63 +19,64 @@ using System.Text; using Microsoft.CodeAnalysis; using SerializationGenerator; -namespace SerializableMigration +namespace SerializableMigration; + +public class RawSerializableMigrationRule : MigrationRule { - public class RawSerializableMigrationRule : ISerializableMigrationRule + public override string RuleName => nameof(RawSerializableMigrationRule); + + public override bool GenerateRuleState( + Compilation compilation, + ISymbol symbol, + ImmutableArray attributes, + ImmutableArray serializableTypes, + ImmutableArray embeddedSerializableTypes, + ISymbol? parentSymbol, + out string[] ruleArguments + ) { - public string RuleName => nameof(RawSerializableMigrationRule); - - public bool GenerateRuleState( - Compilation compilation, - ISymbol symbol, - ImmutableArray attributes, - ImmutableArray serializableTypes, - ImmutableArray embeddedSerializableTypes, - ISymbol? parentSymbol, - out string[] ruleArguments - ) + if (symbol is not ITypeSymbol typeSymbol) { - if (symbol is not ITypeSymbol typeSymbol) - { - ruleArguments = null; - return false; - } - - if (!typeSymbol.HasRawSerializableInterface(compilation, embeddedSerializableTypes)) - { - ruleArguments = null; - return false; - } - - ruleArguments = new[] { "" }; - return true; + ruleArguments = null; + return false; } - public void GenerateDeserializationMethod(StringBuilder source, string indent, SerializableProperty property, string? parentReference) + if (!typeSymbol.HasRawSerializableInterface(compilation, embeddedSerializableTypes)) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var propertyName = property.Name; - source.AppendLine($"{indent}{propertyName} = new {property.Type}({parentReference ?? "this"});"); - source.AppendLine($"{indent}{propertyName}.Deserialize(reader);"); + ruleArguments = null; + return false; } - public void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) - { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } + ruleArguments = new[] { "" }; + return true; + } - var propertyName = property.Name; - source.AppendLine($"{indent}{propertyName}.Serialize(writer);"); + public override void GenerateDeserializationMethod( + StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false + ) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); } + + var propertyName = property.Name; + source.AppendLine($"{indent}{propertyName} = new {property.Type}({parentReference ?? "this"});"); + source.AppendLine($"{indent}{propertyName}.Deserialize(reader);"); + } + + public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); + } + + var propertyName = property.Name; + source.AppendLine($"{indent}{propertyName}.Serialize(writer);"); } } diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/SerializableInterfaceMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/SerializableInterfaceMigrationRule.cs index 3cc932c80..2326af110 100644 --- a/Projects/SerializationGenerator/SerializableMigration/Rules/SerializableInterfaceMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/SerializableInterfaceMigrationRule.cs @@ -19,56 +19,57 @@ using System.Text; using Microsoft.CodeAnalysis; using SerializationGenerator; -namespace SerializableMigration +namespace SerializableMigration; + +public class SerializableInterfaceMigrationRule : MigrationRule { - public class SerializableInterfaceMigrationRule : ISerializableMigrationRule + public override string RuleName => nameof(SerializableInterfaceMigrationRule); + + public override bool GenerateRuleState( + Compilation compilation, + ISymbol symbol, + ImmutableArray attributes, + ImmutableArray serializableTypes, + ImmutableArray embeddedSerializableTypes, + ISymbol? parentSymbol, + out string[] ruleArguments + ) { - public string RuleName => nameof(SerializableInterfaceMigrationRule); - - public bool GenerateRuleState( - Compilation compilation, - ISymbol symbol, - ImmutableArray attributes, - ImmutableArray serializableTypes, - ImmutableArray embeddedSerializableTypes, - ISymbol? parentSymbol, - out string[] ruleArguments - ) + if (symbol is ITypeSymbol typeSymbol && typeSymbol.HasSerializableInterface(compilation, serializableTypes)) { - if (symbol is ITypeSymbol typeSymbol && typeSymbol.HasSerializableInterface(compilation, serializableTypes)) - { - ruleArguments = Array.Empty(); - return true; - } - - ruleArguments = null; - return false; + ruleArguments = Array.Empty(); + return true; } - public void GenerateDeserializationMethod(StringBuilder source, string indent, SerializableProperty property, string? parentReference) - { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } + ruleArguments = null; + return false; + } - var propertyName = property.Name; - source.AppendLine($"{indent}{propertyName} = reader.ReadEntity<{property.Type}>();"); + public override void GenerateDeserializationMethod( + StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false + ) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); } - public void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) - { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } + var propertyName = property.Name; + source.AppendLine($"{indent}{propertyName} = reader.ReadEntity<{property.Type}>();"); + } - var propertyName = property.Name; - source.AppendLine($"{indent}writer.Write({propertyName});"); + public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); } + + var propertyName = property.Name; + source.AppendLine($"{indent}writer.Write({propertyName});"); } } diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/SerializationMethodSignatureMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/SerializationMethodSignatureMigrationRule.cs index 1cd17971b..4e9859170 100644 --- a/Projects/SerializationGenerator/SerializableMigration/Rules/SerializationMethodSignatureMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/SerializationMethodSignatureMigrationRule.cs @@ -19,66 +19,67 @@ using System.Text; using Microsoft.CodeAnalysis; using SerializationGenerator; -namespace SerializableMigration +namespace SerializableMigration; + +public class SerializationMethodSignatureMigrationRule : MigrationRule { - public class SerializationMethodSignatureMigrationRule : ISerializableMigrationRule + public override string RuleName => nameof(SerializationMethodSignatureMigrationRule); + + public override bool GenerateRuleState( + Compilation compilation, + ISymbol symbol, + ImmutableArray attributes, + ImmutableArray serializableTypes, + ImmutableArray embeddedSerializableTypes, + ISymbol? parentSymbol, + out string[] ruleArguments + ) { - public string RuleName => nameof(SerializationMethodSignatureMigrationRule); - - public bool GenerateRuleState( - Compilation compilation, - ISymbol symbol, - ImmutableArray attributes, - ImmutableArray serializableTypes, - ImmutableArray embeddedSerializableTypes, - ISymbol? parentSymbol, - out string[] ruleArguments - ) + if ((symbol as ITypeSymbol)?.HasPublicSerializeMethod(compilation, serializableTypes) != true) { - if ((symbol as ITypeSymbol)?.HasPublicSerializeMethod(compilation, serializableTypes) != true) - { - ruleArguments = null; - return false; - } - - if (symbol is not INamedTypeSymbol namedTypeSymbol || - !namedTypeSymbol.HasGenericReaderCtor(compilation, parentSymbol, out var requiresParent)) - { - ruleArguments = null; - return false; - } - - ruleArguments = new[] { requiresParent ? "DeserializationRequiresParent" : "" }; - return true; + ruleArguments = null; + return false; } - public void GenerateDeserializationMethod(StringBuilder source, string indent, SerializableProperty property, string? parentReference) + if (symbol is not INamedTypeSymbol namedTypeSymbol || + !namedTypeSymbol.HasGenericReaderCtor(compilation, parentSymbol, out var requiresParent)) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var propertyName = property.Name; - var argument = property.RuleArguments?.Length >= 1 && - property.RuleArguments[0] == "DeserializationRequiresParent" ? ", this" : ""; - - source.AppendLine($"{indent}{propertyName} = new {property.Type}(reader{argument});"); + ruleArguments = null; + return false; } - public void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) - { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } + ruleArguments = new[] { requiresParent ? "DeserializationRequiresParent" : "" }; + return true; + } - var propertyName = property.Name; - source.AppendLine($"{indent}{propertyName}.Serialize(writer);"); + public override void GenerateDeserializationMethod( + StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false + ) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); } + + var propertyName = property.Name; + var argument = property.RuleArguments?.Length >= 1 && + property.RuleArguments[0] == "DeserializationRequiresParent" ? ", this" : ""; + + source.AppendLine($"{indent}{propertyName} = new {property.Type}(reader{argument});"); + } + + public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); + } + + var propertyName = property.Name; + source.AppendLine($"{indent}{propertyName}.Serialize(writer);"); } } diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/TimerMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/TimerMigrationRule.cs index 9fba1913a..7d97dfd6e 100644 --- a/Projects/SerializationGenerator/SerializableMigration/Rules/TimerMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/TimerMigrationRule.cs @@ -20,107 +20,117 @@ using System.Text; using Microsoft.CodeAnalysis; using SerializationGenerator; -namespace SerializableMigration +namespace SerializableMigration; + +public class TimerMigrationRule : MigrationRule, IPostDeserializeMethod { - public class TimerMigrationRule : ISerializableMigrationRule, IPostDeserializeMethod + public override string RuleName => nameof(TimerMigrationRule); + + public override bool GenerateRuleState( + Compilation compilation, + ISymbol symbol, + ImmutableArray attributes, + ImmutableArray serializableTypes, + ImmutableArray embeddedSerializableTypes, + ISymbol? parentSymbol, + out string[] ruleArguments + ) { - public string RuleName => nameof(TimerMigrationRule); - - public bool GenerateRuleState( - Compilation compilation, - ISymbol symbol, - ImmutableArray attributes, - ImmutableArray serializableTypes, - ImmutableArray embeddedSerializableTypes, - ISymbol? parentSymbol, - out string[] ruleArguments - ) + if (!(symbol is ITypeSymbol typeSymbol && typeSymbol.IsTimer(compilation))) { - if (!(symbol is ITypeSymbol typeSymbol && typeSymbol.IsTimer(compilation))) - { - ruleArguments = null; - return false; - } - - ruleArguments = attributes.Any(a => a.IsTimerDrift(compilation)) - ? new[] { "@TimerDrift" } - : new[] { "" }; - - return true; + ruleArguments = null; + return false; } - public void GenerateDeserializationMethod(StringBuilder source, string indent, SerializableProperty property, string? parentReference) + ruleArguments = attributes.Any(a => a.IsTimerDrift(compilation)) + ? new[] { "@TimerDrift" } + : new[] { "" }; + + return true; + } + + public override void GenerateMigrationProperty( + StringBuilder source, Compilation compilation, string indent, SerializableProperty serializableProperty + ) + { + source.AppendLine($"{indent}internal readonly System.DateTime {serializableProperty.Name}Next;"); + source.AppendLine($"{indent}internal readonly System.TimeSpan {serializableProperty.Name}Delay;"); + } + + public override void GenerateDeserializationMethod( + StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false + ) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var propertyName = property.Name; - var ruleArguments = property.RuleArguments; - var driftTimer = ruleArguments![0].Contains("@TimerDrift"); - - var readTimer = driftTimer ? "reader.ReadDeltaTime()" : "reader.ReadDateTime()"; - source.AppendLine($"{indent}var {propertyName}Next = {readTimer};"); - source.AppendLine($"{indent}var {propertyName}Delay = {propertyName}Next == System.DateTime.MinValue ? System.TimeSpan.MinValue : {propertyName}Next - Core.Now;"); + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); } - public void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + var propertyName = property.Name; + var ruleArguments = property.RuleArguments; + var driftTimer = ruleArguments![0].Contains("@TimerDrift"); + + var readTimer = driftTimer ? "reader.ReadDeltaTime()" : "reader.ReadDateTime()"; + var useVar = isMigration ? "" : "var "; + source.AppendLine($"{indent}{useVar}{propertyName}Next = {readTimer};"); + source.AppendLine($"{indent}{useVar}{propertyName}Delay = {propertyName}Next == System.DateTime.MinValue ? System.TimeSpan.MinValue : {propertyName}Next - Core.Now;"); + } + + public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var propertyName = property.Name; - var ruleArguments = property.RuleArguments; - var driftTimer = ruleArguments![0].Contains("@TimerDrift"); - - var writerMethod = driftTimer ? "WriteDeltaTime" : "Write"; - source.AppendLine($"{indent}writer.{writerMethod}({propertyName}?.Next ?? System.DateTime.MinValue);"); + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); } - public void PostDeserializeMethod( - StringBuilder source, string indent, SerializableProperty property, Compilation compilation, INamedTypeSymbol classSymbol - ) - { - var deserializeTimerMethod = classSymbol - .GetMembers() - .OfType() - .FirstOrDefault( - m => + var propertyName = property.Name; + var ruleArguments = property.RuleArguments; + var driftTimer = ruleArguments![0].Contains("@TimerDrift"); + + var writerMethod = driftTimer ? "WriteDeltaTime" : "Write"; + source.AppendLine($"{indent}writer.{writerMethod}({propertyName}?.Next ?? System.DateTime.MinValue);"); + } + + public void PostDeserializeMethod( + StringBuilder source, string indent, SerializableProperty property, Compilation compilation, INamedTypeSymbol classSymbol + ) + { + var deserializeTimerMethod = classSymbol + .GetMembers() + .OfType() + .FirstOrDefault( + m => + { + if (!m.ReturnsVoid || m.Parameters.Length != 1 || !m.Parameters[0].Type.IsTimeSpan(compilation)) { - if (!m.ReturnsVoid || m.Parameters.Length != 1 || !m.Parameters[0].Type.IsTimeSpan(compilation)) - { - return false; - } + return false; + } - return m.GetAttributes() - .FirstOrDefault( - attr => - { - if (!SymbolEqualityComparer.Default.Equals( + return m.GetAttributes() + .FirstOrDefault( + attr => + { + if (!SymbolEqualityComparer.Default.Equals( attr.AttributeClass, compilation.GetTypeByMetadataName( SymbolMetadata.DESERIALIZE_TIMER_FIELD_ATTRIBUTE ) )) - { - return false; - } - - var order = (int)attr.ConstructorArguments[0].Value!; - return order == property.Order; + { + return false; } - ) != null; - } - ) ?? throw new Exception("Serializing a timer requires a method with the DeserializeTimerField attribute to handle creating the timer itself."); - source.AppendLine($"{indent}{deserializeTimerMethod.Name}({property.Name}Delay);"); - } + var order = (int)attr.ConstructorArguments[0].Value!; + return order == property.Order; + } + ) != null; + } + ) ?? throw new Exception("Serializing a timer requires a method with the DeserializeTimerField attribute to handle creating the timer itself."); + + source.AppendLine($"{indent}{deserializeTimerMethod.Name}({property.Name}Delay);"); } }