namespace ALttPRandomizer.Serialization { using System; using System.Collections.Generic; using System.Text.Json; using System.Text.Json.Serialization; using ALttPRandomizer.Model; public class RandomizableWeightsJsonConverter : JsonConverterFactory { public override bool CanConvert(Type typeToConvert) { if (!typeToConvert.IsGenericType) { return false; } if (typeToConvert.GetGenericTypeDefinition() != typeof(RandomizableWeights<>)) { return false; } return true; } public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options) { Type itemType = typeToConvert.GetGenericArguments()[0]; Type innerType = typeof(RandomizableWeightsConverterInner<>).MakeGenericType(itemType); return (JsonConverter) Activator.CreateInstance(innerType, args: options)!; } private class RandomizableWeightsConverterInner : JsonConverter> where T : struct, Enum { private readonly JsonConverter> dictionaryConverter; private readonly JsonConverter valueConverter; private readonly Type valueType; private readonly Type dictionaryType; public RandomizableWeightsConverterInner(JsonSerializerOptions options) { dictionaryConverter = (JsonConverter>) options.GetConverter(typeof(IDictionary)); valueConverter = (JsonConverter) options.GetConverter(typeof(T)); this.valueType = typeof(T); this.dictionaryType = typeof(IDictionary); } public override RandomizableWeights? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { switch (reader.TokenType) { case JsonTokenType.Null: return RandomizableWeights.EmptyWeights; case JsonTokenType.String: case JsonTokenType.Number: var value = valueConverter.Read(ref reader, this.valueType, options); return RandomizableWeights.ConstantWeights(value); case JsonTokenType.StartObject: var dict = dictionaryConverter.Read(ref reader, this.dictionaryType, options); if (dict == null) { return RandomizableWeights.EmptyWeights; } else { return RandomizableWeights.FromDictionary(dict); } default: throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, RandomizableWeights value, JsonSerializerOptions options) { switch (value.Options.Count) { case 0: writer.WriteNullValue(); break; case 1: this.valueConverter.Write(writer, value.Options[0].Item, options); break; default: writer.WriteStartObject(); foreach (var (item, weight) in value.Options) { this.valueConverter.WriteAsPropertyName(writer, item, options); writer.WriteNumberValue(weight); } writer.WriteEndObject(); break; } } } } }