AyCode.Core/AyCode.Core.Tests/GeneratedWriters/TestOrderWriter.cs

142 lines
4.7 KiB
C#

using System.Runtime.CompilerServices;
using AyCode.Core.Serializers.Binaries;
using AyCode.Core.Tests.TestModels;
namespace AyCode.Core.Tests.GeneratedWriters;
/// <summary>
/// Hand-written generated binary writer for TestOrder.
/// Demonstrates the pattern that the source generator will produce.
///
/// Bypasses the runtime switch/delegate property loop:
/// - Direct obj.Property access instead of Func&lt;&gt;.Invoke()
/// - No switch dispatch per property
/// - No boxing for value types
/// - Small method (~500B native) vs 27KB WriteObject — better ICache
///
/// Properties are written in alphabetical order to match the runtime serializer.
/// Complex/Collection properties fall back to the runtime serializer via WriteValue.
/// </summary>
internal sealed class TestOrderWriter : IGeneratedBinaryWriter
{
internal static readonly TestOrderWriter Instance = new();
public void WriteProperties<TOutput>(
object value,
AcBinarySerializer.BinarySerializationContext<TOutput> context,
int depth)
where TOutput : struct, IBinaryOutputBase
{
var obj = Unsafe.As<TestOrder>(value);
var nextDepth = depth;
// Properties in alphabetical order (matching runtime serializer):
// AuditMetadata: MetadataInfo? (complex, nullable)
WriteComplexOrNull(obj.AuditMetadata, context, nextDepth);
// Category: SharedCategory? (complex, nullable)
WriteComplexOrNull(obj.Category, context, nextDepth);
// CreatedAt: DateTime
context.WriteByte(BinaryTypeCode.DateTime);
context.WriteDateTimeBits(obj.CreatedAt);
// Id: int
WriteInt32OrSkip(obj.Id, context);
// Items: List<TestOrderItem> (collection)
WriteComplexOrNull(obj.Items, context, nextDepth);
// MetadataList: List<MetadataInfo> (collection)
WriteComplexOrNull(obj.MetadataList, context, nextDepth);
// NoMergeItems: List<TestOrderItem> (collection)
WriteComplexOrNull(obj.NoMergeItems, context, nextDepth);
// OrderMetadata: MetadataInfo? (complex, nullable)
WriteComplexOrNull(obj.OrderMetadata, context, nextDepth);
// OrderNumber: string
AcBinarySerializer.WriteStringGenerated(obj.OrderNumber, context);
// Owner: SharedUser? (complex, nullable)
WriteComplexOrNull(obj.Owner, context, nextDepth);
// PaidDateUtc: DateTime? (nullable)
var paidDate = obj.PaidDateUtc;
if (paidDate.HasValue)
{
context.WriteByte(BinaryTypeCode.DateTime);
context.WriteDateTimeBits(paidDate.Value);
}
else
{
context.WriteByte(BinaryTypeCode.Null);
}
// PrimaryTag: SharedTag? (complex, nullable)
WriteComplexOrNull(obj.PrimaryTag, context, nextDepth);
// SecondaryTag: SharedTag? (complex, nullable)
WriteComplexOrNull(obj.SecondaryTag, context, nextDepth);
// Status: TestStatus (enum)
context.WriteByte(BinaryTypeCode.Enum);
var enumVal = (int)obj.Status;
if (BinaryTypeCode.TryEncodeTinyInt(enumVal, out var tinyEnum))
context.WriteByte(tinyEnum);
else
{
context.WriteByte(BinaryTypeCode.Int32);
context.WriteVarInt(enumVal);
}
// Tags: List<SharedTag> (collection)
WriteComplexOrNull(obj.Tags, context, nextDepth);
// TotalAmount: decimal
if (obj.TotalAmount == 0m)
context.WriteByte(BinaryTypeCode.PropertySkip);
else
{
context.WriteByte(BinaryTypeCode.Decimal);
context.WriteDecimalBits(obj.TotalAmount);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void WriteInt32OrSkip<TOutput>(int value, AcBinarySerializer.BinarySerializationContext<TOutput> context)
where TOutput : struct, IBinaryOutputBase
{
if (value == 0)
{
context.WriteByte(BinaryTypeCode.PropertySkip);
return;
}
if (BinaryTypeCode.TryEncodeTinyInt(value, out var tiny))
{
context.WriteByte(BinaryTypeCode.Int32);
context.WriteByte(tiny);
return;
}
context.WriteByte(BinaryTypeCode.Int32);
context.WriteVarInt(value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void WriteComplexOrNull<TOutput>(object? value, AcBinarySerializer.BinarySerializationContext<TOutput> context, int depth)
where TOutput : struct, IBinaryOutputBase
{
if (value == null)
{
context.WriteByte(BinaryTypeCode.PropertySkip);
return;
}
AcBinarySerializer.WriteValueGenerated(value, value.GetType(), context, depth);
}
}