CultLib/src/GameCult.Caching.MessagePack.Generator/README.md

73 lines
2.4 KiB
Markdown
Raw Normal View History

# GameCult.Caching.MessagePack.Generator
`GameCult.Caching.MessagePack.Generator` is a Roslyn incremental source generator that emits MessagePack formatters for concrete `DatabaseEntry` subclasses.
## Scope
This project is infrastructure for the caching stack. Application code usually does not reference it directly.
Its job is to:
- find non-abstract subclasses of `DatabaseEntry`
- generate concrete `IMessagePackFormatter<T>` implementations
- generate resolver mappings consumed by `DatabaseEntryResolver`
## What It Generates
For each discovered concrete `DatabaseEntry` subtype, the generator emits:
- a formatter type
- a resolver mapping entry
Member slot assignment is:
1. `ID` in slot `0`
2. members with `[Key(...)]` in their exact key slot
3. remaining non-ignored instance fields and properties appended after the
highest occupied slot as legacy convenience
The generated formatter writes a MessagePack array sized to the highest occupied
slot and writes nil for unused gaps. Deserialization tolerates shorter older
arrays by leaving missing members at their constructor/field-initializer values,
and skips unknown extra slots. That makes `[Key(n)]` a durable wire contract:
deleted fields can leave their slot reserved and new fields can use new keys
without a store migration.
For schema-stable cache entries, annotate every persisted member. Unkeyed
members are supported for older code, but they are not a good long-term wire
contract because source member order is not a schema.
## Example
Given:
```csharp
[MessagePackObject]
public class PlayerData : DatabaseEntry, INamedEntry
{
[Key(1)] public string Email = string.Empty;
[Key(2)] public string PasswordHash = string.Empty;
[Key(3)] public string Username = string.Empty;
[IgnoreMember]
public string EntryName
{
get => Username;
set => Username = value;
}
}
```
the generator emits the formatter plumbing needed for MessagePack serialization of `PlayerData` without manually implementing an `IMessagePackFormatter<PlayerData>`.
## When You Need To Think About This Package
Usually only when:
- formatter generation is not happening
- a cache-entry type is not serializing as expected
- you are debugging build-time source generation behavior
## Distribution
The generator is packaged for consumers through [../GameCult.Caching.MessagePack.Analyzers/README.md](../GameCult.Caching.MessagePack.Analyzers/README.md).