diff --git a/AyCode.Core.Serializers.SourceGenerator/AcBinarySourceGenerator.cs b/AyCode.Core.Serializers.SourceGenerator/AcBinarySourceGenerator.cs
index 57ab9ff..c7556c5 100644
--- a/AyCode.Core.Serializers.SourceGenerator/AcBinarySourceGenerator.cs
+++ b/AyCode.Core.Serializers.SourceGenerator/AcBinarySourceGenerator.cs
@@ -665,21 +665,9 @@ public class AcBinarySourceGenerator : IIncrementalGenerator
if (IsMarkerless(p.TypeKind))
{
if (!enableMetadata)
- {
- // Per-type metadata disabled — always markerless, no branch
EmitMarkerless(sb, p.TypeKind, a, i);
- }
else
- {
- sb.AppendLine($"{i}if (context.UseMetadata)");
- sb.AppendLine($"{i}{{");
- EmitSkip(sb, p.TypeKind, a, p.TypeNameForTypeof, i + " ");
- sb.AppendLine($"{i}}}");
- sb.AppendLine($"{i}else");
- sb.AppendLine($"{i}{{");
- EmitMarkerless(sb, p.TypeKind, a, i + " ");
- sb.AppendLine($"{i}}}");
- }
+ EmitPropertyBridge(sb, p.TypeKind, a, i);
return;
}
@@ -811,6 +799,38 @@ public class AcBinarySourceGenerator : IIncrementalGenerator
}
}
+ ///
+ /// Emits a single bridge method call for markerless property types with enableMetadata=true.
+ /// The bridge method on BinarySerializationContext handles both UseMetadata=true (markered+skip)
+ /// and UseMetadata=false (markerless) paths internally. Replaces 7-11 lines of generated code with 1 line.
+ ///
+ private static void EmitPropertyBridge(StringBuilder sb, PropertyTypeKind k, string a, string i)
+ {
+ var call = k switch
+ {
+ PropertyTypeKind.Int32 => $"context.WriteInt32Property({a});",
+ PropertyTypeKind.Int64 => $"context.WriteInt64Property({a});",
+ PropertyTypeKind.Boolean => $"context.WriteBoolProperty({a});",
+ PropertyTypeKind.Double => $"context.WriteFloat64Property({a});",
+ PropertyTypeKind.Single => $"context.WriteFloat32Property({a});",
+ PropertyTypeKind.Decimal => $"context.WriteDecimalProperty({a});",
+ PropertyTypeKind.DateTime => $"context.WriteDateTimeProperty({a});",
+ PropertyTypeKind.Guid => $"context.WriteGuidProperty({a});",
+ PropertyTypeKind.Byte => $"context.WriteByteProperty({a});",
+ PropertyTypeKind.Int16 => $"context.WriteInt16Property({a});",
+ PropertyTypeKind.UInt16 => $"context.WriteUInt16Property({a});",
+ PropertyTypeKind.UInt32 => $"context.WriteUInt32Property({a});",
+ PropertyTypeKind.UInt64 => $"context.WriteUInt64Property({a});",
+ PropertyTypeKind.Enum => $"context.WriteEnumInt32Property((int){a});",
+ PropertyTypeKind.TimeSpan => $"context.WriteTimeSpanProperty({a});",
+ PropertyTypeKind.DateTimeOffset => $"context.WriteDateTimeOffsetProperty({a});",
+ _ => null
+ };
+
+ if (call != null)
+ sb.AppendLine($"{i}{call}");
+ }
+
///
/// Emits direct object write — bypasses GetWrapper + WriteObject entirely.
#region Scan Pass Code Generation
@@ -1203,112 +1223,29 @@ public class AcBinarySourceGenerator : IIncrementalGenerator
private static void EmitDirectObjectWrite(StringBuilder sb, PropInfo p, string a, string i)
{
var writer = p.WriterClassName;
- var nextDepth = "depth + 1";
+ var refSuffix = p.IsIId ? "IId" : "All";
// Reference type properties can always be null at runtime regardless of nullable annotation
sb.AppendLine($"{i}if ({a} == null) context.WriteByte(BinaryTypeCode.PropertySkip);");
- sb.AppendLine($"{i}else");
- sb.AppendLine($"{i}{{");
+ sb.AppendLine($"{i}else if (depth > context.MaxDepth) context.WriteByte(BinaryTypeCode.Null);");
- // MaxDepth check — matches WriteObjectGenerated
- sb.AppendLine($"{i} if (depth > context.MaxDepth) context.WriteByte(BinaryTypeCode.Null);");
- sb.AppendLine($"{i} else");
- sb.AppendLine($"{i} {{");
-
- if (!p.ChildNeedsRefScan)
+ if (!p.ChildNeedsRefScan && !p.ChildEnableMetadata)
{
- // Compile-time proven: scan never tracks child → TryConsumeWritePlanEntry always false
- if (!p.ChildEnableMetadata)
- {
- // No ref, no metadata → ZERO branches: always Object
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.Object);");
- sb.AppendLine($"{i} {writer}.Instance.WriteProperties({a}, context, {nextDepth});");
- }
- else
- {
- // No ref, but metadata possible → UseMetadata branch only
- sb.AppendLine($"{i} var isFirstMeta_{p.Name} = context.UseMetadata && AcBinarySerializer.BinarySerializationContext.RegisterMetadataType(context.GetWrapper(typeof({p.TypeNameForTypeof}), {writer}.s_wrapperSlot));");
- sb.AppendLine($"{i} if (context.UseMetadata)");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.ObjectWithMetadata);");
- EmitInlineMetadata(sb, p.ChildTypeNameHash, p.ChildPropertyHashes!, $"isFirstMeta_{p.Name}", i + " ");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} else");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.Object);");
- sb.AppendLine($"{i} {writer}.Instance.WriteProperties({a}, context, {nextDepth});");
- }
+ // Compile-time proven: no ref, no metadata → ZERO branches: always Object + WriteProperties
+ sb.AppendLine($"{i}else {{ context.WriteByte(BinaryTypeCode.Object); {writer}.Instance.WriteProperties({a}, context, depth + 1); }}");
}
- else if (!p.ChildEnableMetadata)
+ else if (p.ChildNeedsRefScan && !p.ChildEnableMetadata)
{
- // Ref tracking possible, no metadata — Object or ObjectRefFirst/ObjectRef
- var refGuard = p.IsIId
- ? "context.HasRefHandling"
- : "context.HasAllRefHandling";
- sb.AppendLine($"{i} if ({refGuard} && context.TryConsumeWritePlanEntry(out var pe_{p.Name}))");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} if (!pe_{p.Name}.IsFirst)");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.ObjectRef);");
- sb.AppendLine($"{i} context.WriteVarUInt((uint)pe_{p.Name}.CacheMapIndex);");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} else");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.ObjectRefFirst);");
- sb.AppendLine($"{i} context.WriteVarUInt((uint)pe_{p.Name}.CacheMapIndex);");
- sb.AppendLine($"{i} {writer}.Instance.WriteProperties({a}, context, {nextDepth});");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} else");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.Object);");
- sb.AppendLine($"{i} {writer}.Instance.WriteProperties({a}, context, {nextDepth});");
- sb.AppendLine($"{i} }}");
+ sb.AppendLine($"{i}else if (context.WriteObjectRefMarker{refSuffix}()) {writer}.Instance.WriteProperties({a}, context, depth + 1);");
+ }
+ else if (!p.ChildNeedsRefScan && p.ChildEnableMetadata)
+ {
+ sb.AppendLine($"{i}else {{ context.WriteObjectMetaMarker({a}, {writer}.s_wrapperSlot); {writer}.Instance.WriteProperties({a}, context, depth + 1); }}");
}
else
{
- // Full path: ref tracking + metadata
- sb.AppendLine($"{i} var isFirstMeta_{p.Name} = context.UseMetadata && AcBinarySerializer.BinarySerializationContext.RegisterMetadataType(context.GetWrapper(typeof({p.TypeNameForTypeof}), {writer}.s_wrapperSlot));");
- var refGuard = p.IsIId
- ? "context.HasRefHandling"
- : "context.HasAllRefHandling";
- sb.AppendLine($"{i} if ({refGuard} && context.TryConsumeWritePlanEntry(out var pe_{p.Name}))");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} if (!pe_{p.Name}.IsFirst)");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.ObjectRef);");
- sb.AppendLine($"{i} context.WriteVarUInt((uint)pe_{p.Name}.CacheMapIndex);");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} else");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} if (context.UseMetadata)");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.ObjectWithMetadataRefFirst);");
- sb.AppendLine($"{i} context.WriteVarUInt((uint)pe_{p.Name}.CacheMapIndex);");
- EmitInlineMetadata(sb, p.ChildTypeNameHash, p.ChildPropertyHashes!, $"isFirstMeta_{p.Name}", i + " ");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} else");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.ObjectRefFirst);");
- sb.AppendLine($"{i} context.WriteVarUInt((uint)pe_{p.Name}.CacheMapIndex);");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} {writer}.Instance.WriteProperties({a}, context, {nextDepth});");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} else");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} if (context.UseMetadata)");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.ObjectWithMetadata);");
- EmitInlineMetadata(sb, p.ChildTypeNameHash, p.ChildPropertyHashes!, $"isFirstMeta_{p.Name}", i + " ");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} else");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.Object);");
- sb.AppendLine($"{i} {writer}.Instance.WriteProperties({a}, context, {nextDepth});");
- sb.AppendLine($"{i} }}");
+ sb.AppendLine($"{i}else if (context.WriteObjectFullMarker{refSuffix}({a}, {writer}.s_wrapperSlot)) {writer}.Instance.WriteProperties({a}, context, depth + 1);");
}
-
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i}}}");
}
///
@@ -1386,98 +1323,26 @@ public class AcBinarySourceGenerator : IIncrementalGenerator
sb.AppendLine($"{i} if ({e} == null) {{ context.WriteByte(BinaryTypeCode.Null); continue; }}");
sb.AppendLine($"{i} if (depth + 1 > context.MaxDepth) {{ context.WriteByte(BinaryTypeCode.Null); continue; }}");
- if (!p.ElementNeedsRefScan)
+ var elemRefSuffix = p.ElementIsIId ? "IId" : "All";
+
+ if (!p.ElementNeedsRefScan && !p.ElementEnableMetadata)
{
- // Compile-time proven: scan never tracks element → TryConsumeWritePlanEntry always false
- if (!p.ElementEnableMetadata)
- {
- // No ref, no metadata → ZERO branches per element: always Object
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.Object);");
- sb.AppendLine($"{i} {writer}.Instance.WriteProperties({e}, context, nextDepth_{p.Name});");
- }
- else
- {
- // No ref, but metadata possible → UseMetadata branch only
- sb.AppendLine($"{i} var isFirstMeta_e_{p.Name} = context.UseMetadata && AcBinarySerializer.BinarySerializationContext.RegisterMetadataType(context.GetWrapper(typeof({p.ElementFullTypeName}), {writer}.s_wrapperSlot));");
- sb.AppendLine($"{i} if (context.UseMetadata)");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.ObjectWithMetadata);");
- EmitInlineMetadata(sb, p.ElementTypeNameHash, p.ElementPropertyHashes!, $"isFirstMeta_e_{p.Name}", i + " ");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} else");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.Object);");
- sb.AppendLine($"{i} {writer}.Instance.WriteProperties({e}, context, nextDepth_{p.Name});");
- }
+ // Compile-time proven: no ref, no metadata → ZERO branches per element: always Object
+ sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.Object);");
+ sb.AppendLine($"{i} {writer}.Instance.WriteProperties({e}, context, nextDepth_{p.Name});");
+ }
+ else if (p.ElementNeedsRefScan && !p.ElementEnableMetadata)
+ {
+ sb.AppendLine($"{i} if (context.WriteObjectRefMarker{elemRefSuffix}()) {writer}.Instance.WriteProperties({e}, context, nextDepth_{p.Name});");
+ }
+ else if (!p.ElementNeedsRefScan && p.ElementEnableMetadata)
+ {
+ sb.AppendLine($"{i} context.WriteObjectMetaMarker({e}, {writer}.s_wrapperSlot);");
+ sb.AppendLine($"{i} {writer}.Instance.WriteProperties({e}, context, nextDepth_{p.Name});");
}
else
{
- // Inline ref tracking
- var elemRefGuard = p.ElementIsIId
- ? "context.HasRefHandling"
- : "context.HasAllRefHandling";
-
- if (!p.ElementEnableMetadata)
- {
- // Ref tracking possible, no metadata — Object or ObjectRefFirst/ObjectRef
- sb.AppendLine($"{i} if ({elemRefGuard} && context.TryConsumeWritePlanEntry(out var epe_{p.Name}))");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} if (!epe_{p.Name}.IsFirst)");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.ObjectRef);");
- sb.AppendLine($"{i} context.WriteVarUInt((uint)epe_{p.Name}.CacheMapIndex);");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} else");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.ObjectRefFirst);");
- sb.AppendLine($"{i} context.WriteVarUInt((uint)epe_{p.Name}.CacheMapIndex);");
- sb.AppendLine($"{i} {writer}.Instance.WriteProperties({e}, context, nextDepth_{p.Name});");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} else");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.Object);");
- sb.AppendLine($"{i} {writer}.Instance.WriteProperties({e}, context, nextDepth_{p.Name});");
- sb.AppendLine($"{i} }}");
- }
- else
- {
- // Full path: ref tracking + metadata
- sb.AppendLine($"{i} var isFirstMeta_e_{p.Name} = context.UseMetadata && AcBinarySerializer.BinarySerializationContext.RegisterMetadataType(context.GetWrapper(typeof({p.ElementFullTypeName}), {writer}.s_wrapperSlot));");
- sb.AppendLine($"{i} if ({elemRefGuard} && context.TryConsumeWritePlanEntry(out var epe_{p.Name}))");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} if (!epe_{p.Name}.IsFirst)");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.ObjectRef);");
- sb.AppendLine($"{i} context.WriteVarUInt((uint)epe_{p.Name}.CacheMapIndex);");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} else");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} if (context.UseMetadata)");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.ObjectWithMetadataRefFirst);");
- sb.AppendLine($"{i} context.WriteVarUInt((uint)epe_{p.Name}.CacheMapIndex);");
- EmitInlineMetadata(sb, p.ElementTypeNameHash, p.ElementPropertyHashes!, $"isFirstMeta_e_{p.Name}", i + " ");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} else");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.ObjectRefFirst);");
- sb.AppendLine($"{i} context.WriteVarUInt((uint)epe_{p.Name}.CacheMapIndex);");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} {writer}.Instance.WriteProperties({e}, context, nextDepth_{p.Name});");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} else");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} if (context.UseMetadata)");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.ObjectWithMetadata);");
- EmitInlineMetadata(sb, p.ElementTypeNameHash, p.ElementPropertyHashes!, $"isFirstMeta_e_{p.Name}", i + " ");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} else");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.Object);");
- sb.AppendLine($"{i} {writer}.Instance.WriteProperties({e}, context, nextDepth_{p.Name});");
- sb.AppendLine($"{i} }}");
- }
+ sb.AppendLine($"{i} if (context.WriteObjectFullMarker{elemRefSuffix}({e}, {writer}.s_wrapperSlot)) {writer}.Instance.WriteProperties({e}, context, nextDepth_{p.Name});");
}
sb.AppendLine($"{i} }}");
@@ -1632,111 +1497,34 @@ public class AcBinarySourceGenerator : IIncrementalGenerator
///
/// Emits inline write for a Complex+SGen dictionary value with ref tracking and metadata support.
- /// Mirrors EmitDirectCollectionWrite per-element write pattern.
+ /// Delegates marker logic to runtime WriteObjectRefMarker/MetaMarker/FullMarker bridge.
///
private static void EmitDictValueComplexWrite(StringBuilder sb, PropInfo p, string v, string s, string i)
{
var writer = p.DictValueWriterClassName!;
- var valType = p.DictValueTypeName!;
sb.AppendLine($"{i}if ({v} == null) {{ context.WriteByte(BinaryTypeCode.Null); }}");
sb.AppendLine($"{i}else if (nd_{s} > context.MaxDepth) {{ context.WriteByte(BinaryTypeCode.Null); }}");
- sb.AppendLine($"{i}else");
- sb.AppendLine($"{i}{{");
- if (!p.DictValueNeedsRefScan)
+ var dvRefSuffix = p.DictValueIsIId ? "IId" : "All";
+
+ if (!p.DictValueNeedsRefScan && !p.DictValueEnableMetadata)
{
- if (!p.DictValueEnableMetadata)
- {
- // No ref, no metadata → always Object
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.Object);");
- sb.AppendLine($"{i} {writer}.Instance.WriteProperties({v}, context, nd_{s});");
- }
- else
- {
- // No ref, metadata possible
- sb.AppendLine($"{i} var isFirstMeta_dv_{s} = context.UseMetadata && AcBinarySerializer.BinarySerializationContext.RegisterMetadataType(context.GetWrapper(typeof({valType}), {writer}.s_wrapperSlot));");
- sb.AppendLine($"{i} if (context.UseMetadata)");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.ObjectWithMetadata);");
- EmitInlineMetadata(sb, p.DictValueTypeNameHash, p.DictValuePropertyHashes!, $"isFirstMeta_dv_{s}", i + " ");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} else");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.Object);");
- sb.AppendLine($"{i} {writer}.Instance.WriteProperties({v}, context, nd_{s});");
- }
+ // No ref, no metadata → always Object
+ sb.AppendLine($"{i}else {{ context.WriteByte(BinaryTypeCode.Object); {writer}.Instance.WriteProperties({v}, context, nd_{s}); }}");
+ }
+ else if (p.DictValueNeedsRefScan && !p.DictValueEnableMetadata)
+ {
+ sb.AppendLine($"{i}else if (context.WriteObjectRefMarker{dvRefSuffix}()) {writer}.Instance.WriteProperties({v}, context, nd_{s});");
+ }
+ else if (!p.DictValueNeedsRefScan && p.DictValueEnableMetadata)
+ {
+ sb.AppendLine($"{i}else {{ context.WriteObjectMetaMarker({v}, {writer}.s_wrapperSlot); {writer}.Instance.WriteProperties({v}, context, nd_{s}); }}");
}
else
{
- var dvRefGuard = p.DictValueIsIId
- ? "context.HasRefHandling"
- : "context.HasAllRefHandling";
-
- if (!p.DictValueEnableMetadata)
- {
- // Ref tracking, no metadata
- sb.AppendLine($"{i} if ({dvRefGuard} && context.TryConsumeWritePlanEntry(out var dpe_{s}))");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} if (!dpe_{s}.IsFirst)");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.ObjectRef);");
- sb.AppendLine($"{i} context.WriteVarUInt((uint)dpe_{s}.CacheMapIndex);");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} else");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.ObjectRefFirst);");
- sb.AppendLine($"{i} context.WriteVarUInt((uint)dpe_{s}.CacheMapIndex);");
- sb.AppendLine($"{i} {writer}.Instance.WriteProperties({v}, context, nd_{s});");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} else");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.Object);");
- sb.AppendLine($"{i} {writer}.Instance.WriteProperties({v}, context, nd_{s});");
- sb.AppendLine($"{i} }}");
- }
- else
- {
- // Full path: ref tracking + metadata
- sb.AppendLine($"{i} var isFirstMeta_dv_{s} = context.UseMetadata && AcBinarySerializer.BinarySerializationContext.RegisterMetadataType(context.GetWrapper(typeof({valType}), {writer}.s_wrapperSlot));");
- sb.AppendLine($"{i} if ({dvRefGuard} && context.TryConsumeWritePlanEntry(out var dpe_{s}))");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} if (!dpe_{s}.IsFirst)");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.ObjectRef);");
- sb.AppendLine($"{i} context.WriteVarUInt((uint)dpe_{s}.CacheMapIndex);");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} else");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} if (context.UseMetadata)");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.ObjectWithMetadataRefFirst);");
- sb.AppendLine($"{i} context.WriteVarUInt((uint)dpe_{s}.CacheMapIndex);");
- EmitInlineMetadata(sb, p.DictValueTypeNameHash, p.DictValuePropertyHashes!, $"isFirstMeta_dv_{s}", i + " ");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} else");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.ObjectRefFirst);");
- sb.AppendLine($"{i} context.WriteVarUInt((uint)dpe_{s}.CacheMapIndex);");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} {writer}.Instance.WriteProperties({v}, context, nd_{s});");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} else");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} if (context.UseMetadata)");
- sb.AppendLine($"{i} {{");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.ObjectWithMetadata);");
- EmitInlineMetadata(sb, p.DictValueTypeNameHash, p.DictValuePropertyHashes!, $"isFirstMeta_dv_{s}", i + " ");
- sb.AppendLine($"{i} }}");
- sb.AppendLine($"{i} else");
- sb.AppendLine($"{i} context.WriteByte(BinaryTypeCode.Object);");
- sb.AppendLine($"{i} {writer}.Instance.WriteProperties({v}, context, nd_{s});");
- sb.AppendLine($"{i} }}");
- }
+ sb.AppendLine($"{i}else if (context.WriteObjectFullMarker{dvRefSuffix}({v}, {writer}.s_wrapperSlot)) {writer}.Instance.WriteProperties({v}, context, nd_{s});");
}
-
- sb.AppendLine($"{i}}}");
}
private static void EmitSkip(StringBuilder sb, PropertyTypeKind k, string a, string typeName, string i)
@@ -2079,11 +1867,14 @@ public class AcBinarySourceGenerator : IIncrementalGenerator
{
// Compile-time proven: child never tracked → only Object (+ Null for nullable) in stream
// Inline: parent creates instance, calls ReadProperties directly (mirrors EmitDirectObjectWrite)
+ // FixObj slot bytes (0..SlotCount-1) are also valid markers here — populate slot cache
+ // to keep _nextRuntimeSlot in sync with the serializer's _nextTypeSlot counter.
if (p.IsNullable)
{
sb.AppendLine($"{i}if ({tc} == BinaryTypeCode.Null) {{ /* null */ }}");
sb.AppendLine($"{i}else");
sb.AppendLine($"{i}{{");
+ sb.AppendLine($"{i} if ({tc} < BinaryTypeCode.Object) {{ context.GetWrapper(typeof({p.TypeNameForTypeof}), {tc}); if ({tc} >= context._nextRuntimeSlot) context._nextRuntimeSlot = {tc} + 1; }}");
sb.AppendLine($"{i} var rc_{p.Name} = new {p.TypeNameForTypeof}();");
sb.AppendLine($"{i} {reader}.Instance.ReadProperties(rc_{p.Name}, context, {nd});");
sb.AppendLine($"{i} {a} = rc_{p.Name};");
@@ -2091,8 +1882,9 @@ public class AcBinarySourceGenerator : IIncrementalGenerator
}
else
{
- // ZERO branches — tc is always Object
+ // ZERO branches — tc is always Object or FixObj
sb.AppendLine($"{i}{{");
+ sb.AppendLine($"{i} if ({tc} < BinaryTypeCode.Object) {{ context.GetWrapper(typeof({p.TypeNameForTypeof}), {tc}); if ({tc} >= context._nextRuntimeSlot) context._nextRuntimeSlot = {tc} + 1; }}");
sb.AppendLine($"{i} var rc_{p.Name} = new {p.TypeNameForTypeof}();");
sb.AppendLine($"{i} {reader}.Instance.ReadProperties(rc_{p.Name}, context, {nd});");
sb.AppendLine($"{i} {a} = rc_{p.Name};");
@@ -2101,7 +1893,7 @@ public class AcBinarySourceGenerator : IIncrementalGenerator
}
else
{
- // Ref tracking possible — Object/ObjectRefFirst/ObjectRef dispatch
+ // Ref tracking possible — Object/ObjectRefFirst/ObjectRef/FixObj dispatch
// Inline: parent creates instance + handles cache registration
sb.AppendLine($"{i}if ({tc} == BinaryTypeCode.Object)");
sb.AppendLine($"{i}{{");
@@ -2121,6 +1913,16 @@ public class AcBinarySourceGenerator : IIncrementalGenerator
sb.AppendLine($"{i}else if ({tc} == BinaryTypeCode.Null) {{ /* null */ }}");
sb.AppendLine($"{i}else if ({tc} == BinaryTypeCode.ObjectRef)");
sb.AppendLine($"{i} {a} = {cast}context.GetInternedObject((int)context.ReadVarUInt())!;");
+ // FixObj slot (0..SlotCount-1): same type via FixObj marker (non-meta, non-ref mode)
+ // Populate slot cache to keep _nextRuntimeSlot in sync with the serializer.
+ sb.AppendLine($"{i}else if ({tc} < BinaryTypeCode.Object)");
+ sb.AppendLine($"{i}{{");
+ sb.AppendLine($"{i} context.GetWrapper(typeof({p.TypeNameForTypeof}), {tc});");
+ sb.AppendLine($"{i} if ({tc} >= context._nextRuntimeSlot) context._nextRuntimeSlot = {tc} + 1;");
+ sb.AppendLine($"{i} var rc_{p.Name} = new {p.TypeNameForTypeof}();");
+ sb.AppendLine($"{i} {reader}.Instance.ReadProperties(rc_{p.Name}, context, {nd});");
+ sb.AppendLine($"{i} {a} = rc_{p.Name};");
+ sb.AppendLine($"{i}}}");
}
}
@@ -2434,10 +2236,12 @@ public class AcBinarySourceGenerator : IIncrementalGenerator
if (!needsRefScan)
{
- // No ref tracking → only Object or Null in stream — inline ReadProperties
+ // No ref tracking → only Object, FixObj or Null in stream — inline ReadProperties
+ // FixObj slot: populate slot cache to keep _nextRuntimeSlot in sync.
sb.AppendLine($"{i}if ({etc} == BinaryTypeCode.Null) {{ {assignNull} }}");
sb.AppendLine($"{i}else");
sb.AppendLine($"{i}{{");
+ sb.AppendLine($"{i} if ({etc} < BinaryTypeCode.Object) {{ context.GetWrapper(typeof({elemTypeName}), {etc}); if ({etc} >= context._nextRuntimeSlot) context._nextRuntimeSlot = {etc} + 1; }}");
sb.AppendLine($"{i} var re_{propSuffix} = new {elemTypeName}();");
sb.AppendLine($"{i} {reader}.Instance.ReadProperties(re_{propSuffix}, context, nd_{propSuffix});");
sb.AppendLine($"{i} {assignExpr}");
@@ -2445,7 +2249,7 @@ public class AcBinarySourceGenerator : IIncrementalGenerator
}
else
{
- // Object hot path first, then ref markers — inline ReadProperties
+ // Object hot path first, then ref markers, then FixObj — inline ReadProperties
sb.AppendLine($"{i}if ({etc} == BinaryTypeCode.Object)");
sb.AppendLine($"{i}{{");
sb.AppendLine($"{i} var re_{propSuffix} = new {elemTypeName}();");
@@ -2466,6 +2270,16 @@ public class AcBinarySourceGenerator : IIncrementalGenerator
sb.AppendLine($"{i} col_{propSuffix}[{indexVar}] = {elemCast}context.GetInternedObject((int)context.ReadVarUInt())!;");
else
sb.AppendLine($"{i} col_{propSuffix}.{addCall}({elemCast}context.GetInternedObject((int)context.ReadVarUInt())!);");
+ // FixObj slot (0..SlotCount-1): same type via FixObj marker
+ // Populate slot cache to keep _nextRuntimeSlot in sync with the serializer.
+ sb.AppendLine($"{i}else if ({etc} < BinaryTypeCode.Object)");
+ sb.AppendLine($"{i}{{");
+ sb.AppendLine($"{i} context.GetWrapper(typeof({elemTypeName}), {etc});");
+ sb.AppendLine($"{i} if ({etc} >= context._nextRuntimeSlot) context._nextRuntimeSlot = {etc} + 1;");
+ sb.AppendLine($"{i} var re_{propSuffix} = new {elemTypeName}();");
+ sb.AppendLine($"{i} {reader}.Instance.ReadProperties(re_{propSuffix}, context, nd_{propSuffix});");
+ sb.AppendLine($"{i} {assignExpr}");
+ sb.AppendLine($"{i}}}");
}
}
diff --git a/AyCode.Core.Tests/Serialization/AcBinarySerializerDiagnosticTests.cs b/AyCode.Core.Tests/Serialization/AcBinarySerializerDiagnosticTests.cs
index ea446b6..7e1c664 100644
--- a/AyCode.Core.Tests/Serialization/AcBinarySerializerDiagnosticTests.cs
+++ b/AyCode.Core.Tests/Serialization/AcBinarySerializerDiagnosticTests.cs
@@ -247,62 +247,62 @@ public class AcBinarySerializerDiagnosticTests
};
var binary = stockTaking.ToBinary();
-
+
// Log the binary structure
Console.WriteLine($"Binary length: {binary.Length}");
-
- // Parse the header manually to understand structure
+ Console.WriteLine($"Binary hex: {string.Join(" ", binary.Select(b => b.ToString("X2")))}");
+
+ // === HEADER PARSING (using BinaryTypeCode constants) ===
var pos = 0;
var version = binary[pos++];
Console.WriteLine($"Version: {version}");
-
- var marker = binary[pos++];
- Console.WriteLine($"Marker: 0x{marker:X2}");
-
- // Skip any header data (strings interning, etc.)
- // New format uses PropertyIndex directly - no metadata header with property names
-
- // Find Object marker (0x19) or ObjectWithMetadata marker (0x1F)
- while (pos < binary.Length && binary[pos] != 0x19 && binary[pos] != 0x1F)
+
+ var headerFlags = binary[pos++];
+ Console.WriteLine($"Header flags: 0x{headerFlags:X2}");
+
+ bool hasMetadata = (headerFlags & BinaryTypeCode.HeaderFlag_Metadata) != 0;
+ bool hasRefOnlyId = (headerFlags & BinaryTypeCode.HeaderFlag_RefHandling_OnlyId) != 0;
+ bool hasRefAll = (headerFlags & BinaryTypeCode.HeaderFlag_RefHandling_All) != 0;
+ bool hasCacheCount = (headerFlags & BinaryTypeCode.HeaderFlag_HasCacheCount) != 0;
+ Console.WriteLine($" Metadata={hasMetadata}, RefOnlyId={hasRefOnlyId}, RefAll={hasRefAll}, HasCacheCount={hasCacheCount}");
+
+ if (hasCacheCount)
{
- pos++;
+ var ccByte = binary[pos];
+ int cacheCount = (ccByte & 0x80) == 0 ? ccByte : (ccByte & 0x7F) | (binary[pos + 1] << 7);
+ pos += (ccByte & 0x80) == 0 ? 1 : 2;
+ Console.WriteLine($"Cache count: {cacheCount}");
}
Console.WriteLine($"\n=== BODY (starts at position {pos}) ===");
- // The body should start with Object (0x19) or ObjectWithMetadata (0x1F) marker
- var bodyStart = pos;
+ // Read the object marker — can be FixObj slot (0..SlotCount-1) or explicit marker
var objectMarker = binary[pos++];
- Console.WriteLine($"Object marker: 0x{objectMarker:X2} (0x19=Object, 0x1F=ObjectWithMetadata)");
- Assert.IsTrue(objectMarker == 0x19 || objectMarker == 0x1F,
- $"Object marker should be 0x19 or 0x1F, got 0x{objectMarker:X2}");
+ bool isFixObj = objectMarker < BinaryTypeCode.SlotCount;
+ Console.WriteLine($"Object marker: 0x{objectMarker:X2} (FixObj={isFixObj}, " +
+ $"Object=0x{BinaryTypeCode.Object:X2}, ObjectRefFirst=0x{BinaryTypeCode.ObjectRefFirst:X2}, " +
+ $"ObjectWithMetadata=0x{BinaryTypeCode.ObjectWithMetadata:X2})");
- // If ObjectWithMetadata (0x1F), skip inline metadata
- if (objectMarker == 0x1F)
+ Assert.IsTrue(
+ isFixObj
+ || objectMarker == BinaryTypeCode.Object
+ || objectMarker == BinaryTypeCode.ObjectWithMetadata
+ || objectMarker == BinaryTypeCode.ObjectRefFirst
+ || objectMarker == BinaryTypeCode.ObjectWithMetadataRefFirst,
+ $"Expected an object marker, got 0x{objectMarker:X2}");
+
+ // If ObjectWithMetadata, skip inline metadata
+ if (objectMarker is BinaryTypeCode.ObjectWithMetadata or BinaryTypeCode.ObjectWithMetadataRefFirst)
{
- // propNameHash (4 bytes)
var propNameHash = BitConverter.ToInt32(binary, pos);
pos += 4;
Console.WriteLine($"PropNameHash: 0x{propNameHash:X8}");
- // First occurrence: propCount (VarUInt) + property hashes
- // VarUInt: if top bit is set, continue reading
- var propCountByte = binary[pos];
- int inlinePropCount;
- if ((propCountByte & 0x80) == 0)
- {
- inlinePropCount = propCountByte;
- pos++;
- }
- else
- {
- // Multi-byte VarUInt - simplified 2-byte parsing
- inlinePropCount = (propCountByte & 0x7F) | (binary[pos + 1] << 7);
- pos += 2;
- }
+ var pcByte = binary[pos];
+ int inlinePropCount = (pcByte & 0x80) == 0 ? pcByte : (pcByte & 0x7F) | (binary[pos + 1] << 7);
+ pos += (pcByte & 0x80) == 0 ? 1 : 2;
Console.WriteLine($"Inline metadata propCount: {inlinePropCount}");
- // Skip property hashes (4 bytes each)
for (int h = 0; h < inlinePropCount; h++)
{
var hash = BitConverter.ToInt32(binary, pos);
@@ -311,68 +311,57 @@ public class AcBinarySerializerDiagnosticTests
}
}
- // Read ref ID (if reference handling is enabled)
- // VarInt: if top bit is set, continue reading
- var refIdByte = binary[pos];
- int refId;
- if ((refIdByte & 0x80) == 0)
+ // If RefFirst marker, read VarUInt cache index
+ if (objectMarker is BinaryTypeCode.ObjectRefFirst or BinaryTypeCode.ObjectWithMetadataRefFirst)
{
- refId = refIdByte;
- pos++;
+ var rByte = binary[pos];
+ int refCacheIndex = (rByte & 0x80) == 0 ? rByte : (rByte & 0x7F) | (binary[pos + 1] << 7);
+ pos += (rByte & 0x80) == 0 ? 1 : 2;
+ Console.WriteLine($"RefCacheIndex: {refCacheIndex}");
}
- else
- {
- // Multi-byte VarInt - simplified parsing
- refId = -1;
- pos += 2; // Skip for now
- }
- Console.WriteLine($"RefId: {refId}");
- // Read property count in body
- var bodyPropCount = binary[pos++];
- Console.WriteLine($"Property count in body: {bodyPropCount}");
-
- Console.WriteLine($"\n=== BODY PROPERTIES ===");
- for (int i = 0; i < bodyPropCount && pos < binary.Length; i++)
+ // Markerless format: properties are written in order, no property count header
+ Console.WriteLine($"\n=== BODY PROPERTIES (remaining {binary.Length - pos} bytes) ===");
+ int propIdx = 0;
+ while (pos < binary.Length)
{
- // Log the value (no PropertyIndex in inline metadata mode — properties are in hash order)
- var valueType = binary[pos];
- if (valueType == 0x14) // DateTime
+ var b = binary[pos];
+ if (b == BinaryTypeCode.DateTime)
{
- Console.WriteLine($" Property [{i}]: DateTime (9 bytes)");
- pos += 10; // type + 9 bytes
+ Console.WriteLine($" Property [{propIdx}]: DateTime (1+8 bytes)");
+ pos += 9; // marker + 8 bytes ticks
}
- else if (valueType >= 0xC0 && valueType <= 0xFF) // TinyInt (192-255)
+ else if (BinaryTypeCode.IsTinyInt(b))
{
- var tinyValue = valueType - 192 - 16;
- Console.WriteLine($" Property [{i}]: TinyInt value: {tinyValue}");
+ Console.WriteLine($" Property [{propIdx}]: TinyInt value={BinaryTypeCode.DecodeTinyInt(b)} (0x{b:X2})");
pos += 1;
}
- else if (valueType == 0x02) // False (BinaryTypeCode.False = 2)
+ else if (b == BinaryTypeCode.False)
{
- Console.WriteLine($" Property [{i}]: Boolean: false");
+ Console.WriteLine($" Property [{propIdx}]: Boolean: false");
pos += 1;
}
- else if (valueType == 0x01) // True (BinaryTypeCode.True = 1)
+ else if (b == BinaryTypeCode.True)
{
- Console.WriteLine($" Property [{i}]: Boolean: true");
+ Console.WriteLine($" Property [{propIdx}]: Boolean: true");
pos += 1;
}
- else if (valueType == 0x00) // Null
+ else if (b == BinaryTypeCode.Null)
{
- Console.WriteLine($" Property [{i}]: Null");
+ Console.WriteLine($" Property [{propIdx}]: Null");
pos += 1;
}
- else if (valueType == 0xBF) // PropertySkip
+ else if (b == BinaryTypeCode.PropertySkip)
{
- Console.WriteLine($" Property [{i}]: PropertySkip (default/null)");
+ Console.WriteLine($" Property [{propIdx}]: PropertySkip (default/null)");
pos += 1;
}
else
{
- Console.WriteLine($" Property [{i}]: Unknown type: 0x{valueType:X2}");
+ Console.WriteLine($" Property [{propIdx}]: Unknown type: 0x{b:X2}");
break;
}
+ propIdx++;
}
// Deserialize and verify
diff --git a/AyCode.Core.Tests/Serialization/AcBinarySerializerIIdReferenceTests.cs b/AyCode.Core.Tests/Serialization/AcBinarySerializerIIdReferenceTests.cs
index 33a33cb..c58e110 100644
--- a/AyCode.Core.Tests/Serialization/AcBinarySerializerIIdReferenceTests.cs
+++ b/AyCode.Core.Tests/Serialization/AcBinarySerializerIIdReferenceTests.cs
@@ -22,13 +22,11 @@ namespace AyCode.Core.Tests.Serialization;
[TestClass]
public class AcBinarySerializerIIdReferenceTests
{
- // BinaryTypeCode.ObjectRef = 27
- private const byte ObjectRefTypeCode = 27;
-
#region Helper Methods
///
- /// Counts occurrences of ObjectRef (0x1B = 27) in binary data.
+ /// Counts occurrences of ObjectRef in binary data.
+ /// Uses BinaryTypeCode.ObjectRef constant to stay in sync with format changes.
///
private static int CountObjectRefs(byte[] binary, bool writeBinaryToConsole = true)
{
@@ -37,7 +35,7 @@ public class AcBinarySerializerIIdReferenceTests
var count = 0;
for (var i = 0; i < binary.Length; i++)
{
- if (binary[i] == ObjectRefTypeCode)
+ if (binary[i] == BinaryTypeCode.ObjectRef)
count++;
}
return count;
@@ -151,7 +149,10 @@ public class AcBinarySerializerIIdReferenceTests
{
case ReferenceHandlingMode.None:
//none esetén miért nincs infinite loop??? - J.
- Assert.AreEqual(0, objectRefCount, $"[{mode}] Should have 0 ObjectRefs");
+ // Note: CountObjectRefs raw byte scan is unreliable in None mode —
+ // byte 65 (ObjectRef) == ASCII 'A', so "Product-A" and circular-ref
+ // depth expansion produce many false positives. Skip count assertion;
+ // data integrity checks below verify correct deserialization.
//WriteBinaryToConsole(binary);
break;
diff --git a/AyCode.Core.Tests/TestModels/AcSerializerModels.cs b/AyCode.Core.Tests/TestModels/AcSerializerModels.cs
index 3c79ed8..8e31575 100644
--- a/AyCode.Core.Tests/TestModels/AcSerializerModels.cs
+++ b/AyCode.Core.Tests/TestModels/AcSerializerModels.cs
@@ -1,4 +1,5 @@
using AyCode.Core.Interfaces;
+using AyCode.Core.Serializers.Attributes;
using AyCode.Core.Serializers.Binaries;
namespace AyCode.Core.Tests.TestModels;
@@ -8,6 +9,7 @@ namespace AyCode.Core.Tests.TestModels;
///
public static class AcSerializerModels
{
+ [AcBinarySerializable(true)]
public class TestSimpleClass
{
public int Id { get; set; }
diff --git a/AyCode.Core/AyCode.Core.csproj b/AyCode.Core/AyCode.Core.csproj
index 3a6e6dc..9f8c9c2 100644
--- a/AyCode.Core/AyCode.Core.csproj
+++ b/AyCode.Core/AyCode.Core.csproj
@@ -25,7 +25,8 @@
-
+
+
diff --git a/AyCode.Core/Serializers/Binaries/AcBinaryDeserializer.cs b/AyCode.Core/Serializers/Binaries/AcBinaryDeserializer.cs
index b2d2fbf..fe5ff4e 100644
--- a/AyCode.Core/Serializers/Binaries/AcBinaryDeserializer.cs
+++ b/AyCode.Core/Serializers/Binaries/AcBinaryDeserializer.cs
@@ -359,7 +359,16 @@ public static partial class AcBinaryDeserializer
context.ReadHeader();
var typeCode = context.PeekByte();
- if (typeCode == BinaryTypeCode.Object)
+ if (typeCode < BinaryTypeCode.SlotCount)
+ {
+ // FixObj slot: marker byte is the slot index
+ context.ReadByte();
+ context.GetWrapper(targetType, typeCode);
+ if (typeCode >= context._nextRuntimeSlot)
+ context._nextRuntimeSlot = typeCode + 1;
+ PopulateObject(context, target, targetType, 0);
+ }
+ else if (typeCode == BinaryTypeCode.Object)
{
context.ReadByte();
PopulateObject(context, target, targetType, 0);
@@ -520,7 +529,16 @@ public static partial class AcBinaryDeserializer
context.ReadHeader();
var typeCode = context.PeekByte();
- if (typeCode == BinaryTypeCode.Object)
+ if (typeCode < BinaryTypeCode.SlotCount)
+ {
+ // FixObj slot: marker byte is the slot index
+ context.ReadByte();
+ context.GetWrapper(targetType, typeCode);
+ if (typeCode >= context._nextRuntimeSlot)
+ context._nextRuntimeSlot = typeCode + 1;
+ PopulateObject(context, target, targetType, 0);
+ }
+ else if (typeCode == BinaryTypeCode.Object)
{
context.ReadByte();
PopulateObject(context, target, targetType, 0);
diff --git a/AyCode.Core/Serializers/Binaries/AcBinarySerializer.BinarySerializationContext.PropertyWriters.cs b/AyCode.Core/Serializers/Binaries/AcBinarySerializer.BinarySerializationContext.PropertyWriters.cs
new file mode 100644
index 0000000..4292360
--- /dev/null
+++ b/AyCode.Core/Serializers/Binaries/AcBinarySerializer.BinarySerializationContext.PropertyWriters.cs
@@ -0,0 +1,457 @@
+using System.Runtime.CompilerServices;
+
+namespace AyCode.Core.Serializers.Binaries;
+
+public static partial class AcBinarySerializer
+{
+ internal sealed partial class BinarySerializationContext
+ where TOutput : struct, IBinaryOutputBase
+ {
+ #region Property Writer Bridges — used by SGen generated code
+
+ ///
+ /// Writes an Int32 property value. UseMetadata: skip if 0, TinyInt or Int32+VarInt. Markerless: VarInt only.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void WriteInt32Property(int value)
+ {
+ if (UseMetadata)
+ {
+ if (value == 0) { WriteByte(BinaryTypeCode.PropertySkip); return; }
+ if (BinaryTypeCode.TryEncodeTinyInt(value, out var tiny)) { WriteByte(tiny); return; }
+ WriteByte(BinaryTypeCode.Int32);
+ }
+
+ WriteVarInt(value);
+ }
+
+ ///
+ /// Writes an Int64 property value. UseMetadata: skip if 0, int-range TinyInt or Int64+VarLong. Markerless: VarLong only.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void WriteInt64Property(long value)
+ {
+ if (UseMetadata)
+ {
+ if (value == 0L) { WriteByte(BinaryTypeCode.PropertySkip); return; }
+ if (value >= int.MinValue && value <= int.MaxValue)
+ {
+ var iv = (int)value;
+ if (BinaryTypeCode.TryEncodeTinyInt(iv, out var tiny)) { WriteByte(tiny); return; }
+ WriteByte(BinaryTypeCode.Int32);
+ WriteVarInt(iv);
+ }
+ else
+ {
+ WriteByte(BinaryTypeCode.Int64);
+ WriteVarLong(value);
+ }
+ }
+ else
+ {
+ WriteVarLong(value);
+ }
+ }
+
+ ///
+ /// Writes a Boolean property value. UseMetadata: skip if false, else True. Markerless: 1/0 byte.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void WriteBoolProperty(bool value)
+ {
+ if (UseMetadata)
+ WriteByte(value ? BinaryTypeCode.True : BinaryTypeCode.PropertySkip);
+ else
+ WriteByte(value ? (byte)1 : (byte)0);
+ }
+
+ ///
+ /// Writes a Double property value. UseMetadata: skip if 0.0, else Float64+Raw. Markerless: Raw only.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void WriteFloat64Property(double value)
+ {
+ if (UseMetadata)
+ {
+ if (value == 0.0) { WriteByte(BinaryTypeCode.PropertySkip); return; }
+ WriteTypeCodeAndRaw(BinaryTypeCode.Float64, value);
+ }
+ else
+ {
+ WriteRaw(value);
+ }
+ }
+
+ ///
+ /// Writes a Single property value. UseMetadata: skip if 0f, else Float32+Raw. Markerless: Raw only.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void WriteFloat32Property(float value)
+ {
+ if (UseMetadata)
+ {
+ if (value == 0f) { WriteByte(BinaryTypeCode.PropertySkip); return; }
+ WriteTypeCodeAndRaw(BinaryTypeCode.Float32, value);
+ }
+ else
+ {
+ WriteRaw(value);
+ }
+ }
+
+ ///
+ /// Writes a Decimal property value. UseMetadata: skip if 0m, else Decimal+Bits. Markerless: DecimalBits only.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void WriteDecimalProperty(decimal value)
+ {
+ if (UseMetadata)
+ {
+ if (value == 0m) { WriteByte(BinaryTypeCode.PropertySkip); return; }
+ WriteByte(BinaryTypeCode.Decimal);
+ }
+
+ WriteDecimalBits(value);
+ }
+
+ ///
+ /// Writes a Guid property value. UseMetadata: skip if Empty, else Guid+Bits. Markerless: GuidBits only.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void WriteGuidProperty(Guid value)
+ {
+ if (UseMetadata)
+ {
+ if (value == Guid.Empty) { WriteByte(BinaryTypeCode.PropertySkip); return; }
+ WriteByte(BinaryTypeCode.Guid);
+ }
+
+ WriteGuidBits(value);
+ }
+
+ ///
+ /// Writes a DateTime property value. UseMetadata: DateTime+Bits (no skip). Markerless: DateTimeBits only.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void WriteDateTimeProperty(DateTime value)
+ {
+ if (UseMetadata)
+ {
+ WriteByte(BinaryTypeCode.DateTime);
+ }
+
+ WriteDateTimeBits(value);
+ }
+
+ ///
+ /// Writes a Byte property value. UseMetadata: skip if 0, else UInt8+byte. Markerless: byte only.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void WriteByteProperty(byte value)
+ {
+ if (UseMetadata)
+ {
+ if (value == 0) { WriteByte(BinaryTypeCode.PropertySkip); return; }
+ WriteByte(BinaryTypeCode.UInt8);
+ }
+
+ WriteByte(value);
+ }
+
+ ///
+ /// Writes an Int16 property value. UseMetadata: skip if 0, else Int16+Raw. Markerless: Raw only.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void WriteInt16Property(short value)
+ {
+ if (UseMetadata)
+ {
+ if (value == 0) { WriteByte(BinaryTypeCode.PropertySkip); return; }
+ WriteTypeCodeAndRaw(BinaryTypeCode.Int16, value);
+ }
+ else
+ {
+ WriteRaw(value);
+ }
+ }
+
+ ///
+ /// Writes a UInt16 property value. UseMetadata: skip if 0, else UInt16+Raw. Markerless: Raw only.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void WriteUInt16Property(ushort value)
+ {
+ if (UseMetadata)
+ {
+ if (value == 0) { WriteByte(BinaryTypeCode.PropertySkip); return; }
+ WriteTypeCodeAndRaw(BinaryTypeCode.UInt16, value);
+ }
+ else
+ {
+ WriteRaw(value);
+ }
+ }
+
+ ///
+ /// Writes a UInt32 property value. UseMetadata: skip if 0, else UInt32+VarUInt. Markerless: VarUInt only.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void WriteUInt32Property(uint value)
+ {
+ if (UseMetadata)
+ {
+ if (value == 0) { WriteByte(BinaryTypeCode.PropertySkip); return; }
+ WriteByte(BinaryTypeCode.UInt32);
+ }
+
+ WriteVarUInt(value);
+ }
+
+ ///
+ /// Writes a UInt64 property value. UseMetadata: skip if 0, else UInt64+VarULong. Markerless: VarULong only.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void WriteUInt64Property(ulong value)
+ {
+ if (UseMetadata)
+ {
+ if (value == 0) { WriteByte(BinaryTypeCode.PropertySkip); return; }
+ WriteByte(BinaryTypeCode.UInt64);
+ }
+
+ WriteVarULong(value);
+ }
+
+ ///
+ /// Writes an Enum property value (pre-cast to int). UseMetadata: skip if 0, else Enum+TinyInt/VarInt. Markerless: VarInt only.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void WriteEnumInt32Property(int value)
+ {
+ if (UseMetadata)
+ {
+ if (value == 0) { WriteByte(BinaryTypeCode.PropertySkip); return; }
+ WriteByte(BinaryTypeCode.Enum);
+ if (BinaryTypeCode.TryEncodeTinyInt(value, out var tiny))
+ WriteByte(tiny);
+ else
+ {
+ WriteByte(BinaryTypeCode.Int32);
+ WriteVarInt(value);
+ }
+ }
+ else
+ {
+ WriteVarInt(value);
+ }
+ }
+
+ ///
+ /// Writes a TimeSpan property value. UseMetadata: TimeSpan+Raw(Ticks). Markerless: Raw(Ticks) only. No skip.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void WriteTimeSpanProperty(TimeSpan value)
+ {
+ if (UseMetadata)
+ WriteTypeCodeAndRaw(BinaryTypeCode.TimeSpan, value.Ticks);
+ else
+ WriteRaw(value.Ticks);
+ }
+
+ ///
+ /// Writes a DateTimeOffset property value. UseMetadata: DateTimeOffset+Bits. Markerless: DateTimeOffsetBits only. No skip.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void WriteDateTimeOffsetProperty(DateTimeOffset value)
+ {
+ if (UseMetadata)
+ {
+ WriteByte(BinaryTypeCode.DateTimeOffset);
+ }
+
+ WriteDateTimeOffsetBits(value);
+ }
+
+ #endregion
+
+ #region Object Marker — SGen bridge for complex child writes
+ // SGen selects the correct variant at compile-time based on ChildNeedsRefScan / ChildEnableMetadata / IsIId.
+ // The 4th case (!ref && !meta) is handled inline by SGen: Object + WriteProperties (ZERO branches).
+ // Marker methods write only the object marker bytes. WriteProperties is called directly in SGen
+ // (preserving direct call — no interface dispatch on IGeneratedBinaryWriter).
+
+ ///
+ /// Ref tracking (IId) only, no metadata. Uses HasRefHandling.
+ /// Returns false if ObjectRef 2nd occurrence (caller must skip WriteProperties).
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal bool WriteObjectRefMarkerIId()
+ {
+ if (HasRefHandling && TryConsumeWritePlanEntry(out var pe))
+ {
+ if (!pe.IsFirst)
+ {
+ WriteByte(BinaryTypeCode.ObjectRef);
+ WriteVarUInt((uint)pe.CacheMapIndex);
+ return false;
+ }
+
+ WriteByte(BinaryTypeCode.ObjectRefFirst);
+ WriteVarUInt((uint)pe.CacheMapIndex);
+ return true;
+ }
+
+ WriteByte(BinaryTypeCode.Object);
+ return true;
+ }
+
+ ///
+ /// Ref tracking (AllRef) only, no metadata. Uses HasAllRefHandling.
+ /// Returns false if ObjectRef 2nd occurrence (caller must skip WriteProperties).
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal bool WriteObjectRefMarkerAll()
+ {
+ if (HasAllRefHandling && TryConsumeWritePlanEntry(out var pe))
+ {
+ if (!pe.IsFirst)
+ {
+ WriteByte(BinaryTypeCode.ObjectRef);
+ WriteVarUInt((uint)pe.CacheMapIndex);
+ return false;
+ }
+
+ WriteByte(BinaryTypeCode.ObjectRefFirst);
+ WriteVarUInt((uint)pe.CacheMapIndex);
+ return true;
+ }
+
+ WriteByte(BinaryTypeCode.Object);
+ return true;
+ }
+
+ ///
+ /// Metadata only, no ref tracking. Writes ObjectWithMetadata or Object marker.
+ /// Always returns — caller always calls WriteProperties after this.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void WriteObjectMetaMarker(object value, int wrapperSlot)
+ {
+ if (UseMetadata)
+ {
+ var wrapper = GetWrapper(value.GetType(), wrapperSlot);
+ var isFirstMeta = RegisterMetadataType(wrapper);
+ WriteByte(BinaryTypeCode.ObjectWithMetadata);
+ WriteInlineMetadata(wrapper.Metadata, isFirstMeta);
+ }
+ else
+ {
+ WriteByte(BinaryTypeCode.Object);
+ }
+ }
+
+ ///
+ /// Full path (IId): ref tracking + metadata. Uses HasRefHandling.
+ /// Returns false if ObjectRef 2nd occurrence (caller must skip WriteProperties).
+ ///
+ internal bool WriteObjectFullMarkerIId(object value, int wrapperSlot)
+ {
+ var useMetadata = UseMetadata;
+ bool isFirstMeta = false;
+ if (useMetadata)
+ {
+ var wrapper = GetWrapper(value.GetType(), wrapperSlot);
+ isFirstMeta = RegisterMetadataType(wrapper);
+ }
+
+ if (HasRefHandling && TryConsumeWritePlanEntry(out var pe))
+ {
+ if (!pe.IsFirst)
+ {
+ WriteByte(BinaryTypeCode.ObjectRef);
+ WriteVarUInt((uint)pe.CacheMapIndex);
+ return false;
+ }
+
+ if (useMetadata)
+ {
+ WriteByte(BinaryTypeCode.ObjectWithMetadataRefFirst);
+ WriteVarUInt((uint)pe.CacheMapIndex);
+ WriteInlineMetadata(GetWrapper(value.GetType(), wrapperSlot).Metadata, isFirstMeta);
+ }
+ else
+ {
+ WriteByte(BinaryTypeCode.ObjectRefFirst);
+ WriteVarUInt((uint)pe.CacheMapIndex);
+ }
+
+ return true;
+ }
+
+ if (useMetadata)
+ {
+ WriteByte(BinaryTypeCode.ObjectWithMetadata);
+ WriteInlineMetadata(GetWrapper(value.GetType(), wrapperSlot).Metadata, isFirstMeta);
+ }
+ else
+ {
+ WriteByte(BinaryTypeCode.Object);
+ }
+
+ return true;
+ }
+
+ ///
+ /// Full path (AllRef): ref tracking + metadata. Uses HasAllRefHandling.
+ /// Returns false if ObjectRef 2nd occurrence (caller must skip WriteProperties).
+ ///
+ internal bool WriteObjectFullMarkerAll(object value, int wrapperSlot)
+ {
+ var useMetadata = UseMetadata;
+ bool isFirstMeta = false;
+ if (useMetadata)
+ {
+ var wrapper = GetWrapper(value.GetType(), wrapperSlot);
+ isFirstMeta = RegisterMetadataType(wrapper);
+ }
+
+ if (HasAllRefHandling && TryConsumeWritePlanEntry(out var pe))
+ {
+ if (!pe.IsFirst)
+ {
+ WriteByte(BinaryTypeCode.ObjectRef);
+ WriteVarUInt((uint)pe.CacheMapIndex);
+ return false;
+ }
+
+ if (useMetadata)
+ {
+ WriteByte(BinaryTypeCode.ObjectWithMetadataRefFirst);
+ WriteVarUInt((uint)pe.CacheMapIndex);
+ WriteInlineMetadata(GetWrapper(value.GetType(), wrapperSlot).Metadata, isFirstMeta);
+ }
+ else
+ {
+ WriteByte(BinaryTypeCode.ObjectRefFirst);
+ WriteVarUInt((uint)pe.CacheMapIndex);
+ }
+
+ return true;
+ }
+
+ if (useMetadata)
+ {
+ WriteByte(BinaryTypeCode.ObjectWithMetadata);
+ WriteInlineMetadata(GetWrapper(value.GetType(), wrapperSlot).Metadata, isFirstMeta);
+ }
+ else
+ {
+ WriteByte(BinaryTypeCode.Object);
+ }
+
+ return true;
+ }
+
+ #endregion
+ }
+}
diff --git a/AyCode.Core/Serializers/Binaries/AcBinarySerializer.BinarySerializationContext.cs b/AyCode.Core/Serializers/Binaries/AcBinarySerializer.BinarySerializationContext.cs
index 432addf..3497ee0 100644
--- a/AyCode.Core/Serializers/Binaries/AcBinarySerializer.BinarySerializationContext.cs
+++ b/AyCode.Core/Serializers/Binaries/AcBinarySerializer.BinarySerializationContext.cs
@@ -56,7 +56,7 @@ public static partial class AcBinarySerializer
/// All write operations (WriteByte, WriteVarUInt, etc.) are inline methods here.
/// TOutput Output handles only cold-path buffer management (Grow/Initialize) and finalization.
///
- internal sealed class BinarySerializationContext
+ internal sealed partial class BinarySerializationContext
: SerializationContextBase, IDisposable
where TOutput : struct, IBinaryOutputBase
{
diff --git a/AyCode.Core/Serializers/Binaries/AcBinarySerializer.cs b/AyCode.Core/Serializers/Binaries/AcBinarySerializer.cs
index 081a399..018236f 100644
--- a/AyCode.Core/Serializers/Binaries/AcBinarySerializer.cs
+++ b/AyCode.Core/Serializers/Binaries/AcBinarySerializer.cs
@@ -1327,11 +1327,7 @@ public static partial class AcBinarySerializer
{
var prop = properties[i];
- if (prop.ExpectedTypeCode.HasValue)
- {
- WritePropertyMarkerless(value, prop, context);
- }
- else if (hasPropertyFilter && !context.ShouldSerializeProperty(value, prop))
+ if (!prop.ExpectedTypeCode.HasValue && hasPropertyFilter && !context.ShouldSerializeProperty(value, prop))
{
context.WriteByte(BinaryTypeCode.PropertySkip);
}
@@ -1537,8 +1533,9 @@ public static partial class AcBinarySerializer
///
/// Writes a property value OR a skip marker if the value is default/null.
- /// Single-pass optimization: checks default + writes value in one operation.
- /// Avoids double getter calls.
+ /// Delegates to PropertyWriter bridge methods which handle UseMetadata internally:
+ /// UseMetadata=true: skip marker for defaults, type code + value for non-defaults.
+ /// UseMetadata=false (markerless): raw value only, no skip markers.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void WritePropertyOrSkip(object obj, BinaryPropertyAccessor prop, TypeMetadataWrapper parentWrapper, BinarySerializationContext context, int depth)
@@ -1547,143 +1544,47 @@ public static partial class AcBinarySerializer
switch (prop.AccessorType)
{
case PropertyAccessorType.Int32:
- {
- int value = prop.GetInt32(obj);
- if (value == 0)
- context.WriteByte(BinaryTypeCode.PropertySkip);
- else
- WriteInt32(value, context);
- return;
- }
+ context.WriteInt32Property(prop.GetInt32(obj));
+ return;
case PropertyAccessorType.Int64:
- {
- long value = prop.GetInt64(obj);
- if (value == 0L)
- context.WriteByte(BinaryTypeCode.PropertySkip);
- else
- WriteInt64(value, context);
- return;
- }
+ context.WriteInt64Property(prop.GetInt64(obj));
+ return;
case PropertyAccessorType.Boolean:
- {
- bool value = prop.GetBoolean(obj);
- if (!value)
- context.WriteByte(BinaryTypeCode.PropertySkip);
- else
- context.WriteByte(BinaryTypeCode.True);
- return;
- }
+ context.WriteBoolProperty(prop.GetBoolean(obj));
+ return;
case PropertyAccessorType.Double:
- {
- double value = prop.GetDouble(obj);
- if (value == 0.0)
- context.WriteByte(BinaryTypeCode.PropertySkip);
- else
- WriteFloat64Unsafe(value, context);
- return;
- }
+ context.WriteFloat64Property(prop.GetDouble(obj));
+ return;
case PropertyAccessorType.Single:
- {
- float value = prop.GetSingle(obj);
- if (value == 0f)
- context.WriteByte(BinaryTypeCode.PropertySkip);
- else
- WriteFloat32Unsafe(value, context);
- return;
- }
+ context.WriteFloat32Property(prop.GetSingle(obj));
+ return;
case PropertyAccessorType.Decimal:
- {
- decimal value = prop.GetDecimal(obj);
- if (value == 0m)
- context.WriteByte(BinaryTypeCode.PropertySkip);
- else
- WriteDecimalUnsafe(value, context);
- return;
- }
+ context.WriteDecimalProperty(prop.GetDecimal(obj));
+ return;
case PropertyAccessorType.DateTime:
- {
- DateTime value = prop.GetDateTime(obj);
- // DateTime always written (no default skip)
- WriteDateTimeUnsafe(value, context);
- return;
- }
+ context.WriteDateTimeProperty(prop.GetDateTime(obj));
+ return;
case PropertyAccessorType.Byte:
- {
- byte value = prop.GetByte(obj);
- if (value == 0)
- context.WriteByte(BinaryTypeCode.PropertySkip);
- else
- {
- context.WriteByte(BinaryTypeCode.UInt8);
- context.WriteByte(value);
- }
- return;
- }
+ context.WriteByteProperty(prop.GetByte(obj));
+ return;
case PropertyAccessorType.Int16:
- {
- short value = prop.GetInt16(obj);
- if (value == 0)
- context.WriteByte(BinaryTypeCode.PropertySkip);
- else
- WriteInt16Unsafe(value, context);
- return;
- }
+ context.WriteInt16Property(prop.GetInt16(obj));
+ return;
case PropertyAccessorType.UInt16:
- {
- ushort value = prop.GetUInt16(obj);
- if (value == 0)
- context.WriteByte(BinaryTypeCode.PropertySkip);
- else
- WriteUInt16Unsafe(value, context);
- return;
- }
+ context.WriteUInt16Property(prop.GetUInt16(obj));
+ return;
case PropertyAccessorType.UInt32:
- {
- uint value = prop.GetUInt32(obj);
- if (value == 0)
- context.WriteByte(BinaryTypeCode.PropertySkip);
- else
- WriteUInt32(value, context);
- return;
- }
+ context.WriteUInt32Property(prop.GetUInt32(obj));
+ return;
case PropertyAccessorType.UInt64:
- {
- ulong value = prop.GetUInt64(obj);
- if (value == 0)
- context.WriteByte(BinaryTypeCode.PropertySkip);
- else
- WriteUInt64(value, context);
- return;
- }
+ context.WriteUInt64Property(prop.GetUInt64(obj));
+ return;
case PropertyAccessorType.Guid:
- {
- Guid value = prop.GetGuid(obj);
- if (value == Guid.Empty)
- context.WriteByte(BinaryTypeCode.PropertySkip);
- else
- WriteGuidUnsafe(value, context);
- return;
- }
+ context.WriteGuidProperty(prop.GetGuid(obj));
+ return;
case PropertyAccessorType.Enum:
- {
- int enumValue = prop.GetEnumAsInt32(obj);
- if (enumValue == 0)
- {
- context.WriteByte(BinaryTypeCode.PropertySkip);
- }
- else if (BinaryTypeCode.TryEncodeTinyInt(enumValue, out var tiny))
- {
- context.WriteByte(BinaryTypeCode.Enum);
- context.WriteByte(tiny);
- }
- else
- {
- context.WriteByte(BinaryTypeCode.Enum);
- context.WriteByte(BinaryTypeCode.Int32);
- context.WriteVarInt(enumValue);
- }
- return;
- }
+ context.WriteEnumInt32Property(prop.GetEnumAsInt32(obj));
+ return;
case PropertyAccessorType.String:
{
// Fast path: typed getter, no boxing, no Type.GetTypeCode() call
@@ -1744,62 +1645,6 @@ public static partial class AcBinarySerializer
}
}
- ///
- /// Writes a property value without type marker byte (markerless mode, UseMetadata=false).
- /// All values are written including defaults — no PropertySkip markers.
- /// Only called for non-nullable value types with ExpectedTypeCode set.
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void WritePropertyMarkerless(object obj, BinaryPropertyAccessor prop, BinarySerializationContext context)
- where TOutput : struct, IBinaryOutputBase
- {
- switch (prop.AccessorType)
- {
- case PropertyAccessorType.Int32:
- context.WriteVarInt(prop.GetInt32(obj));
- return;
- case PropertyAccessorType.Int64:
- context.WriteVarLong(prop.GetInt64(obj));
- return;
- case PropertyAccessorType.Double:
- context.WriteRaw(prop.GetDouble(obj));
- return;
- case PropertyAccessorType.Single:
- context.WriteRaw(prop.GetSingle(obj));
- return;
- case PropertyAccessorType.Decimal:
- context.WriteDecimalBits(prop.GetDecimal(obj));
- return;
- case PropertyAccessorType.DateTime:
- context.WriteDateTimeBits(prop.GetDateTime(obj));
- return;
- case PropertyAccessorType.Guid:
- context.WriteGuidBits(prop.GetGuid(obj));
- return;
- case PropertyAccessorType.Byte:
- context.WriteByte(prop.GetByte(obj));
- return;
- case PropertyAccessorType.Int16:
- context.WriteRaw(prop.GetInt16(obj));
- return;
- case PropertyAccessorType.UInt16:
- context.WriteRaw(prop.GetUInt16(obj));
- return;
- case PropertyAccessorType.UInt32:
- context.WriteVarUInt(prop.GetUInt32(obj));
- return;
- case PropertyAccessorType.UInt64:
- context.WriteVarULong(prop.GetUInt64(obj));
- return;
- case PropertyAccessorType.Boolean:
- context.WriteByte(prop.GetBoolean(obj) ? (byte)1 : (byte)0);
- return;
- case PropertyAccessorType.Enum:
- context.WriteVarInt(prop.GetEnumAsInt32(obj));
- return;
- }
- }
-
#endregion
#region Specialized Array Writers