chore: experimentations

This commit is contained in:
Syntriax 2025-04-23 23:20:00 +03:00
parent 2637f99456
commit 35a75d993b
5 changed files with 55 additions and 33 deletions

View File

@ -1,6 +1,6 @@
using System.Collections; using System.Collections;
using System.Reflection; using System.Reflection;
using Syntriax.Engine.Core;
using Syntriax.Engine.Core.Factory; using Syntriax.Engine.Core.Factory;
using YamlDotNet.Core; using YamlDotNet.Core;
@ -9,17 +9,15 @@ using YamlDotNet.Serialization;
namespace Syntriax.Engine.Serialization; namespace Syntriax.Engine.Serialization;
public class InstanceConverter : IEngineTypeYamlConverter public class EntityConverter(IReadOnlyDictionary<string, IEntity> entities) : IYamlTypeConverter
{ {
private int depth = 0; private readonly IReadOnlyDictionary<string, IEntity> Entities = entities;
private int maxDepth = 5; private readonly HashSet<IEntity> entitiesVisited = [];
public bool Accepts(Type type) => !type.IsPrimitive && type != typeof(string); public bool Accepts(Type type) => typeof(IEntity).IsAssignableFrom(type);
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer) public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
{ {
if (depth > maxDepth)
return null;
parser.Consume<MappingStart>(); parser.Consume<MappingStart>();
TypeContainer typeContainer = (TypeContainer)rootDeserializer(typeof(TypeContainer))!; TypeContainer typeContainer = (TypeContainer)rootDeserializer(typeof(TypeContainer))!;
@ -32,16 +30,12 @@ public class InstanceConverter : IEngineTypeYamlConverter
if (type.GetField(key, BindingFlags.Instance | BindingFlags.NonPublic) is FieldInfo fieldInfo) if (type.GetField(key, BindingFlags.Instance | BindingFlags.NonPublic) is FieldInfo fieldInfo)
{ {
depth++;
object? fieldValue = rootDeserializer(fieldInfo.FieldType); object? fieldValue = rootDeserializer(fieldInfo.FieldType);
depth--;
fieldInfo.SetValue(instance, fieldValue); fieldInfo.SetValue(instance, fieldValue);
} }
else if (type.GetProperty(key) is PropertyInfo propertyInfo) else if (type.GetProperty(key) is PropertyInfo propertyInfo)
{ {
depth++;
object? propertyValue = rootDeserializer(propertyInfo.PropertyType); object? propertyValue = rootDeserializer(propertyInfo.PropertyType);
depth--;
propertyInfo.SetValue(instance, propertyValue); propertyInfo.SetValue(instance, propertyValue);
} }
else else
@ -55,6 +49,19 @@ public class InstanceConverter : IEngineTypeYamlConverter
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer) public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
{ {
if (type.HasAttribute<IgnoreSerializationAttribute>())
{
emitter.Emit(new Scalar(""));
return;
}
IEntity entity = (IEntity)value!;
if (!entitiesVisited.Add(entity))
{
emitter.Emit(new Scalar(entity.Id));
return;
}
emitter.Emit(new MappingStart()); emitter.Emit(new MappingStart());
serializer(new TypeContainer(value), typeof(TypeContainer)); serializer(new TypeContainer(value), typeof(TypeContainer));
@ -68,12 +75,7 @@ public class InstanceConverter : IEngineTypeYamlConverter
emitter.Emit(new Scalar(propertyInfo.Name)); emitter.Emit(new Scalar(propertyInfo.Name));
object? propertyValue = propertyInfo.GetValue(value); object? propertyValue = propertyInfo.GetValue(value);
depth++; EmitValue(propertyValue, propertyInfo.PropertyType, emitter, serializer);
if (depth <= maxDepth)
EmitValue(propertyValue, propertyInfo.PropertyType, emitter, serializer);
else
emitter.Emit(new Scalar("Skipped"));
depth--;
} }
foreach (FieldInfo fieldInfo in typeData.Fields) foreach (FieldInfo fieldInfo in typeData.Fields)
@ -81,18 +83,16 @@ public class InstanceConverter : IEngineTypeYamlConverter
if (fieldInfo.HasAttribute<System.Runtime.CompilerServices.CompilerGeneratedAttribute>()) if (fieldInfo.HasAttribute<System.Runtime.CompilerServices.CompilerGeneratedAttribute>())
continue; continue;
if (!fieldInfo.HasAttribute<SerializeAttribute>()) if (fieldInfo.HasAttribute<IgnoreSerializationAttribute>())
continue; continue;
// if (!fieldInfo.HasAttribute<SerializeAttribute>())
// continue;
emitter.Emit(new Scalar(fieldInfo.Name)); emitter.Emit(new Scalar(fieldInfo.Name));
object? fieldValue = fieldInfo.GetValue(value); object? fieldValue = fieldInfo.GetValue(value);
depth++; EmitValue(fieldValue, fieldInfo.FieldType, emitter, serializer);
if (depth <= maxDepth)
EmitValue(fieldValue, fieldInfo.FieldType, emitter, serializer);
else
emitter.Emit(new Scalar("Skipped"));
depth--;
} }
emitter.Emit(new MappingEnd()); emitter.Emit(new MappingEnd());
@ -106,6 +106,12 @@ public class InstanceConverter : IEngineTypeYamlConverter
return; return;
} }
if (value is IEntity entity)
{
emitter.Emit(new Scalar(entity.Id));
return;
}
bool isSequence = Utils.IsEnumerable(declaredType); bool isSequence = Utils.IsEnumerable(declaredType);
if (!isSequence) if (!isSequence)
@ -118,7 +124,10 @@ public class InstanceConverter : IEngineTypeYamlConverter
emitter.Emit(new SequenceStart(null, null, false, SequenceStyle.Block)); emitter.Emit(new SequenceStart(null, null, false, SequenceStyle.Block));
foreach (object? item in sequence) foreach (object? item in sequence)
serializer(item); if (value is IEntity sequenceEntity)
emitter.Emit(new Scalar(sequenceEntity.Id));
else
serializer(item);
emitter.Emit(new SequenceEnd()); emitter.Emit(new SequenceEnd());
} }
} }

