Code cleanup and fix test running

This commit is contained in:
Timothy Baldridge
2021-10-23 10:51:17 -06:00
parent 2b5662a15b
commit f99f4a7538
577 changed files with 26516 additions and 27096 deletions

View File

@ -1,40 +1,39 @@
using System.IO;
using System.Text;
namespace Wabbajack.DTOs.ConverterGenerators
namespace Wabbajack.DTOs.ConverterGenerators;
public class CFile
{
public class CFile
private readonly StringBuilder _sb;
private int _indent;
public CFile()
{
private readonly StringBuilder _sb;
private int _indent;
_sb = new StringBuilder();
Code("// THIS FILE IS AUTOGENERATED DO NOT EDIT BY HAND");
Code("using System;");
Code("using System.Text.Json;");
Code("using System.Text.Json.Serialization;");
Code("using Wabbajack.Hashing.xxHash64;");
Code("using Microsoft.Extensions.DependencyInjection;");
Code("");
}
public CFile()
{
_sb = new StringBuilder();
Code("// THIS FILE IS AUTOGENERATED DO NOT EDIT BY HAND");
Code("using System;");
Code("using System.Text.Json;");
Code("using System.Text.Json.Serialization;");
Code("using Wabbajack.Hashing.xxHash64;");
Code("using Microsoft.Extensions.DependencyInjection;");
Code("");
}
public void Write(string path)
{
File.WriteAllText(path, _sb.ToString());
}
public void Write(string path)
{
File.WriteAllText(path, _sb.ToString());
}
public void Code(string c)
{
if (c.EndsWith("}"))
_indent--;
public void Code(string c)
{
if (c.EndsWith("}"))
_indent--;
for (var i = 0; i < _indent; i++) _sb.Append(" ");
_sb.AppendLine(c);
for (var i = 0; i < _indent; i++) _sb.Append(" ");
_sb.AppendLine(c);
if (c.EndsWith("{"))
_indent++;
}
if (c.EndsWith("{"))
_indent++;
}
}

View File

