The static UntrustedData options are gone. An assembly declares its formatter resolvers with [assembly: CultCacheFormatterResolver(typeof(R))]; CultDocumentMessagePackSerialization.OptionsFor(assembly) composes them ahead of CultDocumentResolver and StandardResolver, once per assembly, and hands assemblies that declare nothing the base Options. Generated codecs and the reflective SerializeUntyped/DeserializeUntyped path both read OptionsFor(typeof(X).Assembly). No registration call, no mutable options, no load order. CultMessagePackSecurity copies UntrustedData and supplies a collision-resistant comparer over CultRecordRef<T>.Key.Value, so ref-keyed dictionaries deserialize. Tests: RefKeyedDictionaryRoundTrips failed on825b4f7("No hash-resistant equality comparer available"); DeclaredResolverEncodesValueTypeAsPositionalArray and UnknownAssemblyGetsBaseOptions did not compile there (new API); InteropNoteBytesUnchanged is a pin whose payload constant was captured on825b4f7. BenchItem, the one unkeyed [CultDocument] in any consumer (in-memory benchmark, no store), gains [Key]s in its existing slot order. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
43 lines
1.4 KiB
C#
43 lines
1.4 KiB
C#
using GameCult.Caching.MessagePack;
|
|
using GameCult.Caching.Tests;
|
|
using MessagePack;
|
|
using MessagePack.Formatters;
|
|
|
|
[assembly: CultCacheFormatterResolver(typeof(PairResolver))]
|
|
|
|
namespace GameCult.Caching.Tests
|
|
{
|
|
public struct Pair
|
|
{
|
|
public float A;
|
|
public float B;
|
|
}
|
|
|
|
public sealed class PairResolver : IFormatterResolver
|
|
{
|
|
public static readonly IFormatterResolver Instance = new PairResolver();
|
|
|
|
public IMessagePackFormatter<T>? GetFormatter<T>()
|
|
{
|
|
return typeof(T) == typeof(Pair) ? (IMessagePackFormatter<T>)(object)PairFormatter.Instance : null;
|
|
}
|
|
|
|
private sealed class PairFormatter : IMessagePackFormatter<Pair>
|
|
{
|
|
public static readonly PairFormatter Instance = new();
|
|
|
|
public void Serialize(ref MessagePackWriter writer, Pair value, MessagePackSerializerOptions options)
|
|
{
|
|
writer.WriteArrayHeader(2);
|
|
writer.Write(value.A);
|
|
writer.Write(value.B);
|
|
}
|
|
|
|
public Pair Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
|
{
|
|
if (reader.ReadArrayHeader() != 2) throw new MessagePackSerializationException("Pair is a two-element array.");
|
|
return new Pair { A = reader.ReadSingle(), B = reader.ReadSingle() };
|
|
}
|
|
}
|
|
}
|
|
}
|