feat: added primitive serialization
This commit is contained in:
parent
c205e710bc
commit
eb454a471c
41
Engine.Serialization/Converters/AABBConverter.cs
Normal file
41
Engine.Serialization/Converters/AABBConverter.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
using YamlDotNet.Core;
|
||||
using YamlDotNet.Core.Events;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Syntriax.Engine.Serialization;
|
||||
|
||||
public class AABBConverter : IEngineTypeYamlConverter
|
||||
{
|
||||
public bool Accepts(Type type) => type == typeof(AABB);
|
||||
|
||||
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
|
||||
{
|
||||
parser.Consume<MappingStart>();
|
||||
|
||||
if (parser.Consume<Scalar>().Value.CompareTo(nameof(AABB.LowerBoundary)) != 0)
|
||||
throw new ArgumentException($"{nameof(AABB)} mapping must start with {nameof(AABB.LowerBoundary)}");
|
||||
Vector2D lowerBoundary = (Vector2D)rootDeserializer(typeof(Vector2D))!;
|
||||
|
||||
if (parser.Consume<Scalar>().Value.CompareTo(nameof(AABB.UpperBoundary)) != 0)
|
||||
throw new ArgumentException($"{nameof(AABB)} mapping must end with {nameof(AABB.UpperBoundary)}");
|
||||
Vector2D upperBoundary = (Vector2D)rootDeserializer(typeof(Vector2D))!;
|
||||
|
||||
parser.Consume<MappingEnd>();
|
||||
|
||||
return new AABB(lowerBoundary, upperBoundary);
|
||||
}
|
||||
|
||||
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
|
||||
{
|
||||
AABB aabb = (AABB)value!;
|
||||
|
||||
emitter.Emit(new MappingStart());
|
||||
emitter.Emit(new Scalar(nameof(AABB.LowerBoundary)));
|
||||
serializer(aabb.LowerBoundary, typeof(Vector2D));
|
||||
emitter.Emit(new Scalar(nameof(AABB.UpperBoundary)));
|
||||
serializer(aabb.UpperBoundary, typeof(Vector2D));
|
||||
emitter.Emit(new MappingEnd());
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Syntriax.Engine.Serialization;
|
||||
|
||||
public interface IEngineTypeYamlConverter : IYamlTypeConverter;
|
41
Engine.Serialization/Converters/CircleConverter.cs
Normal file
41
Engine.Serialization/Converters/CircleConverter.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
using YamlDotNet.Core;
|
||||
using YamlDotNet.Core.Events;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Syntriax.Engine.Serialization;
|
||||
|
||||
public class CircleConverter : IEngineTypeYamlConverter
|
||||
{
|
||||
public bool Accepts(Type type) => type == typeof(Circle);
|
||||
|
||||
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
|
||||
{
|
||||
parser.Consume<MappingStart>();
|
||||
|
||||
if (parser.Consume<Scalar>().Value.CompareTo(nameof(Circle.Center)) != 0)
|
||||
throw new ArgumentException($"{nameof(Circle)} mapping must start with {nameof(Circle.Center)}");
|
||||
Vector2D lowerBoundary = (Vector2D)rootDeserializer(typeof(Vector2D))!;
|
||||
|
||||
if (parser.Consume<Scalar>().Value.CompareTo(nameof(Circle.Radius)) != 0)
|
||||
throw new ArgumentException($"{nameof(Circle)} mapping must end with {nameof(Circle.Radius)}");
|
||||
float radius = (float)rootDeserializer(typeof(float))!;
|
||||
|
||||
parser.Consume<MappingEnd>();
|
||||
|
||||
return new Circle(lowerBoundary, radius);
|
||||
}
|
||||
|
||||
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
|
||||
{
|
||||
Circle circle = (Circle)value!;
|
||||
|
||||
emitter.Emit(new MappingStart());
|
||||
emitter.Emit(new Scalar(nameof(Circle.Center)));
|
||||
serializer(circle.Center, typeof(Vector2D));
|
||||
emitter.Emit(new Scalar(nameof(Circle.Radius)));
|
||||
serializer(circle.Radius, typeof(float));
|
||||
emitter.Emit(new MappingEnd());
|
||||
}
|
||||
}
|
41
Engine.Serialization/Converters/Line2DConverter.cs
Normal file
41
Engine.Serialization/Converters/Line2DConverter.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
using YamlDotNet.Core;
|
||||
using YamlDotNet.Core.Events;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Syntriax.Engine.Serialization;
|
||||
|
||||
public class Line2DConverter : IEngineTypeYamlConverter
|
||||
{
|
||||
public bool Accepts(Type type) => type == typeof(Line2D);
|
||||
|
||||
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
|
||||
{
|
||||
parser.Consume<MappingStart>();
|
||||
|
||||
if (parser.Consume<Scalar>().Value.CompareTo(nameof(Line2D.From)) != 0)
|
||||
throw new ArgumentException($"{nameof(Line2D)} mapping must start with {nameof(Line2D.From)}");
|
||||
Vector2D from = (Vector2D)rootDeserializer(typeof(Vector2D))!;
|
||||
|
||||
if (parser.Consume<Scalar>().Value.CompareTo(nameof(Line2D.To)) != 0)
|
||||
throw new ArgumentException($"{nameof(Line2D)} mapping must end with {nameof(Line2D.To)}");
|
||||
Vector2D to = (Vector2D)rootDeserializer(typeof(Vector2D))!;
|
||||
|
||||
parser.Consume<MappingEnd>();
|
||||
|
||||
return new Line2D(from, to);
|
||||
}
|
||||
|
||||
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
|
||||
{
|
||||
Line2D line2D = (Line2D)value!;
|
||||
|
||||
emitter.Emit(new MappingStart());
|
||||
emitter.Emit(new Scalar(nameof(Line2D.From)));
|
||||
serializer(line2D.From, typeof(Vector2D));
|
||||
emitter.Emit(new Scalar(nameof(Line2D.To)));
|
||||
serializer(line2D.To, typeof(Vector2D));
|
||||
emitter.Emit(new MappingEnd());
|
||||
}
|
||||
}
|
41
Engine.Serialization/Converters/Line2DEquationConverter.cs
Normal file
41
Engine.Serialization/Converters/Line2DEquationConverter.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
using YamlDotNet.Core;
|
||||
using YamlDotNet.Core.Events;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Syntriax.Engine.Serialization;
|
||||
|
||||
public class Line2DEquationConverter : IEngineTypeYamlConverter
|
||||
{
|
||||
public bool Accepts(Type type) => type == typeof(Line2DEquation);
|
||||
|
||||
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
|
||||
{
|
||||
parser.Consume<MappingStart>();
|
||||
|
||||
if (parser.Consume<Scalar>().Value.CompareTo(nameof(Line2DEquation.Slope)) != 0)
|
||||
throw new ArgumentException($"{nameof(Line2DEquation)} mapping must start with {nameof(Line2DEquation.Slope)}");
|
||||
float slope = (float)rootDeserializer(typeof(float))!;
|
||||
|
||||
if (parser.Consume<Scalar>().Value.CompareTo(nameof(Line2DEquation.OffsetY)) != 0)
|
||||
throw new ArgumentException($"{nameof(Line2DEquation)} mapping must end with {nameof(Line2DEquation.OffsetY)}");
|
||||
float offset = (float)rootDeserializer(typeof(float))!;
|
||||
|
||||
parser.Consume<MappingEnd>();
|
||||
|
||||
return new Line2DEquation(slope, offset);
|
||||
}
|
||||
|
||||
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
|
||||
{
|
||||
Line2DEquation line2DEquation = (Line2DEquation)value!;
|
||||
|
||||
emitter.Emit(new MappingStart());
|
||||
emitter.Emit(new Scalar(nameof(Line2DEquation.Slope)));
|
||||
serializer(line2DEquation.Slope, typeof(float));
|
||||
emitter.Emit(new Scalar(nameof(Line2DEquation.OffsetY)));
|
||||
serializer(line2DEquation.OffsetY, typeof(float));
|
||||
emitter.Emit(new MappingEnd());
|
||||
}
|
||||
}
|
41
Engine.Serialization/Converters/Projection1DConverter.cs
Normal file
41
Engine.Serialization/Converters/Projection1DConverter.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
using YamlDotNet.Core;
|
||||
using YamlDotNet.Core.Events;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Syntriax.Engine.Serialization;
|
||||
|
||||
public class Projection1DConverter : IEngineTypeYamlConverter
|
||||
{
|
||||
public bool Accepts(Type type) => type == typeof(Projection1D);
|
||||
|
||||
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
|
||||
{
|
||||
parser.Consume<MappingStart>();
|
||||
|
||||
if (parser.Consume<Scalar>().Value.CompareTo(nameof(Projection1D.Min)) != 0)
|
||||
throw new ArgumentException($"{nameof(Projection1D)} mapping must start with {nameof(Projection1D.Min)}");
|
||||
float min = (float)rootDeserializer(typeof(float))!;
|
||||
|
||||
if (parser.Consume<Scalar>().Value.CompareTo(nameof(Projection1D.Max)) != 0)
|
||||
throw new ArgumentException($"{nameof(Projection1D)} mapping must end with {nameof(Projection1D.Max)}");
|
||||
float max = (float)rootDeserializer(typeof(float))!;
|
||||
|
||||
parser.Consume<MappingEnd>();
|
||||
|
||||
return new Projection1D(min, max);
|
||||
}
|
||||
|
||||
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
|
||||
{
|
||||
Projection1D projection1D = (Projection1D)value!;
|
||||
|
||||
emitter.Emit(new MappingStart());
|
||||
emitter.Emit(new Scalar(nameof(Projection1D.Min)));
|
||||
serializer(projection1D.Min, typeof(float));
|
||||
emitter.Emit(new Scalar(nameof(Projection1D.Max)));
|
||||
serializer(projection1D.Max, typeof(float));
|
||||
emitter.Emit(new MappingEnd());
|
||||
}
|
||||
}
|
28
Engine.Serialization/Converters/QuaternionConverter.cs
Normal file
28
Engine.Serialization/Converters/QuaternionConverter.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
using YamlDotNet.Core;
|
||||
using YamlDotNet.Core.Events;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Syntriax.Engine.Serialization;
|
||||
|
||||
public class QuaternionConverter : IEngineTypeYamlConverter
|
||||
{
|
||||
private static readonly int SUBSTRING_START_LENGTH = nameof(Quaternion).Length + 1;
|
||||
|
||||
public bool Accepts(Type type) => type == typeof(Quaternion);
|
||||
|
||||
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
|
||||
{
|
||||
string value = parser.Consume<Scalar>().Value;
|
||||
string insideParenthesis = value[SUBSTRING_START_LENGTH..^1];
|
||||
string[] values = insideParenthesis.Split(", ");
|
||||
return new Quaternion(float.Parse(values[0]), float.Parse(values[1]), float.Parse(values[2]), float.Parse(values[3]));
|
||||
}
|
||||
|
||||
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
|
||||
{
|
||||
Quaternion quaternion = (Quaternion)value!;
|
||||
emitter.Emit(new Scalar($"{nameof(Quaternion)}({quaternion.X}, {quaternion.Y}, {quaternion.Z}, {quaternion.W})"));
|
||||
}
|
||||
}
|
47
Engine.Serialization/Converters/Shape2DConverter.cs
Normal file
47
Engine.Serialization/Converters/Shape2DConverter.cs
Normal file
@ -0,0 +1,47 @@
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
using YamlDotNet.Core;
|
||||
using YamlDotNet.Core.Events;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Syntriax.Engine.Serialization;
|
||||
|
||||
public class Shape2DConverter : IEngineTypeYamlConverter
|
||||
{
|
||||
public bool Accepts(Type type) => type == typeof(Shape2D);
|
||||
|
||||
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
|
||||
{
|
||||
parser.Consume<MappingStart>();
|
||||
|
||||
if (parser.Consume<Scalar>().Value.CompareTo(nameof(Shape2D.Vertices)) != 0)
|
||||
throw new ArgumentException($"{nameof(Shape2D)} mapping have a {nameof(Shape2D.Vertices)}");
|
||||
|
||||
parser.Consume<SequenceStart>();
|
||||
|
||||
List<Vector2D> vertices = [];
|
||||
|
||||
while (!parser.TryConsume<SequenceEnd>(out _))
|
||||
{
|
||||
Vector2D vertex = (Vector2D)rootDeserializer(typeof(Vector2D))!;
|
||||
vertices.Add(vertex);
|
||||
}
|
||||
|
||||
parser.Consume<MappingEnd>();
|
||||
|
||||
return new Shape2D(vertices);
|
||||
}
|
||||
|
||||
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
|
||||
{
|
||||
Shape2D shape2D = (Shape2D)value!;
|
||||
|
||||
emitter.Emit(new MappingStart());
|
||||
emitter.Emit(new Scalar(nameof(Shape2D.Vertices)));
|
||||
emitter.Emit(new SequenceStart(anchor: null, tag: null, isImplicit: false, style: SequenceStyle.Block));
|
||||
foreach (Vector2D vertex in shape2D.Vertices)
|
||||
serializer(vertex, typeof(Vector2D));
|
||||
emitter.Emit(new SequenceEnd());
|
||||
emitter.Emit(new MappingEnd());
|
||||
}
|
||||
}
|
47
Engine.Serialization/Converters/TriangleConverter.cs
Normal file
47
Engine.Serialization/Converters/TriangleConverter.cs
Normal file
@ -0,0 +1,47 @@
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
using YamlDotNet.Core;
|
||||
using YamlDotNet.Core.Events;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Syntriax.Engine.Serialization;
|
||||
|
||||
public class TriangleConverter : IEngineTypeYamlConverter
|
||||
{
|
||||
public bool Accepts(Type type) => type == typeof(Triangle);
|
||||
|
||||
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
|
||||
{
|
||||
parser.Consume<MappingStart>();
|
||||
|
||||
if (parser.Consume<Scalar>().Value.CompareTo(nameof(Triangle.A)) != 0)
|
||||
throw new ArgumentException($"{nameof(Triangle)} mapping must start with {nameof(Triangle.A)}");
|
||||
Vector2D a = (Vector2D)rootDeserializer(typeof(Vector2D))!;
|
||||
|
||||
if (parser.Consume<Scalar>().Value.CompareTo(nameof(Triangle.B)) != 0)
|
||||
throw new ArgumentException($"{nameof(Triangle)} mapping must have {nameof(Triangle.B)} after {nameof(Triangle.A)}");
|
||||
Vector2D b = (Vector2D)rootDeserializer(typeof(Vector2D))!;
|
||||
|
||||
if (parser.Consume<Scalar>().Value.CompareTo(nameof(Triangle.C)) != 0)
|
||||
throw new ArgumentException($"{nameof(Triangle)} mapping must end with {nameof(Triangle.C)}");
|
||||
Vector2D c = (Vector2D)rootDeserializer(typeof(Vector2D))!;
|
||||
|
||||
parser.Consume<MappingEnd>();
|
||||
|
||||
return new Triangle(a, b, c);
|
||||
}
|
||||
|
||||
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
|
||||
{
|
||||
Triangle aabb = (Triangle)value!;
|
||||
|
||||
emitter.Emit(new MappingStart());
|
||||
emitter.Emit(new Scalar(nameof(Triangle.A)));
|
||||
serializer(aabb.A, typeof(Vector2D));
|
||||
emitter.Emit(new Scalar(nameof(Triangle.B)));
|
||||
serializer(aabb.B, typeof(Vector2D));
|
||||
emitter.Emit(new Scalar(nameof(Triangle.C)));
|
||||
serializer(aabb.C, typeof(Vector2D));
|
||||
emitter.Emit(new MappingEnd());
|
||||
}
|
||||
}
|
28
Engine.Serialization/Converters/Vector2DConverter.cs
Normal file
28
Engine.Serialization/Converters/Vector2DConverter.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
using YamlDotNet.Core;
|
||||
using YamlDotNet.Core.Events;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Syntriax.Engine.Serialization;
|
||||
|
||||
public class Vector2DConverter : IEngineTypeYamlConverter
|
||||
{
|
||||
private static readonly int SUBSTRING_START_LENGTH = nameof(Vector2D).Length + 1;
|
||||
|
||||
public bool Accepts(Type type) => type == typeof(Vector2D);
|
||||
|
||||
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
|
||||
{
|
||||
string value = parser.Consume<Scalar>().Value;
|
||||
string insideParenthesis = value[SUBSTRING_START_LENGTH..^1];
|
||||
string[] values = insideParenthesis.Split(", ");
|
||||
return new Vector2D(float.Parse(values[0]), float.Parse(values[1]));
|
||||
}
|
||||
|
||||
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
|
||||
{
|
||||
Vector2D vector2D = (Vector2D)value!;
|
||||
emitter.Emit(new Scalar($"{nameof(Vector2D)}({vector2D.X}, {vector2D.Y})"));
|
||||
}
|
||||
}
|
28
Engine.Serialization/Converters/Vector3DConverter.cs
Normal file
28
Engine.Serialization/Converters/Vector3DConverter.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
using YamlDotNet.Core;
|
||||
using YamlDotNet.Core.Events;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Syntriax.Engine.Serialization;
|
||||
|
||||
public class Vector3DConverter : IEngineTypeYamlConverter
|
||||
{
|
||||
private static readonly int SUBSTRING_START_LENGTH = nameof(Vector3D).Length + 1;
|
||||
|
||||
public bool Accepts(Type type) => type == typeof(Vector3D);
|
||||
|
||||
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
|
||||
{
|
||||
string value = parser.Consume<Scalar>().Value;
|
||||
string insideParenthesis = value[SUBSTRING_START_LENGTH..^1];
|
||||
string[] values = insideParenthesis.Split(", ");
|
||||
return new Vector3D(float.Parse(values[0]), float.Parse(values[1]), float.Parse(values[2]));
|
||||
}
|
||||
|
||||
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
|
||||
{
|
||||
Vector3D vector3D = (Vector3D)value!;
|
||||
emitter.Emit(new Scalar($"{nameof(Vector3D)}({vector3D.X}, {vector3D.Y}, {vector3D.Z})"));
|
||||
}
|
||||
}
|
@ -1,172 +0,0 @@
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
using YamlDotNet.Core;
|
||||
using YamlDotNet.Core.Events;
|
||||
using YamlDotNet.Serialization;
|
||||
using YamlDotNet.Serialization.NamingConventions;
|
||||
|
||||
namespace Syntriax.Engine.Serialization;
|
||||
|
||||
public class Vector2DConverter : IYamlTypeConverter
|
||||
{
|
||||
public bool Accepts(Type type)
|
||||
{
|
||||
return type == typeof(Vector2D);
|
||||
}
|
||||
|
||||
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
|
||||
{
|
||||
parser.Consume<MappingStart>();
|
||||
|
||||
float x = 0f;
|
||||
float y = 0f;
|
||||
|
||||
while (!parser.TryConsume<MappingEnd>(out _))
|
||||
{
|
||||
string key = parser.Consume<Scalar>().Value;
|
||||
string value = parser.Consume<Scalar>().Value;
|
||||
|
||||
if (key.CompareTo(nameof(Vector2D.X)) == 0) x = float.Parse(value);
|
||||
if (key.CompareTo(nameof(Vector2D.Y)) == 0) y = float.Parse(value);
|
||||
}
|
||||
|
||||
return new Vector2D(x, y);
|
||||
}
|
||||
|
||||
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
|
||||
{
|
||||
Vector2D vector2D = (Vector2D)value!;
|
||||
|
||||
emitter.Emit(new MappingStart());
|
||||
emitter.Emit(new Scalar(nameof(Vector2D.X)));
|
||||
emitter.Emit(new Scalar(vector2D.X.ToString()));
|
||||
emitter.Emit(new Scalar(nameof(Vector2D.Y)));
|
||||
emitter.Emit(new Scalar(vector2D.Y.ToString()));
|
||||
emitter.Emit(new MappingEnd());
|
||||
}
|
||||
}
|
||||
|
||||
public class EntityConverter : IYamlTypeConverter
|
||||
{
|
||||
private static readonly ISerializer serializer = new SerializerBuilder()
|
||||
.WithNamingConvention(PascalCaseNamingConvention.Instance)
|
||||
.DisableAliases()
|
||||
.Build();
|
||||
|
||||
private static readonly IDeserializer deserializer = new DeserializerBuilder()
|
||||
.WithNamingConvention(PascalCaseNamingConvention.Instance)
|
||||
.Build();
|
||||
|
||||
public bool Accepts(Type type)
|
||||
{
|
||||
bool v = typeof(IEntity).IsAssignableFrom(type);
|
||||
return v;
|
||||
}
|
||||
|
||||
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
|
||||
{
|
||||
string? id = null;
|
||||
|
||||
parser.Consume<MappingStart>();
|
||||
|
||||
while (!parser.TryConsume<MappingEnd>(out _))
|
||||
{
|
||||
string key = parser.Consume<Scalar>().Value;
|
||||
string value = parser.Consume<Scalar>().Value;
|
||||
|
||||
if (key.CompareTo(nameof(EntityReference.Id)) == 0)
|
||||
id = value;
|
||||
}
|
||||
|
||||
return new EntityReference() { Id = id };
|
||||
}
|
||||
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
|
||||
{
|
||||
if (value is not IEntity entity)
|
||||
return;
|
||||
|
||||
var typeData = GetTypeData(type);
|
||||
emitter.Emit(new MappingStart());
|
||||
|
||||
foreach (var fieldInfo in typeData.Fields)
|
||||
{
|
||||
if (fieldInfo.GetCustomAttribute<System.Runtime.CompilerServices.CompilerGeneratedAttribute>() != null)
|
||||
continue;
|
||||
|
||||
emitter.Emit(new Scalar(fieldInfo.Name));
|
||||
var fieldValue = fieldInfo.GetValue(entity);
|
||||
|
||||
EmitValue(fieldValue, fieldInfo.FieldType, emitter, serializer);
|
||||
}
|
||||
|
||||
foreach (var propertyInfo in typeData.Properties)
|
||||
{
|
||||
emitter.Emit(new Scalar(propertyInfo.Name));
|
||||
var propValue = propertyInfo.GetValue(entity);
|
||||
|
||||
EmitValue(propValue, propertyInfo.PropertyType, emitter, serializer);
|
||||
}
|
||||
|
||||
emitter.Emit(new MappingEnd());
|
||||
}
|
||||
private void EmitValue(object? value, Type declaredType, IEmitter emitter, ObjectSerializer serializer)
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
emitter.Emit(new Scalar("null"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (value is IEntity singleEntity && !IsEnumerable(declaredType))
|
||||
{
|
||||
emitter.Emit(new Scalar(singleEntity.Id));
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsEnumerable(declaredType) && value is System.Collections.IEnumerable list)
|
||||
{
|
||||
emitter.Emit(new SequenceStart(null, null, false, SequenceStyle.Block));
|
||||
foreach (var item in list)
|
||||
{
|
||||
if (item is IEntity itemEntity)
|
||||
emitter.Emit(new Scalar(itemEntity.Id));
|
||||
else
|
||||
serializer(item); // fallback for non-entity items
|
||||
}
|
||||
emitter.Emit(new SequenceEnd());
|
||||
return;
|
||||
}
|
||||
|
||||
// fallback
|
||||
serializer(value);
|
||||
}
|
||||
private static TypeData GetTypeData(Type objectType)
|
||||
{
|
||||
IEnumerable<System.Reflection.EventInfo> eventInfos = objectType.GetEvents(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
|
||||
.OrderBy(ei => ei.Name)
|
||||
.AsEnumerable();
|
||||
IEnumerable<FieldInfo> fieldInfos = objectType.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
|
||||
.Where(fi => !eventInfos.Any(ei => fi.Name.CompareTo(ei.Name) == 0))
|
||||
.OrderBy(ei => ei.Name) //ei => ei.FieldType.IsPrimitive || ei.FieldType == typeof(string))
|
||||
// .ThenByDescending(ei => ei.Name)
|
||||
.AsEnumerable();
|
||||
IEnumerable<PropertyInfo> propertyInfos = objectType.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
|
||||
.Where(pi => pi.SetMethod is not null)
|
||||
.OrderBy(ei => ei.Name)// ei => ei.PropertyType.IsPrimitive || ei.PropertyType == typeof(string))
|
||||
// .ThenByDescending(ei => ei.Name)
|
||||
.AsEnumerable();
|
||||
|
||||
return new TypeData(eventInfos, fieldInfos, propertyInfos);
|
||||
}
|
||||
private static bool IsEnumerable(Type type)
|
||||
{
|
||||
return typeof(System.Collections.IEnumerable).IsAssignableFrom(type) && type != typeof(string);
|
||||
}
|
||||
private record struct TypeData(IEnumerable<System.Reflection.EventInfo> Events, IEnumerable<FieldInfo> Fields, IEnumerable<PropertyInfo> Properties)
|
||||
{
|
||||
public static implicit operator (IEnumerable<System.Reflection.EventInfo> events, IEnumerable<FieldInfo> fields, IEnumerable<PropertyInfo> properties)(TypeData value) => (value.Events, value.Fields, value.Properties);
|
||||
public static implicit operator TypeData((IEnumerable<System.Reflection.EventInfo> events, IEnumerable<FieldInfo> fields, IEnumerable<PropertyInfo> properties) value) => new TypeData(value.events, value.fields, value.properties);
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
namespace Syntriax.Engine.Serialization;
|
||||
|
||||
public class EntityReference
|
||||
{
|
||||
public string Id { get; set; }
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
using System.Reflection;
|
||||
using YamlDotNet.Serialization;
|
||||
using YamlDotNet.Serialization.NamingConventions;
|
||||
|
||||
@ -5,24 +6,47 @@ namespace Syntriax.Engine.Serialization;
|
||||
|
||||
public static class Serializer
|
||||
{
|
||||
private static readonly ISerializer serializer = new SerializerBuilder()
|
||||
.WithNamingConvention(PascalCaseNamingConvention.Instance)
|
||||
.DisableAliases()
|
||||
.WithTypeConverter(new EntityConverter())
|
||||
.WithTypeConverter(new Vector2DConverter())
|
||||
.Build();
|
||||
private static readonly ISerializer serializer = GetSerializer();
|
||||
private static ISerializer GetSerializer()
|
||||
{
|
||||
SerializerBuilder serializerBuilder = new SerializerBuilder()
|
||||
.WithNamingConvention(PascalCaseNamingConvention.Instance)
|
||||
.DisableAliases();
|
||||
|
||||
private static readonly IDeserializer deserializer = new DeserializerBuilder()
|
||||
.WithNamingConvention(PascalCaseNamingConvention.Instance)
|
||||
.WithTypeConverter(new EntityConverter())
|
||||
.WithTypeConverter(new Vector2DConverter())
|
||||
.Build();
|
||||
foreach (IEngineTypeYamlConverter typeConverter in GetEngineYamlTypeConverters())
|
||||
serializerBuilder = serializerBuilder.WithTypeConverter(typeConverter);
|
||||
|
||||
return serializerBuilder.Build();
|
||||
}
|
||||
|
||||
private static readonly IDeserializer deserializer = GetDeserializer();
|
||||
private static IDeserializer GetDeserializer()
|
||||
{
|
||||
DeserializerBuilder serializerBuilder = new DeserializerBuilder()
|
||||
.WithNamingConvention(PascalCaseNamingConvention.Instance);
|
||||
|
||||
foreach (IEngineTypeYamlConverter typeConverter in GetEngineYamlTypeConverters())
|
||||
serializerBuilder = serializerBuilder.WithTypeConverter(typeConverter);
|
||||
|
||||
return serializerBuilder.Build();
|
||||
}
|
||||
|
||||
private static IEnumerable<IEngineTypeYamlConverter> GetEngineYamlTypeConverters()
|
||||
{
|
||||
foreach (Type type in Assembly.GetExecutingAssembly().GetTypes().Where(t => typeof(IEngineTypeYamlConverter).IsAssignableFrom(t) && t.IsClass && !t.IsAbstract))
|
||||
yield return (Activator.CreateInstance(type) as IEngineTypeYamlConverter)!;
|
||||
}
|
||||
|
||||
public static string Serialize(object instance)
|
||||
{
|
||||
return serializer.Serialize(instance);
|
||||
}
|
||||
|
||||
public static object Deserialize(string yaml)
|
||||
{
|
||||
return deserializer.Deserialize(yaml)!;
|
||||
}
|
||||
|
||||
public static T Deserialize<T>(string yaml)
|
||||
{
|
||||
return deserializer.Deserialize<T>(yaml);
|
||||
|
31
Engine.Serialization/Utils.cs
Normal file
31
Engine.Serialization/Utils.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using System.Reflection;
|
||||
|
||||
namespace Syntriax.Engine.Serialization;
|
||||
|
||||
internal static class Utils
|
||||
{
|
||||
internal static TypeData GetTypeData(this Type type)
|
||||
{
|
||||
IEnumerable<EventInfo> eventInfos = type.GetEvents(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
|
||||
.OrderBy(ei => ei.Name)
|
||||
.AsEnumerable();
|
||||
IEnumerable<FieldInfo> fieldInfos = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
|
||||
.Where(fi => !eventInfos.Any(ei => fi.Name.CompareTo(ei.Name) == 0))
|
||||
.OrderBy(ei => ei.Name) //ei => ei.FieldType.IsPrimitive || ei.FieldType == typeof(string))
|
||||
// .ThenByDescending(ei => ei.Name)
|
||||
.AsEnumerable();
|
||||
IEnumerable<PropertyInfo> propertyInfos = type.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
|
||||
.Where(pi => pi.SetMethod is not null)
|
||||
.OrderBy(ei => ei.Name)// ei => ei.PropertyType.IsPrimitive || ei.PropertyType == typeof(string))
|
||||
// .ThenByDescending(ei => ei.Name)
|
||||
.AsEnumerable();
|
||||
|
||||
return new TypeData(eventInfos, fieldInfos, propertyInfos);
|
||||
}
|
||||
}
|
||||
|
||||
internal record struct TypeData(IEnumerable<EventInfo> Events, IEnumerable<FieldInfo> Fields, IEnumerable<PropertyInfo> Properties)
|
||||
{
|
||||
public static implicit operator (IEnumerable<EventInfo> events, IEnumerable<FieldInfo> fields, IEnumerable<PropertyInfo> properties)(TypeData value) => (value.Events, value.Fields, value.Properties);
|
||||
public static implicit operator TypeData((IEnumerable<EventInfo> events, IEnumerable<FieldInfo> fields, IEnumerable<PropertyInfo> properties) value) => new TypeData(value.events, value.fields, value.properties);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user