using System; using GameCult.Caching; using MessagePack; using MessagePack.Formatters; using MessagePack.Resolvers; namespace GameCult.Caching.MessagePack; public sealed class CultRecordRefFormatter : IMessagePackFormatter> { public void Serialize(ref MessagePackWriter writer, CultRecordRef value, MessagePackSerializerOptions options) { options.Resolver.GetFormatterWithVerify().Serialize(ref writer, value.Key.Value, options); } public CultRecordRef Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { var key = options.Resolver.GetFormatterWithVerify().Deserialize(ref reader, options) ?? string.Empty; return new CultRecordRef(new CultRecordKey(key)); } } public sealed class CultDocumentResolver : IFormatterResolver { public static readonly CultDocumentResolver Instance = new(); private CultDocumentResolver() { } public IMessagePackFormatter? GetFormatter() { var generated = GeneratedCultDocumentResolvers.GetFormatter(); if (generated != null) { return generated; } var type = typeof(T); if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(CultRecordRef<>)) { var formatterType = typeof(CultRecordRefFormatter<>).MakeGenericType(type.GetGenericArguments()[0]); return (IMessagePackFormatter)Activator.CreateInstance(formatterType)!; } return null; } } public static class CultDocumentMessagePackSerialization { public static readonly MessagePackSerializerOptions Options = MessagePackSerializerOptions.Standard .WithResolver(CompositeResolver.Create( CultDocumentResolver.Instance, StandardResolver.Instance)) .WithSecurity(MessagePackSecurity.UntrustedData); public static byte[] Serialize(T value) { return MessagePackSerializer.Serialize(value, Options); } public static T Deserialize(byte[] payload) { return MessagePackSerializer.Deserialize(payload, Options); } public static byte[] SerializeUntyped(object value, Type type) { return MessagePackSerializer.Serialize(type, value, Options); } public static object DeserializeUntyped(Type type, byte[] payload) { return MessagePackSerializer.Deserialize(type, payload, Options); } } public static class GeneratedCultDocumentResolvers { public static IMessagePackFormatter? GetFormatter() => null; } public class SingleFileMessagePackBackingStore : SingleFileBackingStore { public SingleFileMessagePackBackingStore(string filePath) : base(filePath) { } protected override byte[] SerializeSnapshot(CultPersistedStoreSnapshot snapshot) { return CultDocumentMessagePackSerialization.Serialize(snapshot); } protected override CultPersistedStoreSnapshot DeserializeSnapshot(byte[] data) { return CultDocumentMessagePackSerialization.Deserialize(data); } protected override byte[] SerializePayload(object document) { return CultDocumentMessagePackSerialization.SerializeUntyped(document, document.GetType()); } protected override object DeserializePayload(Type documentType, byte[] payload) { return CultDocumentMessagePackSerialization.DeserializeUntyped(documentType, payload); } } public class MultiFileMessagePackBackingStore : MultiFileBackingStore { public MultiFileMessagePackBackingStore(string path) : base(path) { } protected override byte[] SerializeRecord(CultPersistedRecord record) { return CultDocumentMessagePackSerialization.Serialize(record); } protected override CultPersistedRecord DeserializeRecord(byte[] data) { return CultDocumentMessagePackSerialization.Deserialize(data); } protected override byte[] SerializeCatalog(CultSchemaCatalogEntry[] catalog) { return CultDocumentMessagePackSerialization.Serialize(catalog); } protected override CultSchemaCatalogEntry[] DeserializeCatalog(byte[] data) { return CultDocumentMessagePackSerialization.Deserialize(data); } protected override byte[] SerializePayload(object document) { return CultDocumentMessagePackSerialization.SerializeUntyped(document, document.GetType()); } protected override object DeserializePayload(Type documentType, byte[] payload) { return CultDocumentMessagePackSerialization.DeserializeUntyped(documentType, payload); } public override string Extension => "msgpack"; }