Skip to content

Commit

Permalink
Merge pull request #58 from richdog/arch-json-serializer-custom-resol…
Browse files Browse the repository at this point in the history
…vers

Allow custom resolvers to (optionally) be passed into the json serializer
  • Loading branch information
genaray authored Dec 18, 2023
2 parents 6c8d173 + a8db537 commit 10ff1ba
Showing 1 changed file with 49 additions and 26 deletions.
75 changes: 49 additions & 26 deletions Arch.Persistence/Serializer.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
using System.Buffers;
using Arch.Core;
using Arch.Core.Extensions;
using Arch.Core.Extensions.Dangerous;
using Arch.Core.Utils;
using Arch.Core;
using MessagePack;
using MessagePack.Formatters;
using System.Buffers;
using Utf8Json;
using Utf8Json.Resolvers;
using DateTimeFormatter = Utf8Json.Formatters.DateTimeFormatter;
Expand All @@ -25,7 +22,7 @@ public interface IArchSerializer
/// <param name="world">The <see cref="World"/>.</param>
/// <param name="entity">The <see cref="Entity"/>.</param>
byte[] Serialize(World world, Entity entity);

/// <summary>
/// Serializes an <see cref="Entity"/> to a <see cref="Stream"/> e.g. a File or existing array.
/// </summary>
Expand All @@ -41,7 +38,7 @@ public interface IArchSerializer
/// <param name="world">The <see cref="World"/>.</param>
/// <param name="entity">The <see cref="Entity"/>.</param>
void Serialize(IBufferWriter<byte> writer, World world, Entity entity);

/// <summary>
/// Deserializes an <see cref="Entity"/> from its bytes to an real <see cref="Entity"/> in a <see cref="World"/>.
/// <remarks>The new <see cref="Entity.Id"/> and <see cref="Entity.WorldId"/> will differ.</remarks>
Expand All @@ -65,21 +62,21 @@ public interface IArchSerializer
/// </summary>
/// <param name="world">The <see cref="World"/>.</param>
byte[] Serialize(World world);

/// <summary>
/// Serializes a <see cref="World"/> to a <see cref="Stream"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/>.</param>
/// <param name="world">The <see cref="World"/>.</param>
void Serialize(Stream stream, World world);

/// <summary>
/// Serializes a <see cref="World"/> to a <see cref="IBufferWriter{T}"/>.
/// </summary>
/// <param name="writer">The <see cref="IBufferWriter{T}"/>.</param>
/// <param name="world">The <see cref="World"/>.</param>
void Serialize(IBufferWriter<byte> writer, World world);

/// <summary>
/// Deserializes a byte-array into a <see cref="World"/>.
/// </summary>
Expand Down Expand Up @@ -129,12 +126,12 @@ public class ArchBinarySerializer : IArchSerializer
/// The standard <see cref="MessagePackSerializerOptions"/> for world (de)serialization.
/// </summary>
private readonly MessagePackSerializerOptions _options;

/// <summary>
/// The standard <see cref="MessagePackSerializerOptions"/> for single entity (de)serialization.
/// </summary>
private readonly MessagePackSerializerOptions _singleEntityOptions;

/// <summary>
/// The static constructor gets called during compile time to setup the serializer.
/// </summary>
Expand All @@ -151,7 +148,7 @@ public ArchBinarySerializer(params IMessagePackFormatter[] custFormatters)
}
)
);

_singleEntityOptions = MessagePackSerializerOptions.Standard.WithResolver(
MessagePack.Resolvers.CompositeResolver.Create(
_singleEntityFormatters.Concat(custFormatters).ToList(),
Expand All @@ -163,7 +160,7 @@ public ArchBinarySerializer(params IMessagePackFormatter[] custFormatters)
)
);
}