@ -6,203 +6,202 @@ using System.Text.Json;
using System.Text.Json.Serialization;
using Wabbajack.DTOs.JsonConverters;
namespace Wabbajack.DTOs.ConverterGenerators
namespace Wabbajack.DTOs.ConverterGenerators;
public class PolymorphicGenerator<T>
{
public class PolymorphicGenerator<T>
public PolymorphicGenerator()
{
public PolymorphicGenerator()
var types = typeof(T).Assembly.GetTypes()
.Where(t => !t.IsAbstract && !t.IsInterface)
.Where(t => t.IsAssignableTo(typeof(T)));
foreach (var type in types)
{
var types = typeof(T).Assembly.GetTypes()
.Where(t => !t.IsAbstract && !t.IsInterface)
.Where(t => t.IsAssignableTo(typeof(T)));
var nameAttr = type.CustomAttributes.Where(t => t.AttributeType == typeof(JsonNameAttribute))
.Select(t => (string) t.ConstructorArguments.First().Value!)
.FirstOrDefault();
foreach (var type in types)
{
var nameAttr = type.CustomAttributes.Where(t => t.AttributeType == typeof(JsonNameAttribute))
.Select(t => (string)t.ConstructorArguments.First().Value!)
.FirstOrDefault();
if (nameAttr == default)
throw new JsonException($"Type {type} of interface {typeof(T)} does not have a JsonNameAttribute");
Registry[nameAttr] = type;
ReverseRegistry[type] = nameAttr;
if (nameAttr == default)
throw new JsonException($"Type {type} of interface {typeof(T)} does not have a JsonNameAttribute");
Registry[nameAttr] = type;
ReverseRegistry[type] = nameAttr;
var aliases = type.CustomAttributes.Where(t => t.AttributeType == typeof(JsonAliasAttribute))
.Select(t => t.ConstructorArguments.First());
var aliases = type.CustomAttributes.Where(t => t.AttributeType == typeof(JsonAliasAttribute))
.Select(t => t.ConstructorArguments.First());
foreach (var alias in aliases) Registry[(string)alias.Value!] = type;
}
foreach (var alias in aliases) Registry[(string) alias.Value!] = type;
}
}
public Dictionary<string, Type> Registry { get; } = new();
public Dictionary<Type, string> ReverseRegistry { get; } = new();
public Dictionary<string, Type> Registry { get; } = new();
public Dictionary<Type, string> ReverseRegistry { get; } = new();
public void GenerateSpecific(CFile c)
public void GenerateSpecific(CFile c)
{
foreach (var type in ReverseRegistry.Keys.OrderBy(k => k.FullName))
{
foreach (var type in ReverseRegistry.Keys.OrderBy(k => k.FullName))
{
var members = type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.CanRead)
.Where(p => p.CanWrite)
.Where(p => !p.CustomAttributes.Any(c => c.AttributeType == typeof(JsonIgnoreAttribute)))
.Select(p =>
var members = type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.CanRead)
.Where(p => p.CanWrite)
.Where(p => !p.CustomAttributes.Any(c => c.AttributeType == typeof(JsonIgnoreAttribute)))
.Select(p =>
{
var name = p.CustomAttributes.Where(c => c.AttributeType == typeof(JsonPropertyNameAttribute))
.Select(a => (string) a.ConstructorArguments.FirstOrDefault().Value)
.FirstOrDefault() ?? p.Name;
return new
{
var name = p.CustomAttributes.Where(c => c.AttributeType == typeof(JsonPropertyNameAttribute))
.Select(a => (string)a.ConstructorArguments.FirstOrDefault().Value)
.FirstOrDefault() ?? p.Name;
return new
{
Name = name, PropName = name.ToLower() + "Prop", Property = p, Type = p.PropertyType,
RealName = p.Name
};
})
.OrderBy(p => p.Name)
.ToArray();
var mungedName = type.FullName!.Replace(".", "_");
c.Code($"public class {mungedName}Converter : JsonConverter<{type.FullName}> {{");
c.Code(
$"public override {type.FullName} Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {{");
c.Code("if (reader.TokenType != JsonTokenType.StartObject)");
c.Code(" throw new JsonException();");
foreach (var member in members) c.Code($"{member.Type.FullName} {member.PropName} = default;");
c.Code("while (true) {");
c.Code("reader.Read();");
c.Code("if (reader.TokenType == JsonTokenType.EndObject) {");
c.Code("reader.Read();");
c.Code("break;");
c.Code("}");
c.Code("var prop = reader.GetString();");
c.Code("reader.Read();");
c.Code("switch (prop) {");
foreach (var member in members)
{
c.Code($"case \"{member.Name}\":");
c.Code(
$" {member.PropName} = JsonSerializer.Deserialize<{member.Type.FullName}>(ref reader, options);");
c.Code(" break;");
}
c.Code("default:");
c.Code(" reader.Skip();");
c.Code(" break;");
c.Code("}");
c.Code("}");
c.Code($"return new {type.FullName} {{");
foreach (var member in members) c.Code($"{member.RealName} = {member.PropName},");
c.Code("};");
c.Code("}");
c.Code(
$"public override void Write(Utf8JsonWriter writer, {type.FullName} value, JsonSerializerOptions options) {{");
c.Code("writer.WriteStartObject();");
c.Code($"writer.WriteString(\"$type\", \"{ReverseRegistry[type]}\");");
foreach (var member in members)
{
c.Code($"writer.WritePropertyName(\"{member.Name}\");");
c.Code(
$"JsonSerializer.Serialize<{member.Type.FullName}>(writer, value.{member.RealName}, options);");
}
c.Code("writer.WriteEndObject();");
c.Code("}");
c.Code("}");
}
}
public void GenerateGeneric(CFile c)
{
var type = typeof(T);
var mungedName = typeof(T).FullName!.Replace(".", "_");
Name = name, PropName = name.ToLower() + "Prop", Property = p, Type = p.PropertyType,
RealName = p.Name
};
})
.OrderBy(p => p.Name)
.ToArray();
var mungedName = type.FullName!.Replace(".", "_");
c.Code($"public class {mungedName}Converter : JsonConverter<{type.FullName}> {{");
c.Code("public static void ConfigureServices(IServiceCollection services) {");
foreach (var tp in ReverseRegistry.Keys)
c.Code($"services.AddSingleton<JsonConverter, {tp.FullName!.Replace(".", "_")}Converter>();");
c.Code($"services.AddSingleton<JsonConverter, {mungedName}Converter>();");
c.Code("}");
c.Code(
$"public override {type.FullName} Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {{");
c.Code("var cReader = reader;");
c.Code("if (reader.TokenType != JsonTokenType.StartObject)");
c.Code(" throw new JsonException();");
c.Code("cReader.Read();");
foreach (var member in members) c.Code($"{member.Type.FullName} {member.PropName} = default;");
c.Code("if (cReader.GetString() != \"$type\")");
c.Code(" throw new JsonException();");
c.Code("cReader.Read();");
c.Code("var type = cReader.GetString();");
c.Code("switch(type) {");
foreach (var (alias, tp) in Registry)
c.Code("while (true) {");
c.Code("reader.Read();");
c.Code("if (reader.TokenType == JsonTokenType.EndObject) {");
c.Code("reader.Read();");
c.Code("break;");
c.Code("}");
c.Code("var prop = reader.GetString();");
c.Code("reader.Read();");
c.Code("switch (prop) {");
foreach (var member in members)
{
c.Code($"case \"{alias}\":");
c.Code($" return JsonSerializer.Deserialize<{tp.FullName}>(ref reader, options)!;");
c.Code($"case \"{member.Name}\":");
c.Code(
$" {member.PropName} = JsonSerializer.Deserialize<{member.Type.FullName}>(ref reader, options);");
c.Code(" break;");
}
c.Code("default:");
c.Code(" throw new JsonException($\"No Type dispatch for {type}\");");
c.Code(" reader.Skip();");
c.Code(" break;");
c.Code("}");
c.Code("}");
c.Code($"return new {type.FullName} {{");
foreach (var member in members) c.Code($"{member.RealName} = {member.PropName},");
c.Code("};");
c.Code("}");
c.Code(
$"public override void Write(Utf8JsonWriter writer, {type.FullName} value, JsonSerializerOptions options) {{");
c.Code("switch (value) {");
var idx = 0;
c.Code("writer.WriteStartObject();");
c.Code($"writer.WriteString(\"$type\", \"{ReverseRegistry[type]}\");");
int Distance(Type t)
foreach (var member in members)
{
var depth = 0;
var b = t;
while (b != null)
{
b = b.BaseType;
depth += 1;
}
return depth;
c.Code($"writer.WritePropertyName(\"{member.Name}\");");
c.Code(
$"JsonSerializer.Serialize<{member.Type.FullName}>(writer, value.{member.RealName}, options);");
}
foreach (var t in ReverseRegistry.Keys.OrderByDescending(t => Distance(t)))
{
c.Code($"case {t.FullName} v{idx}:");
c.Code($" JsonSerializer.Serialize(writer, v{idx}, options);");
c.Code(" return;");
idx += 1;
}
c.Code("writer.WriteEndObject();");
c.Code("}");
c.Code("}");
c.Code("}");
}
public void GenerateAll(CFile cfile)
{
GenerateGeneric(cfile);
GenerateSpecific(cfile);
}
}
public void GenerateGeneric(CFile c)
{
var type = typeof(T);
var mungedName = typeof(T).FullName!.Replace(".", "_");
c.Code($"public class {mungedName}Converter : JsonConverter<{type.FullName}> {{");
c.Code("public static void ConfigureServices(IServiceCollection services) {");
foreach (var tp in ReverseRegistry.Keys)
c.Code($"services.AddSingleton<JsonConverter, {tp.FullName!.Replace(".", "_")}Converter>();");
c.Code($"services.AddSingleton<JsonConverter, {mungedName}Converter>();");
c.Code("}");
c.Code(
$"public override {type.FullName} Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {{");
c.Code("var cReader = reader;");
c.Code("if (reader.TokenType != JsonTokenType.StartObject)");
c.Code(" throw new JsonException();");
c.Code("cReader.Read();");
c.Code("if (cReader.GetString() != \"$type\")");
c.Code(" throw new JsonException();");
c.Code("cReader.Read();");
c.Code("var type = cReader.GetString();");
c.Code("switch(type) {");
foreach (var (alias, tp) in Registry)
{
c.Code($"case \"{alias}\":");
c.Code($" return JsonSerializer.Deserialize<{tp.FullName}>(ref reader, options)!;");
}
c.Code("default:");
c.Code(" throw new JsonException($\"No Type dispatch for {type}\");");
c.Code("}");
c.Code("}");
c.Code(
$"public override void Write(Utf8JsonWriter writer, {type.FullName} value, JsonSerializerOptions options) {{");
c.Code("switch (value) {");
var idx = 0;
int Distance(Type t)
{
var depth = 0;
var b = t;
while (b != null)
{
b = b.BaseType;
depth += 1;
}
return depth;
}
foreach (var t in ReverseRegistry.Keys.OrderByDescending(t => Distance(t)))
{
c.Code($"case {t.FullName} v{idx}:");
c.Code($" JsonSerializer.Serialize(writer, v{idx}, options);");
c.Code(" return;");
idx += 1;
}
c.Code("}");
c.Code("}");
c.Code("}");
}
public void GenerateAll(CFile cfile)
{
GenerateGeneric(cfile);
GenerateSpecific(cfile);
}
}

View File

@ -2,20 +2,19 @@
using Wabbajack.DTOs.BSA.FileStates;
using Wabbajack.DTOs.DownloadStates;
namespace Wabbajack.DTOs.ConverterGenerators
namespace Wabbajack.DTOs.ConverterGenerators;
internal class Program
{
internal class Program
private static void Main(string[] args)
{
private static void Main(string[] args)
{
var cfile = new CFile();
new PolymorphicGenerator<IDownloadState>().GenerateAll(cfile);
new PolymorphicGenerator<IArchive>().GenerateAll(cfile);
new PolymorphicGenerator<Directive>().GenerateAll(cfile);
new PolymorphicGenerator<AFile>().GenerateAll(cfile);
var cfile = new CFile();
new PolymorphicGenerator<IDownloadState>().GenerateAll(cfile);
new PolymorphicGenerator<IArchive>().GenerateAll(cfile);
new PolymorphicGenerator<Directive>().GenerateAll(cfile);
new PolymorphicGenerator<AFile>().GenerateAll(cfile);
cfile.Write(@"..\Wabbajack.DTOs\JsonConverters\Generated.cs");
}
cfile.Write(@"..\Wabbajack.DTOs\JsonConverters\Generated.cs");
}
}