Files
alttpr-backend/ALttPRandomizer/Serialization/RandomizableWeightsJsonConverter.cs

83 lines
3.7 KiB
C#

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<T> : JsonConverter<RandomizableWeights<T>> where T : struct, Enum {
private readonly JsonConverter<IDictionary<T, int>> dictionaryConverter;
private readonly JsonConverter<T> valueConverter;
private readonly Type valueType;
private readonly Type dictionaryType;
public RandomizableWeightsConverterInner(JsonSerializerOptions options) {
dictionaryConverter = (JsonConverter<IDictionary<T, int>>) options.GetConverter(typeof(IDictionary<T, int>));
valueConverter = (JsonConverter<T>) options.GetConverter(typeof(T));
this.valueType = typeof(T);
this.dictionaryType = typeof(IDictionary<T, int>);
}
public override RandomizableWeights<T>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
switch (reader.TokenType) {
case JsonTokenType.Null:
return RandomizableWeights<T>.EmptyWeights;
case JsonTokenType.String:
case JsonTokenType.Number:
var value = valueConverter.Read(ref reader, this.valueType, options);
return RandomizableWeights<T>.ConstantWeights(value);
case JsonTokenType.StartObject:
var dict = dictionaryConverter.Read(ref reader, this.dictionaryType, options);
if (dict == null) {
return RandomizableWeights<T>.EmptyWeights;
} else {
return RandomizableWeights<T>.FromDictionary(dict);
}
default:
throw new JsonException();
}
}
public override void Write(Utf8JsonWriter writer, RandomizableWeights<T> 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;
}
}
}
}
}