2026-09-13 21:12:53 +02:00
|
|
|
#nullable enable
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
2026-09-13 22:06:17 +02:00
|
|
|
using System.Linq;
|
|
|
|
|
using System.Reflection;
|
Delete the CultCache MessagePack source generator
The reflective CultDocumentRegistry is now the only descriptor authority,
and payloads always go through MessagePackSerializer with
OptionsFor(document assembly). No consumer builds AOT, IL2CPP or trimmed,
Unity always ran the reflective path, and no benchmark showed a gain,
while the generator duplicated the registry's shape rules.
Removed: GameCult.Caching.MessagePack.Generator and .Analyzers (solution,
project and analyzer references, NuGet pack list), CultGeneratedDocumentMetadata
(provider attribute, interface, definitions, loader), the generated descriptor
and codec branches in CultCache and CultDocumentMessagePackSerialization,
DocumentShapeSweepTests and the generator half of the unkeyed test, the
Microsoft.CodeAnalysis.CSharp test reference and InternalsVisibleTo.
The registry rejects, with a message naming the fix, what MessagePackSerializer
cannot serialize and what the generator used to paper over: a document without
[MessagePackObject], a non-public document without AllowPrivate = true, and a
non-public member of an AllowPrivate document that is not [IgnoreMember].
DocumentShapeTests pins every rejection message and the accepted shapes'
round trips against MessagePackSerializer bytes (keeps the 93A16E0305 pin).
Rejected shapes are emitted into a dynamic assembly, which registry
discovery skips.
Nested member type names use reflection's Outer+Inner form, not the
generator's dot form, so ReferenceHolderEntry's fixture id is re-pinned
(bd8506... -> 4ec0c5...). A scan of the schema catalogs in all 2786 .cc
stores under F:\Projects (AetheriaEve and CultLib-* worktrees, bin and obj
excluded) found no member type name naming a nested type in either form.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 23:38:08 +02:00
|
|
|
using System.Reflection.Emit;
|
2026-09-13 21:12:53 +02:00
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using GameCult.Caching;
|
|
|
|
|
using GameCult.Caching.MessagePack;
|
|
|
|
|
using MessagePack;
|
Delete the CultCache MessagePack source generator
The reflective CultDocumentRegistry is now the only descriptor authority,
and payloads always go through MessagePackSerializer with
OptionsFor(document assembly). No consumer builds AOT, IL2CPP or trimmed,
Unity always ran the reflective path, and no benchmark showed a gain,
while the generator duplicated the registry's shape rules.
Removed: GameCult.Caching.MessagePack.Generator and .Analyzers (solution,
project and analyzer references, NuGet pack list), CultGeneratedDocumentMetadata
(provider attribute, interface, definitions, loader), the generated descriptor
and codec branches in CultCache and CultDocumentMessagePackSerialization,
DocumentShapeSweepTests and the generator half of the unkeyed test, the
Microsoft.CodeAnalysis.CSharp test reference and InternalsVisibleTo.
The registry rejects, with a message naming the fix, what MessagePackSerializer
cannot serialize and what the generator used to paper over: a document without
[MessagePackObject], a non-public document without AllowPrivate = true, and a
non-public member of an AllowPrivate document that is not [IgnoreMember].
DocumentShapeTests pins every rejection message and the accepted shapes'
round trips against MessagePackSerializer bytes (keeps the 93A16E0305 pin).
Rejected shapes are emitted into a dynamic assembly, which registry
discovery skips.
Nested member type names use reflection's Outer+Inner form, not the
generator's dot form, so ReferenceHolderEntry's fixture id is re-pinned
(bd8506... -> 4ec0c5...). A scan of the schema catalogs in all 2786 .cc
stores under F:\Projects (AetheriaEve and CultLib-* worktrees, bin and obj
excluded) found no member type name naming a nested type in either form.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 23:38:08 +02:00
|
|
|
using MessagePack.Formatters;
|
2026-09-13 21:12:53 +02:00
|
|
|
using NUnit.Framework;
|
|
|
|
|
|
|
|
|
|
namespace GameCult.Caching.Tests
|
|
|
|
|
{
|
|
|
|
|
public class SerializationOptionsTests
|
|
|
|
|
{
|
|
|
|
|
// Captured on CultLib 825b4f7, before per-assembly options.
|
|
|
|
|
private const string InteropNotePayloadHex =
|
|
|
|
|
"96B963756C7463616368652E696E7465726F705F6E6F74652E7631AB6E6F74653A637368617270A6637368617270BD6373686172702077726F746520612043756C744361636865206E6F7465D9245468652076312073746F726520666F726D61742069732074686520636F6E74726163742E92A6637368617270A7696E7465726F70";
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void InteropNoteBytesUnchanged()
|
|
|
|
|
{
|
|
|
|
|
var registry = CultDocumentRegistry.ForTypes(new[] { typeof(OptionsInteropNote) });
|
|
|
|
|
var note = new OptionsInteropNote
|
|
|
|
|
{
|
|
|
|
|
DocumentId = "note:csharp",
|
|
|
|
|
AuthorRuntimeId = "csharp",
|
|
|
|
|
Title = "csharp wrote a CultCache note",
|
|
|
|
|
Body = "The v1 store format is the contract.",
|
|
|
|
|
Tags = new[] { "csharp", "interop" }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var payload = CultDocumentMessagePackSerialization.SerializeUntyped(note, typeof(OptionsInteropNote), registry);
|
|
|
|
|
|
|
|
|
|
Assert.That(Convert.ToHexString(payload), Is.EqualTo(InteropNotePayloadHex));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public async Task RefKeyedDictionaryRoundTrips()
|
|
|
|
|
{
|
|
|
|
|
var path = Path.Combine(Path.GetTempPath(), $"cultlib-refkeyed-{Guid.NewGuid():N}.cc");
|
|
|
|
|
var registry = CultDocumentRegistry.ForTypes(new[] { typeof(RefKeyedHolder) });
|
|
|
|
|
var alpha = new CultRecordRef<RefKeyedHolder>(new CultRecordKey("alpha"));
|
|
|
|
|
var beta = new CultRecordRef<RefKeyedHolder>(new CultRecordKey("beta"));
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
using (var cache = new CultCache(registry))
|
|
|
|
|
{
|
|
|
|
|
cache.AddBackingStore(new SingleFileMessagePackBackingStore(path));
|
|
|
|
|
await cache.UpsertAsync(
|
|
|
|
|
new RefKeyedHolder { Name = "holder", Weights = new() { [alpha] = 0.25f, [beta] = 2f } },
|
|
|
|
|
new CultRecordHandle<RefKeyedHolder>(new CultRecordKey("holder")));
|
|
|
|
|
cache.FlushAllBackingStores();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
using var reopened = new CultCache(registry);
|
|
|
|
|
reopened.AddBackingStore(new SingleFileMessagePackBackingStore(path));
|
|
|
|
|
await reopened.PullAllBackingStoresAsync();
|
|
|
|
|
var loaded = reopened.Get<RefKeyedHolder>(new CultRecordKey("holder"));
|
|
|
|
|
|
|
|
|
|
Assert.That(loaded, Is.Not.Null);
|
|
|
|
|
Assert.That(loaded!.Weights[new CultRecordRef<RefKeyedHolder>(new CultRecordKey("alpha"))], Is.EqualTo(0.25f));
|
|
|
|
|
Assert.That(loaded.Weights[new CultRecordRef<RefKeyedHolder>(new CultRecordKey("beta"))], Is.EqualTo(2f));
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
if (File.Exists(path)) File.Delete(path);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void DeclaredResolverEncodesValueTypeAsPositionalArray()
|
|
|
|
|
{
|
|
|
|
|
var registry = CultDocumentRegistry.ForTypes(new[] { typeof(PairHolder) });
|
|
|
|
|
var holder = new PairHolder { Name = "pair", Value = new Pair { A = 1.5f, B = -2f } };
|
|
|
|
|
|
Delete the CultCache MessagePack source generator
The reflective CultDocumentRegistry is now the only descriptor authority,
and payloads always go through MessagePackSerializer with
OptionsFor(document assembly). No consumer builds AOT, IL2CPP or trimmed,
Unity always ran the reflective path, and no benchmark showed a gain,
while the generator duplicated the registry's shape rules.
Removed: GameCult.Caching.MessagePack.Generator and .Analyzers (solution,
project and analyzer references, NuGet pack list), CultGeneratedDocumentMetadata
(provider attribute, interface, definitions, loader), the generated descriptor
and codec branches in CultCache and CultDocumentMessagePackSerialization,
DocumentShapeSweepTests and the generator half of the unkeyed test, the
Microsoft.CodeAnalysis.CSharp test reference and InternalsVisibleTo.
The registry rejects, with a message naming the fix, what MessagePackSerializer
cannot serialize and what the generator used to paper over: a document without
[MessagePackObject], a non-public document without AllowPrivate = true, and a
non-public member of an AllowPrivate document that is not [IgnoreMember].
DocumentShapeTests pins every rejection message and the accepted shapes'
round trips against MessagePackSerializer bytes (keeps the 93A16E0305 pin).
Rejected shapes are emitted into a dynamic assembly, which registry
discovery skips.
Nested member type names use reflection's Outer+Inner form, not the
generator's dot form, so ReferenceHolderEntry's fixture id is re-pinned
(bd8506... -> 4ec0c5...). A scan of the schema catalogs in all 2786 .cc
stores under F:\Projects (AetheriaEve and CultLib-* worktrees, bin and obj
excluded) found no member type name naming a nested type in either form.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 23:38:08 +02:00
|
|
|
var payload = CultDocumentMessagePackSerialization.SerializeUntyped(holder, typeof(PairHolder), registry);
|
2026-09-13 21:12:53 +02:00
|
|
|
|
Delete the CultCache MessagePack source generator
The reflective CultDocumentRegistry is now the only descriptor authority,
and payloads always go through MessagePackSerializer with
OptionsFor(document assembly). No consumer builds AOT, IL2CPP or trimmed,
Unity always ran the reflective path, and no benchmark showed a gain,
while the generator duplicated the registry's shape rules.
Removed: GameCult.Caching.MessagePack.Generator and .Analyzers (solution,
project and analyzer references, NuGet pack list), CultGeneratedDocumentMetadata
(provider attribute, interface, definitions, loader), the generated descriptor
and codec branches in CultCache and CultDocumentMessagePackSerialization,
DocumentShapeSweepTests and the generator half of the unkeyed test, the
Microsoft.CodeAnalysis.CSharp test reference and InternalsVisibleTo.
The registry rejects, with a message naming the fix, what MessagePackSerializer
cannot serialize and what the generator used to paper over: a document without
[MessagePackObject], a non-public document without AllowPrivate = true, and a
non-public member of an AllowPrivate document that is not [IgnoreMember].
DocumentShapeTests pins every rejection message and the accepted shapes'
round trips against MessagePackSerializer bytes (keeps the 93A16E0305 pin).
Rejected shapes are emitted into a dynamic assembly, which registry
discovery skips.
Nested member type names use reflection's Outer+Inner form, not the
generator's dot form, so ReferenceHolderEntry's fixture id is re-pinned
(bd8506... -> 4ec0c5...). A scan of the schema catalogs in all 2786 .cc
stores under F:\Projects (AetheriaEve and CultLib-* worktrees, bin and obj
excluded) found no member type name naming a nested type in either form.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 23:38:08 +02:00
|
|
|
var reader = new MessagePackReader(payload);
|
2026-09-13 21:12:53 +02:00
|
|
|
Assert.That(reader.ReadArrayHeader(), Is.EqualTo(2));
|
|
|
|
|
reader.Skip();
|
|
|
|
|
Assert.That(reader.ReadArrayHeader(), Is.EqualTo(2));
|
|
|
|
|
Assert.That(reader.ReadSingle(), Is.EqualTo(1.5f));
|
|
|
|
|
Assert.That(reader.ReadSingle(), Is.EqualTo(-2f));
|
Delete the CultCache MessagePack source generator
The reflective CultDocumentRegistry is now the only descriptor authority,
and payloads always go through MessagePackSerializer with
OptionsFor(document assembly). No consumer builds AOT, IL2CPP or trimmed,
Unity always ran the reflective path, and no benchmark showed a gain,
while the generator duplicated the registry's shape rules.
Removed: GameCult.Caching.MessagePack.Generator and .Analyzers (solution,
project and analyzer references, NuGet pack list), CultGeneratedDocumentMetadata
(provider attribute, interface, definitions, loader), the generated descriptor
and codec branches in CultCache and CultDocumentMessagePackSerialization,
DocumentShapeSweepTests and the generator half of the unkeyed test, the
Microsoft.CodeAnalysis.CSharp test reference and InternalsVisibleTo.
The registry rejects, with a message naming the fix, what MessagePackSerializer
cannot serialize and what the generator used to paper over: a document without
[MessagePackObject], a non-public document without AllowPrivate = true, and a
non-public member of an AllowPrivate document that is not [IgnoreMember].
DocumentShapeTests pins every rejection message and the accepted shapes'
round trips against MessagePackSerializer bytes (keeps the 93A16E0305 pin).
Rejected shapes are emitted into a dynamic assembly, which registry
discovery skips.
Nested member type names use reflection's Outer+Inner form, not the
generator's dot form, so ReferenceHolderEntry's fixture id is re-pinned
(bd8506... -> 4ec0c5...). A scan of the schema catalogs in all 2786 .cc
stores under F:\Projects (AetheriaEve and CultLib-* worktrees, bin and obj
excluded) found no member type name naming a nested type in either form.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 23:38:08 +02:00
|
|
|
var decoded = (PairHolder)CultDocumentMessagePackSerialization.DeserializeUntyped(typeof(PairHolder), payload, registry);
|
|
|
|
|
Assert.That(decoded.Value, Is.EqualTo(holder.Value));
|
2026-09-13 21:12:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void UnknownAssemblyGetsBaseOptions()
|
|
|
|
|
{
|
|
|
|
|
Assert.That(CultDocumentMessagePackSerialization.OptionsFor(typeof(object).Assembly),
|
|
|
|
|
Is.SameAs(CultDocumentMessagePackSerialization.Options));
|
|
|
|
|
Assert.That(CultDocumentMessagePackSerialization.Options.Resolver.GetFormatter<Pair>(), Is.Null);
|
|
|
|
|
Assert.That(CultDocumentMessagePackSerialization.OptionsFor(typeof(Pair).Assembly),
|
|
|
|
|
Is.SameAs(CultDocumentMessagePackSerialization.OptionsFor(typeof(Pair).Assembly)));
|
|
|
|
|
Assert.That(CultDocumentMessagePackSerialization.OptionsFor(typeof(Pair).Assembly).Resolver.GetFormatter<Pair>(), Is.Not.Null);
|
|
|
|
|
}
|
|
|
|
|
|
2026-09-13 22:06:17 +02:00
|
|
|
// GenericHolder<Pair> lives in an assembly that declares a resolver writing Pair as [B, A]; Pair's own assembly writes [A, B].
|
|
|
|
|
[Test]
|
|
|
|
|
public void GenericDocumentUsesItsOwnAssemblyResolvers()
|
|
|
|
|
{
|
Delete the CultCache MessagePack source generator
The reflective CultDocumentRegistry is now the only descriptor authority,
and payloads always go through MessagePackSerializer with
OptionsFor(document assembly). No consumer builds AOT, IL2CPP or trimmed,
Unity always ran the reflective path, and no benchmark showed a gain,
while the generator duplicated the registry's shape rules.
Removed: GameCult.Caching.MessagePack.Generator and .Analyzers (solution,
project and analyzer references, NuGet pack list), CultGeneratedDocumentMetadata
(provider attribute, interface, definitions, loader), the generated descriptor
and codec branches in CultCache and CultDocumentMessagePackSerialization,
DocumentShapeSweepTests and the generator half of the unkeyed test, the
Microsoft.CodeAnalysis.CSharp test reference and InternalsVisibleTo.
The registry rejects, with a message naming the fix, what MessagePackSerializer
cannot serialize and what the generator used to paper over: a document without
[MessagePackObject], a non-public document without AllowPrivate = true, and a
non-public member of an AllowPrivate document that is not [IgnoreMember].
DocumentShapeTests pins every rejection message and the accepted shapes'
round trips against MessagePackSerializer bytes (keeps the 93A16E0305 pin).
Rejected shapes are emitted into a dynamic assembly, which registry
discovery skips.
Nested member type names use reflection's Outer+Inner form, not the
generator's dot form, so ReferenceHolderEntry's fixture id is re-pinned
(bd8506... -> 4ec0c5...). A scan of the schema catalogs in all 2786 .cc
stores under F:\Projects (AetheriaEve and CultLib-* worktrees, bin and obj
excluded) found no member type name naming a nested type in either form.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 23:38:08 +02:00
|
|
|
var assembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("GenericHolders"), AssemblyBuilderAccess.Run, new[]
|
|
|
|
|
{
|
|
|
|
|
new CustomAttributeBuilder(typeof(CultCacheFormatterResolverAttribute).GetConstructor(new[] { typeof(Type) })!, new object[] { typeof(ReversedPairResolver) })
|
|
|
|
|
});
|
|
|
|
|
var builder = assembly.DefineDynamicModule("GenericHolders").DefineType("GenericHolder`1", TypeAttributes.Public | TypeAttributes.Sealed);
|
|
|
|
|
var parameter = builder.DefineGenericParameters("T")[0];
|
|
|
|
|
builder.SetCustomAttribute(new CustomAttributeBuilder(
|
|
|
|
|
typeof(CultDocumentAttribute).GetConstructor(new[] { typeof(string), typeof(string) })!, new object[] { "tests.generic_holder", "tests.generic_holder.v1" }));
|
|
|
|
|
builder.SetCustomAttribute(new CustomAttributeBuilder(typeof(MessagePackObjectAttribute).GetConstructor(new[] { typeof(bool) })!, new object[] { false }));
|
|
|
|
|
builder.DefineField("Value", parameter, FieldAttributes.Public)
|
|
|
|
|
.SetCustomAttribute(new CustomAttributeBuilder(typeof(KeyAttribute).GetConstructor(new[] { typeof(int) })!, new object[] { 0 }));
|
|
|
|
|
var type = builder.CreateType()!.MakeGenericType(typeof(Pair));
|
2026-09-13 22:06:17 +02:00
|
|
|
var registry = CultDocumentRegistry.ForTypes(new[] { type });
|
|
|
|
|
var holder = Activator.CreateInstance(type)!;
|
|
|
|
|
type.GetField("Value")!.SetValue(holder, new Pair { A = 1.5f, B = -2f });
|
|
|
|
|
|
|
|
|
|
var payload = CultDocumentMessagePackSerialization.SerializeUntyped(holder, type, registry);
|
|
|
|
|
|
Delete the CultCache MessagePack source generator
The reflective CultDocumentRegistry is now the only descriptor authority,
and payloads always go through MessagePackSerializer with
OptionsFor(document assembly). No consumer builds AOT, IL2CPP or trimmed,
Unity always ran the reflective path, and no benchmark showed a gain,
while the generator duplicated the registry's shape rules.
Removed: GameCult.Caching.MessagePack.Generator and .Analyzers (solution,
project and analyzer references, NuGet pack list), CultGeneratedDocumentMetadata
(provider attribute, interface, definitions, loader), the generated descriptor
and codec branches in CultCache and CultDocumentMessagePackSerialization,
DocumentShapeSweepTests and the generator half of the unkeyed test, the
Microsoft.CodeAnalysis.CSharp test reference and InternalsVisibleTo.
The registry rejects, with a message naming the fix, what MessagePackSerializer
cannot serialize and what the generator used to paper over: a document without
[MessagePackObject], a non-public document without AllowPrivate = true, and a
non-public member of an AllowPrivate document that is not [IgnoreMember].
DocumentShapeTests pins every rejection message and the accepted shapes'
round trips against MessagePackSerializer bytes (keeps the 93A16E0305 pin).
Rejected shapes are emitted into a dynamic assembly, which registry
discovery skips.
Nested member type names use reflection's Outer+Inner form, not the
generator's dot form, so ReferenceHolderEntry's fixture id is re-pinned
(bd8506... -> 4ec0c5...). A scan of the schema catalogs in all 2786 .cc
stores under F:\Projects (AetheriaEve and CultLib-* worktrees, bin and obj
excluded) found no member type name naming a nested type in either form.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 23:38:08 +02:00
|
|
|
Assert.That(type.Assembly, Is.Not.SameAs(typeof(Pair).Assembly));
|
2026-09-13 22:06:17 +02:00
|
|
|
var reader = new MessagePackReader(payload);
|
|
|
|
|
Assert.That(reader.ReadArrayHeader(), Is.EqualTo(1));
|
|
|
|
|
Assert.That(reader.ReadArrayHeader(), Is.EqualTo(2));
|
|
|
|
|
Assert.That(reader.ReadSingle(), Is.EqualTo(-2f), "Pair's own assembly resolver was used instead of the document's");
|
|
|
|
|
Assert.That(reader.ReadSingle(), Is.EqualTo(1.5f));
|
|
|
|
|
var decoded = CultDocumentMessagePackSerialization.DeserializeUntyped(type, payload, registry);
|
|
|
|
|
Assert.That(type.GetField("Value")!.GetValue(decoded), Is.EqualTo(new Pair { A = 1.5f, B = -2f }));
|
|
|
|
|
}
|
|
|
|
|
|
Delete the CultCache MessagePack source generator
The reflective CultDocumentRegistry is now the only descriptor authority,
and payloads always go through MessagePackSerializer with
OptionsFor(document assembly). No consumer builds AOT, IL2CPP or trimmed,
Unity always ran the reflective path, and no benchmark showed a gain,
while the generator duplicated the registry's shape rules.
Removed: GameCult.Caching.MessagePack.Generator and .Analyzers (solution,
project and analyzer references, NuGet pack list), CultGeneratedDocumentMetadata
(provider attribute, interface, definitions, loader), the generated descriptor
and codec branches in CultCache and CultDocumentMessagePackSerialization,
DocumentShapeSweepTests and the generator half of the unkeyed test, the
Microsoft.CodeAnalysis.CSharp test reference and InternalsVisibleTo.
The registry rejects, with a message naming the fix, what MessagePackSerializer
cannot serialize and what the generator used to paper over: a document without
[MessagePackObject], a non-public document without AllowPrivate = true, and a
non-public member of an AllowPrivate document that is not [IgnoreMember].
DocumentShapeTests pins every rejection message and the accepted shapes'
round trips against MessagePackSerializer bytes (keeps the 93A16E0305 pin).
Rejected shapes are emitted into a dynamic assembly, which registry
discovery skips.
Nested member type names use reflection's Outer+Inner form, not the
generator's dot form, so ReferenceHolderEntry's fixture id is re-pinned
(bd8506... -> 4ec0c5...). A scan of the schema catalogs in all 2786 .cc
stores under F:\Projects (AetheriaEve and CultLib-* worktrees, bin and obj
excluded) found no member type name naming a nested type in either form.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 23:38:08 +02:00
|
|
|
public sealed class ReversedPairResolver : IFormatterResolver
|
|
|
|
|
{
|
|
|
|
|
public static readonly IFormatterResolver Instance = new ReversedPairResolver();
|
|
|
|
|
public IMessagePackFormatter<T>? GetFormatter<T>() => typeof(T) == typeof(Pair) ? (IMessagePackFormatter<T>)(object)new ReversedPairFormatter() : null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public sealed class ReversedPairFormatter : IMessagePackFormatter<Pair>
|
|
|
|
|
{
|
|
|
|
|
public void Serialize(ref MessagePackWriter writer, Pair value, MessagePackSerializerOptions options) { writer.WriteArrayHeader(2); writer.Write(value.B); writer.Write(value.A); }
|
|
|
|
|
public Pair Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { reader.ReadArrayHeader(); var b = reader.ReadSingle(); return new Pair { A = reader.ReadSingle(), B = b }; }
|
|
|
|
|
}
|
|
|
|
|
|
2026-09-13 21:12:53 +02:00
|
|
|
[CultDocument("tests.pair_holder", "tests.pair_holder.v1")]
|
|
|
|
|
[MessagePackObject]
|
|
|
|
|
public sealed class PairHolder
|
|
|
|
|
{
|
|
|
|
|
[Key(0)] public string Name = string.Empty;
|
|
|
|
|
[Key(1)] public Pair Value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[CultDocument("cultcache.interop-note", "cultcache.interop_note.v1")]
|
Delete the CultCache MessagePack source generator
The reflective CultDocumentRegistry is now the only descriptor authority,
and payloads always go through MessagePackSerializer with
OptionsFor(document assembly). No consumer builds AOT, IL2CPP or trimmed,
Unity always ran the reflective path, and no benchmark showed a gain,
while the generator duplicated the registry's shape rules.
Removed: GameCult.Caching.MessagePack.Generator and .Analyzers (solution,
project and analyzer references, NuGet pack list), CultGeneratedDocumentMetadata
(provider attribute, interface, definitions, loader), the generated descriptor
and codec branches in CultCache and CultDocumentMessagePackSerialization,
DocumentShapeSweepTests and the generator half of the unkeyed test, the
Microsoft.CodeAnalysis.CSharp test reference and InternalsVisibleTo.
The registry rejects, with a message naming the fix, what MessagePackSerializer
cannot serialize and what the generator used to paper over: a document without
[MessagePackObject], a non-public document without AllowPrivate = true, and a
non-public member of an AllowPrivate document that is not [IgnoreMember].
DocumentShapeTests pins every rejection message and the accepted shapes'
round trips against MessagePackSerializer bytes (keeps the 93A16E0305 pin).
Rejected shapes are emitted into a dynamic assembly, which registry
discovery skips.
Nested member type names use reflection's Outer+Inner form, not the
generator's dot form, so ReferenceHolderEntry's fixture id is re-pinned
(bd8506... -> 4ec0c5...). A scan of the schema catalogs in all 2786 .cc
stores under F:\Projects (AetheriaEve and CultLib-* worktrees, bin and obj
excluded) found no member type name naming a nested type in either form.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 23:38:08 +02:00
|
|
|
[MessagePackObject]
|
2026-09-13 21:12:53 +02:00
|
|
|
public sealed class OptionsInteropNote
|
|
|
|
|
{
|
|
|
|
|
[Key(0)] public string SchemaVersion { get; set; } = "cultcache.interop_note.v1";
|
|
|
|
|
[Key(1)] [CultName] public string DocumentId { get; set; } = string.Empty;
|
|
|
|
|
[Key(2)] public string AuthorRuntimeId { get; set; } = string.Empty;
|
|
|
|
|
[Key(3)] public string Title { get; set; } = string.Empty;
|
|
|
|
|
[Key(4)] public string Body { get; set; } = string.Empty;
|
|
|
|
|
[Key(5)] public string[] Tags { get; set; } = Array.Empty<string>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[CultDocument("tests.ref_keyed_holder", "tests.ref_keyed_holder.v1")]
|
Delete the CultCache MessagePack source generator
The reflective CultDocumentRegistry is now the only descriptor authority,
and payloads always go through MessagePackSerializer with
OptionsFor(document assembly). No consumer builds AOT, IL2CPP or trimmed,
Unity always ran the reflective path, and no benchmark showed a gain,
while the generator duplicated the registry's shape rules.
Removed: GameCult.Caching.MessagePack.Generator and .Analyzers (solution,
project and analyzer references, NuGet pack list), CultGeneratedDocumentMetadata
(provider attribute, interface, definitions, loader), the generated descriptor
and codec branches in CultCache and CultDocumentMessagePackSerialization,
DocumentShapeSweepTests and the generator half of the unkeyed test, the
Microsoft.CodeAnalysis.CSharp test reference and InternalsVisibleTo.
The registry rejects, with a message naming the fix, what MessagePackSerializer
cannot serialize and what the generator used to paper over: a document without
[MessagePackObject], a non-public document without AllowPrivate = true, and a
non-public member of an AllowPrivate document that is not [IgnoreMember].
DocumentShapeTests pins every rejection message and the accepted shapes'
round trips against MessagePackSerializer bytes (keeps the 93A16E0305 pin).
Rejected shapes are emitted into a dynamic assembly, which registry
discovery skips.
Nested member type names use reflection's Outer+Inner form, not the
generator's dot form, so ReferenceHolderEntry's fixture id is re-pinned
(bd8506... -> 4ec0c5...). A scan of the schema catalogs in all 2786 .cc
stores under F:\Projects (AetheriaEve and CultLib-* worktrees, bin and obj
excluded) found no member type name naming a nested type in either form.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 23:38:08 +02:00
|
|
|
[MessagePackObject]
|
2026-09-13 21:12:53 +02:00
|
|
|
public sealed class RefKeyedHolder
|
|
|
|
|
{
|
|
|
|
|
[Key(0)] [CultName] public string Name = string.Empty;
|
|
|
|
|
[Key(1)] public Dictionary<CultRecordRef<RefKeyedHolder>, float> Weights = new();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|