using System.Collections; using System.Reflection; using Syntriax.Engine.Core; using Syntriax.Engine.Core.Factory; using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Serialization; namespace Syntriax.Engine.Serialization; public class EntityConverter(IReadOnlyDictionary entities) : IYamlTypeConverter { private readonly IReadOnlyDictionary Entities = entities; private readonly HashSet entitiesVisited = []; public bool Accepts(Type type) => typeof(IEntity).IsAssignableFrom(type); public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer) { parser.Consume(); TypeContainer typeContainer = (TypeContainer)rootDeserializer(typeof(TypeContainer))!; object instance = TypeFactory.Get(typeContainer.Type); while (!parser.TryConsume(out _)) { string key = parser.Consume().Value; if (type.GetField(key, BindingFlags.Instance | BindingFlags.NonPublic) is FieldInfo fieldInfo) { object? fieldValue = rootDeserializer(fieldInfo.FieldType); fieldInfo.SetValue(instance, fieldValue); } else if (type.GetProperty(key) is PropertyInfo propertyInfo) { object? propertyValue = rootDeserializer(propertyInfo.PropertyType); propertyInfo.SetValue(instance, propertyValue); } else parser.SkipThisAndNestedEvents(); } parser.TryConsume(out _); return instance; } public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer) { if (type.HasAttribute()) { emitter.Emit(new Scalar("")); return; } IEntity entity = (IEntity)value!; if (!entitiesVisited.Add(entity)) { emitter.Emit(new Scalar(entity.Id)); return; } emitter.Emit(new MappingStart()); serializer(new TypeContainer(value), typeof(TypeContainer)); TypeData typeData = Utils.GetTypeData(type); foreach (PropertyInfo propertyInfo in typeData.Properties) { if (propertyInfo.HasAttribute()) continue; emitter.Emit(new Scalar(propertyInfo.Name)); object? propertyValue = propertyInfo.GetValue(value); EmitValue(propertyValue, propertyInfo.PropertyType, emitter, serializer); } foreach (FieldInfo fieldInfo in typeData.Fields) { if (fieldInfo.HasAttribute()) continue; if (fieldInfo.HasAttribute()) continue; // if (!fieldInfo.HasAttribute()) // continue; emitter.Emit(new Scalar(fieldInfo.Name)); object? fieldValue = fieldInfo.GetValue(value); EmitValue(fieldValue, fieldInfo.FieldType, emitter, serializer); } 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; } if (value is IEntity entity) { emitter.Emit(new Scalar(entity.Id)); 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) if (value is IEntity sequenceEntity) emitter.Emit(new Scalar(sequenceEntity.Id)); else serializer(item); emitter.Emit(new SequenceEnd()); } }