View File

@ -7,9 +7,9 @@ namespace Syntriax.Engine.Serialization;
public class EntityFinder public class EntityFinder
{ {
private readonly HashSet<IEntity> _entities = []; private readonly Dictionary<string, IEntity> _entities = [];
public IReadOnlyCollection<IEntity> Entities => _entities; public IReadOnlyDictionary<string, IEntity> Entities => _entities;
public void FindEntitiesUnder(object @object) public void FindEntitiesUnder(object @object)
{ {
@ -23,9 +23,11 @@ public class EntityFinder
return; return;
} }
if (!_entities.Add(entity)) if (Entities.ContainsKey(entity.Id))
return; return;
_entities.Add(entity.Id, entity);
foreach (PropertyInfo propertyInfo in typeData.Properties) foreach (PropertyInfo propertyInfo in typeData.Properties)
{ {
if (propertyInfo.PropertyType?.IsPrimitive ?? true || propertyInfo.PropertyType == typeof(string)) if (propertyInfo.PropertyType?.IsPrimitive ?? true || propertyInfo.PropertyType == typeof(string))

View File

@ -1,4 +1,4 @@
namespace Syntriax.Engine.Serialization; namespace Syntriax.Engine.Serialization;
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class)] [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Class)]
public class IgnoreSerializationAttribute : Attribute; public class IgnoreSerializationAttribute : Attribute;

View File

@ -7,7 +7,7 @@ namespace Syntriax.Engine.Serialization;
public static class Serializer public static class Serializer
{ {
private static readonly ISerializer serializer = GetSerializer(); private static readonly ISerializer serializer = GetSerializer();
private static ISerializer GetSerializer() private static ISerializer GetSerializer(EntityFinder? entityFinder = null)
{ {
SerializerBuilder serializerBuilder = new SerializerBuilder() SerializerBuilder serializerBuilder = new SerializerBuilder()
.WithNamingConvention(PascalCaseNamingConvention.Instance) .WithNamingConvention(PascalCaseNamingConvention.Instance)
@ -16,6 +16,9 @@ public static class Serializer
foreach (IEngineTypeYamlConverter typeConverter in GetEngineYamlTypeConverters()) foreach (IEngineTypeYamlConverter typeConverter in GetEngineYamlTypeConverters())
serializerBuilder = serializerBuilder.WithTypeConverter(typeConverter); serializerBuilder = serializerBuilder.WithTypeConverter(typeConverter);
if (entityFinder is not null)
serializerBuilder = serializerBuilder.WithTypeConverter(new EntityConverter(entityFinder.Entities));
return serializerBuilder.Build(); return serializerBuilder.Build();
} }
@ -39,7 +42,10 @@ public static class Serializer
public static string Serialize(object instance) public static string Serialize(object instance)
{ {
return serializer.Serialize(instance); EntityFinder entityFinder = new();
entityFinder.FindEntitiesUnder(instance);
ISerializer serializer = GetSerializer(entityFinder);
return serializer.Serialize(entityFinder.Entities);
} }
public static object Deserialize(string yaml) public static object Deserialize(string yaml)

View File

@ -9,10 +9,15 @@ internal static class Utils
internal static TypeData GetTypeData(this Type objectType) internal static TypeData GetTypeData(this Type objectType)
{ {
List<FieldInfo> fieldInfos = GetFieldInfosIncludingBaseClasses(objectType, BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.NonPublic | BindingFlags.Public); List<EventInfo> eventInfos = objectType.GetEvents(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
.OrderBy(ei => ei.Name)
.ToList();
List<FieldInfo> fieldInfos = GetFieldInfosIncludingBaseClasses(objectType, BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.NonPublic | BindingFlags.Public)
.Where(pi => !eventInfos.Any(ei => pi.Name.CompareTo(ei.Name) == 0)).ToList();
List<PropertyInfo> propertyInfos = GetPropertyInfosIncludingBaseClasses(objectType, BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.Public) List<PropertyInfo> propertyInfos = GetPropertyInfosIncludingBaseClasses(objectType, BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.Public)
.Where(pi => pi.SetMethod is not null) .Where(pi => pi.SetMethod is not null && !eventInfos.Any(ei => pi.Name.CompareTo(ei.Name) == 0))
.ToList(); .ToList();
return new TypeData(fieldInfos, propertyInfos); return new TypeData(fieldInfos, propertyInfos);