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

106 lines
4.0 KiB
C#

namespace ALttPRandomizer.Serialization {
using System;
using System.Collections.Generic;
using ALttPRandomizer.Model;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;
public class RandomizableWeightsYamlConverters : IYamlTypeConverter {
private readonly Dictionary<Type, IYamlTypeConverter> converters = new();
public bool Accepts(Type type) {
if (this.converters.ContainsKey(type)) {
return true;
}
if (!type.IsGenericType) {
return false;
}
if (type.GetGenericTypeDefinition() != typeof(RandomizableWeights<>)) {
return false;
}
Type itemType = type.GetGenericArguments()[0];
Type innerType = typeof(RandomizableWeightsYamlConverter<>).MakeGenericType(itemType)!;
this.converters[type] = (IYamlTypeConverter) Activator.CreateInstance(innerType)!;
return true;
}
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer) {
return this.converters[type].ReadYaml(parser, type, rootDeserializer);
}
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer) {
this.converters[type].WriteYaml(emitter, value, type, serializer);
}
}
internal class RandomizableWeightsYamlConverter<T> : IYamlTypeConverter where T : struct, Enum {
private readonly Type valueType;
private readonly Type dictionaryType;
public RandomizableWeightsYamlConverter() {
this.valueType = typeof(T);
this.dictionaryType = typeof(IDictionary<T, int>);
}
public bool Accepts(Type type) {
return type == typeof(RandomizableWeights<T>);
}
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer) {
if (parser.Accept<Scalar>(out var evt)) {
if (evt.Value == "null") {
parser.Consume<Scalar>();
return RandomizableWeights<T>.EmptyWeights;
}
var value = rootDeserializer.Invoke(this.valueType);
if (value is T t) {
return RandomizableWeights<T>.ConstantWeights(t);
} else {
return RandomizableWeights<T>.EmptyWeights;
}
}
if (parser.Accept<MappingStart>(out _)) {
var value = rootDeserializer.Invoke(this.dictionaryType);
if (value is IDictionary<T, int> dict) {
return RandomizableWeights<T>.FromDictionary(dict);
} else {
return RandomizableWeights<T>.EmptyWeights;
}
}
throw new YamlException($"Error reading type RandomizableWeights<{typeof(T).Name}>.");
}
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer) {
if (value is RandomizableWeights<T> weights) {
switch (weights.Options.Count) {
case 0:
emitter.Emit(new Scalar("null"));
break;
case 1:
serializer.Invoke(weights.Options[0].Item, valueType);
break;
default:
emitter.Emit(new MappingStart());
foreach (var (item, weight) in weights.Options) {
serializer.Invoke(item, valueType);
emitter.Emit(new Scalar(weight.ToString()));
}
emitter.Emit(new MappingEnd());
break;
}
} else {
emitter.Emit(new MappingStart());
emitter.Emit(new MappingEnd());
}
}
}
}