/// <inheritdoc/>
public byte[] Serialize(World world, Entity entity)
{
Expand Down Expand Up @@ -202,7 +199,7 @@ public Entity Deserialize(Stream stream, World world)
/// <inheritdoc/>
public byte[] Serialize(World world)
{
return MessagePackSerializer.Serialize(world, _options);;
return MessagePackSerializer.Serialize(world, _options); ;
}

/// <inheritdoc/>
Expand Down Expand Up @@ -236,7 +233,7 @@ public World Deserialize(Stream stream)
/// </summary>
public class ArchJsonSerializer : IArchSerializer
{

/// <summary>
/// The default formatters used to (de)serialize the <see cref="World"/>.
/// </summary>
Expand All @@ -252,7 +249,7 @@ public class ArchJsonSerializer : IArchSerializer
new DateTimeFormatter("yyyy-MM-dd HH:mm:ss"),
new NullableDateTimeFormatter("yyyy-MM-dd HH:mm:ss")
};

/// <summary>
/// The default formatters used to (de)serialize a single <see cref="Entity"/>.
/// </summary>
Expand All @@ -263,32 +260,32 @@ public class ArchJsonSerializer : IArchSerializer
new DateTimeFormatter("yyyy-MM-dd HH:mm:ss"),
new NullableDateTimeFormatter("yyyy-MM-dd HH:mm:ss")
};

// It can `not` garbage collect and create is slightly high cost.
// so you should store to static field.
private IJsonFormatterResolver _formatterResolver;

// CompositeResolver.Create can create dynamic composite resolver.
// It can `not` garbage collect and create is slightly high cost.
// so you should store to static field.
private IJsonFormatterResolver _singleEntityFormatterResolver;

/// <summary>
/// The static constructor gets called during compile time to setup the serializer.
/// </summary>
public ArchJsonSerializer(params IJsonFormatter[] custFormatters)
{
// Register all important jsonformatters
_formatterResolver = CompositeResolver.Create(
_formatters.Concat(custFormatters).ToArray(),
_formatters.Concat(custFormatters).ToArray(),
new[] {
EnumResolver.UnderlyingValue,
StandardResolver.AllowPrivateExcludeNullSnakeCase,
BuiltinResolver.Instance,
DynamicGenericResolver.Instance,
}
);

_singleEntityFormatterResolver = CompositeResolver.Create(
_singleEntityFormatters.Concat(custFormatters).ToArray(),
new[] {
Expand All @@ -297,7 +294,33 @@ public ArchJsonSerializer(params IJsonFormatter[] custFormatters)
}
);
}


/// <summary>
/// The static constructor gets called during compile time to setup the serializer.
/// This variant allows custom resolvers to be passed in as well.
/// </summary>
public ArchJsonSerializer(IJsonFormatter[] custFormatters, IJsonFormatterResolver[] custResolvers)
{
// Register all important jsonformatters
_formatterResolver = CompositeResolver.Create(
_formatters.Concat(custFormatters).ToArray(),
custResolvers.Concat(new[] {
EnumResolver.UnderlyingValue,
StandardResolver.AllowPrivateExcludeNullSnakeCase,
BuiltinResolver.Instance,
DynamicGenericResolver.Instance,
}).ToArray()
);

_singleEntityFormatterResolver = CompositeResolver.Create(
_singleEntityFormatters.Concat(custFormatters).ToArray(),
custResolvers.Concat(new[] {
EnumResolver.UnderlyingValue,
StandardResolver.AllowPrivateExcludeNullSnakeCase,
}).ToArray()
);
}

/// <summary>
/// Serializes the given <see cref="World"/> to a json-string.
/// </summary>
Expand All @@ -320,7 +343,7 @@ public string ToJson(World world, Entity entity)
(_singleEntityFormatters[1] as SingleEntityFormatter)!.EntityWorld = world;
return JsonSerializer.ToJsonString(entity, _singleEntityFormatterResolver);
}

/// <summary>
/// Deserializes the given json <see cref="string"/> to a <see cref="World"/>.
/// </summary>
Expand All @@ -330,7 +353,7 @@ public World FromJson(string jsonWorld)
{
return JsonSerializer.Deserialize<World>(jsonWorld, _formatterResolver);
}

/// <summary>
/// Deserializes the given json <see cref="string"/> to a <see cref="World"/>.
/// <remarks>The deserialized <see cref="Entity"/> will receive a new id and a new worldId.</remarks>
Expand All @@ -343,7 +366,7 @@ public Entity FromJson(World world, string jsonEntity)
(_singleEntityFormatters[1] as SingleEntityFormatter)!.EntityWorld = world;
return JsonSerializer.Deserialize<Entity>(jsonEntity, _singleEntityFormatterResolver);
}

/// <inheritdoc/>
public byte[] Serialize(World world, Entity entity)
{
Expand Down

0 comments on commit 10ff1ba

Please sign in to comment.