125 lines
3.7 KiB
C#

using System.Collections;
using System.Reflection;
using Syntriax.Engine.Core.Factory;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;
namespace Syntriax.Engine.Serialization;
public class InstanceConverter : IEngineTypeYamlConverter
{
private int depth = 0;
private int maxDepth = 5;
public bool Accepts(Type type) => !type.IsPrimitive && type != typeof(string);
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
{
if (depth > maxDepth)
return null;
parser.Consume<MappingStart>();
TypeContainer typeContainer = (TypeContainer)rootDeserializer(typeof(TypeContainer))!;
object instance = TypeFactory.Get(typeContainer.Type);
while (!parser.TryConsume<MappingEnd>(out _))
{
string key = parser.Consume<Scalar>().Value;
if (type.GetField(key, BindingFlags.Instance | BindingFlags.NonPublic) is FieldInfo fieldInfo)
{
depth++;
object? fieldValue = rootDeserializer(fieldInfo.FieldType);
depth--;
fieldInfo.SetValue(instance, fieldValue);
}
else if (type.GetProperty(key) is PropertyInfo propertyInfo)
{
depth++;
object? propertyValue = rootDeserializer(propertyInfo.PropertyType);
depth--;
propertyInfo.SetValue(instance, propertyValue);
}
else
parser.SkipThisAndNestedEvents();
}
parser.TryConsume<MappingEnd>(out _);
return instance;
}
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
{
emitter.Emit(new MappingStart());
serializer(new TypeContainer(value), typeof(TypeContainer));
TypeData typeData = Utils.GetTypeData(type);
foreach (PropertyInfo propertyInfo in typeData.Properties)
{
if (propertyInfo.HasAttribute<IgnoreSerializationAttribute>())
continue;
emitter.Emit(new Scalar(propertyInfo.Name));
object? propertyValue = propertyInfo.GetValue(value);
depth++;
if (depth <= maxDepth)
EmitValue(propertyValue, propertyInfo.PropertyType, emitter, serializer);
else
emitter.Emit(new Scalar("Skipped"));
depth--;
}
foreach (FieldInfo fieldInfo in typeData.Fields)
{
if (fieldInfo.HasAttribute<System.Runtime.CompilerServices.CompilerGeneratedAttribute>())
continue;
if (!fieldInfo.HasAttribute<SerializeAttribute>())
continue;
emitter.Emit(new Scalar(fieldInfo.Name));
object? fieldValue = fieldInfo.GetValue(value);
depth++;
if (depth <= maxDepth)
EmitValue(fieldValue, fieldInfo.FieldType, emitter, serializer);
else
emitter.Emit(new Scalar("Skipped"));
depth--;
}
emitter.Emit(new MappingEnd());
}
private static void EmitValue(object? value, Type declaredType, IEmitter emitter, ObjectSerializer serializer)
{
if (value is null)
{
emitter.Emit(new Scalar(""));
return;
}
bool isSequence = Utils.IsEnumerable(declaredType);
if (!isSequence)
{
serializer(value);
return;
}
IEnumerable sequence = (IEnumerable)value;
emitter.Emit(new SequenceStart(null, null, false, SequenceStyle.Block));
foreach (object? item in sequence)
serializer(item);
emitter.Emit(new SequenceEnd());
}
}