From d102c5471d85b074439c4d497d3135716faa0a01 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Fri, 25 Apr 2025 22:56:25 +0300 Subject: [PATCH] feat: type container added back for field/property serialization --- .../Converters/SerializedClassConverter.cs | 72 +++++++++++++++++++ .../Serialization/Converters/TypeContainer.cs | 13 ++++ .../Converters/TypeContainerConverter.cs | 47 ++++++++++++ Engine.Core/Serialization/Serializer.cs | 5 ++ 4 files changed, 137 insertions(+) create mode 100644 Engine.Core/Serialization/Converters/SerializedClassConverter.cs create mode 100644 Engine.Core/Serialization/Converters/TypeContainer.cs create mode 100644 Engine.Core/Serialization/Converters/TypeContainerConverter.cs diff --git a/Engine.Core/Serialization/Converters/SerializedClassConverter.cs b/Engine.Core/Serialization/Converters/SerializedClassConverter.cs new file mode 100644 index 0000000..b43c6d4 --- /dev/null +++ b/Engine.Core/Serialization/Converters/SerializedClassConverter.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Syntriax.Engine.Core.Factory; + +using YamlDotNet.Core; +using YamlDotNet.Core.Events; +using YamlDotNet.Serialization; + +namespace Syntriax.Engine.Core.Serialization; + +public class SerializedClassConverter : IEngineTypeYamlConverter +{ + public bool Accepts(Type type) => type == typeof(SerializedClass); + + public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer) + { + SerializedClass serializedClass = new(); + + parser.Consume(); + + if (parser.Consume().Value.CompareTo(nameof(SerializedClass.Type)) != 0) + throw new(); + serializedClass.Type = parser.Consume().Value; + + if (parser.Consume().Value.CompareTo(nameof(SerializedClass.Public)) != 0) + throw new(); + Dictionary publicDictionary = (Dictionary)rootDeserializer(typeof(Dictionary))!; + + if (parser.Consume().Value.CompareTo(nameof(SerializedClass.Private)) != 0) + throw new(); + Dictionary privateDictionary = (Dictionary)rootDeserializer(typeof(Dictionary))!; + + parser.Consume(); + + foreach ((string key, TypeContainer typeContainer) in publicDictionary) + serializedClass.Public.Add(key, Serializer.Deserialize(typeContainer.Value!.ToString()!, TypeFactory.GetType(typeContainer.Type))); + + foreach ((string key, TypeContainer typeContainer) in privateDictionary) + serializedClass.Private.Add(key, Serializer.Deserialize(typeContainer.Value!.ToString()!, TypeFactory.GetType(typeContainer.Type))); + + return serializedClass; + } + + public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer) + { + SerializedClass serializedClass = (SerializedClass)value!; + + Dictionary publics = []; + Dictionary privates = []; + + foreach ((string key, object? @object) in serializedClass.Public.Where(v => !v.GetType().HasAttribute())) + publics.Add(key, new TypeContainer(@object)); + + foreach ((string key, object? @object) in serializedClass.Private.Where(v => !v.GetType().HasAttribute())) + privates.Add(key, new TypeContainer(@object)); + + emitter.Emit(new MappingStart()); + + emitter.Emit(new Scalar(nameof(SerializedClass.Type))); + emitter.Emit(new Scalar(serializedClass.Type)); + + emitter.Emit(new Scalar(nameof(SerializedClass.Public))); + serializer(publics); + + emitter.Emit(new Scalar(nameof(SerializedClass.Private))); + serializer(privates); + + emitter.Emit(new MappingEnd()); + } +} diff --git a/Engine.Core/Serialization/Converters/TypeContainer.cs b/Engine.Core/Serialization/Converters/TypeContainer.cs new file mode 100644 index 0000000..7179745 --- /dev/null +++ b/Engine.Core/Serialization/Converters/TypeContainer.cs @@ -0,0 +1,13 @@ +using System; + +namespace Syntriax.Engine.Core.Serialization; + +public class TypeContainer +{ + public object? Value { get; set; } = string.Empty; + public string Type { get; set; } = string.Empty; + + public TypeContainer() { } + public TypeContainer(Type type) { Type = type.FullName ?? string.Empty; } + public TypeContainer(object? value) { Value = value; Type = value?.GetType().FullName ?? string.Empty; } +} diff --git a/Engine.Core/Serialization/Converters/TypeContainerConverter.cs b/Engine.Core/Serialization/Converters/TypeContainerConverter.cs new file mode 100644 index 0000000..2acf200 --- /dev/null +++ b/Engine.Core/Serialization/Converters/TypeContainerConverter.cs @@ -0,0 +1,47 @@ +using System; + +using Syntriax.Engine.Core.Factory; + +using YamlDotNet.Core; +using YamlDotNet.Core.Events; +using YamlDotNet.Serialization; + +namespace Syntriax.Engine.Core.Serialization; + +public class TypeContainerConverter : IEngineTypeYamlConverter +{ + public bool Accepts(Type type) => type == typeof(TypeContainer); + + public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer) + { + parser.Consume(); + + if (parser.Consume().Value.CompareTo(nameof(TypeContainer.Type)) != 0) + throw new ArgumentException($"{nameof(TypeContainer)} mapping must start with {nameof(TypeContainer.Type)}"); + string typeFullName = parser.Consume().Value; + + if (parser.Consume().Value.CompareTo(nameof(TypeContainer.Value)) != 0) + throw new ArgumentException($"{nameof(TypeContainer)} mapping must end with {nameof(TypeContainer.Type)}"); + + object? value = rootDeserializer(TypeFactory.GetType(typeFullName)); + + parser.Consume(); + + return new TypeContainer() { Type = typeFullName, Value = value }; + } + + public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer) + { + TypeContainer? typeContainer = (TypeContainer)value!; + + emitter.Emit(new MappingStart()); + + emitter.Emit(new Scalar(nameof(TypeContainer.Type))); + emitter.Emit(new Scalar(typeContainer.Type)); + + emitter.Emit(new Scalar(nameof(TypeContainer.Value))); + serializer(typeContainer.Value, TypeFactory.GetType(typeContainer.Type)); + + emitter.Emit(new MappingEnd()); + } +} diff --git a/Engine.Core/Serialization/Serializer.cs b/Engine.Core/Serialization/Serializer.cs index 6933fc7..466ac82 100644 --- a/Engine.Core/Serialization/Serializer.cs +++ b/Engine.Core/Serialization/Serializer.cs @@ -51,6 +51,11 @@ public static class Serializer return deserializer.Deserialize(yaml)!; } + public static object Deserialize(string yaml, Type type) + { + return deserializer.Deserialize(yaml, type)!; + } + public static T Deserialize(string yaml) { return deserializer.Deserialize(yaml);