diff --git a/AyCode.Core.Serializers.Console/AyCode.Core.Serializers.Console.csproj b/AyCode.Core.Serializers.Console/AyCode.Core.Serializers.Console.csproj
index 32fbf97..0f900d8 100644
--- a/AyCode.Core.Serializers.Console/AyCode.Core.Serializers.Console.csproj
+++ b/AyCode.Core.Serializers.Console/AyCode.Core.Serializers.Console.csproj
@@ -6,6 +6,7 @@
+
diff --git a/AyCode.Core.Serializers.Console/Program.cs b/AyCode.Core.Serializers.Console/Program.cs
index 77ef1df..9900348 100644
--- a/AyCode.Core.Serializers.Console/Program.cs
+++ b/AyCode.Core.Serializers.Console/Program.cs
@@ -1,7 +1,7 @@
using AyCode.Core.Compression;
using AyCode.Core.Serializers.Binaries;
-using AyCode.Core.Serializers.Jsons;
using AyCode.Core.Tests.TestModels;
+using MemoryPack;
using MessagePack;
using MessagePack.Resolvers;
using Microsoft.Extensions.Options;
@@ -15,7 +15,7 @@ namespace AyCode.Core.Serializers.Console;
///
/// Comprehensive benchmark application for all serializers.
-/// Compares: AcBinary (all options), AcJson, MessagePack, Newtonsoft.Json, System.Text.Json
+/// Compares: AcBinary (all options), MemoryPack, MessagePack, Newtonsoft.Json, System.Text.Json
///
/// Usage:
/// dotnet run # Run all benchmarks
@@ -39,7 +39,7 @@ public static class Program
private const string SerializerAcBinaryNoRef = "AcBinary (NoRef)";
private const string SerializerAcBinaryFastMode = "AcBinary (FastMode)";
private const string SerializerAcBinaryNoIntern = "AcBinary (NoIntern)";
- private const string SerializerAcJsonDefault = "AcJson (Default)";
+ private const string SerializerMemoryPack = "MemoryPack";
private const string SerializerAcBinaryBufferWriter = "AcBinary (BufferWriter)";
private const string SerializerSystemTextJson = "System.Text.Json";
@@ -212,18 +212,18 @@ public static class Program
{
// AcBinary variants
- new AcBinaryBenchmark(testData.Order, AcBinarySerializerOptions.Default, SerializerAcBinaryDefault),
- new AcBinaryBenchmark(testData.Order, AcBinarySerializerOptions.WithoutReferenceHandling, SerializerAcBinaryNoRef),
- new AcBinaryBenchmark(testData.Order, AcBinarySerializerOptions.FastMode, SerializerAcBinaryFastMode),
- new AcBinaryBenchmark(testData.Order, new AcBinarySerializerOptions { UseStringInterning = StringInterningMode.None }, SerializerAcBinaryNoIntern),
-
- //new AcBinaryBenchmark(testData.Order, AcBinarySerializerOptions.FastMode, SerializerAcBinaryDefault),
- //new AcBinaryBenchmark(testData.Order, AcBinarySerializerOptions.FastMode, SerializerAcBinaryNoRef),
+ //new AcBinaryBenchmark(testData.Order, AcBinarySerializerOptions.Default, SerializerAcBinaryDefault),
+ //new AcBinaryBenchmark(testData.Order, AcBinarySerializerOptions.WithoutReferenceHandling, SerializerAcBinaryNoRef),
//new AcBinaryBenchmark(testData.Order, AcBinarySerializerOptions.FastMode, SerializerAcBinaryFastMode),
- //new AcBinaryBenchmark(testData.Order, AcBinarySerializerOptions.FastMode, SerializerAcBinaryNoIntern),
+ //new AcBinaryBenchmark(testData.Order, new AcBinarySerializerOptions { UseStringInterning = StringInterningMode.None }, SerializerAcBinaryNoIntern),
- // AcJson
- new AcJsonBenchmark(testData.Order, AcJsonSerializerOptions.Default, SerializerAcJsonDefault),
+ new AcBinaryBenchmark(testData.Order, AcBinarySerializerOptions.FastMode, SerializerAcBinaryDefault),
+ new AcBinaryBenchmark(testData.Order, AcBinarySerializerOptions.FastMode, SerializerAcBinaryNoRef),
+ new AcBinaryBenchmark(testData.Order, AcBinarySerializerOptions.FastMode, SerializerAcBinaryFastMode),
+ new AcBinaryBenchmark(testData.Order, AcBinarySerializerOptions.FastMode, SerializerAcBinaryNoIntern),
+
+ // MemoryPack
+ new MemoryPackBenchmark(testData.Order, SerializerMemoryPack),
// MessagePack
new MessagePackBenchmark(testData.Order, SerializerMessagePack),
@@ -295,23 +295,19 @@ public static class Program
public void Deserialize() => AcBinaryDeserializer.Deserialize(_serialized, _options);
}
- private sealed class AcJsonBenchmark : ISerializerBenchmark
+ private sealed class MemoryPackBenchmark : ISerializerBenchmark
{
private readonly TestOrder _order;
- private readonly AcJsonSerializerOptions _options;
- private readonly string _serialized;
- private readonly byte[] _serializedUtf8;
+ private readonly byte[] _serialized;
public string Name { get; }
- public int SerializedSize => _serializedUtf8.Length;
+ public int SerializedSize => _serialized.Length;
- public AcJsonBenchmark(TestOrder order, AcJsonSerializerOptions options, string name)
+ public MemoryPackBenchmark(TestOrder order, string name)
{
_order = order;
- _options = options;
Name = name;
- _serialized = AcJsonSerializer.Serialize(order, options);
- _serializedUtf8 = Utf8NoBom.GetBytes(_serialized);
+ _serialized = MemoryPackSerializer.Serialize(order);
}
public void Warmup(int iterations)
@@ -324,10 +320,10 @@ public static class Program
}
[MethodImpl(MethodImplOptions.NoInlining)]
- public void Serialize() => AcJsonSerializer.Serialize(_order, _options);
+ public void Serialize() => MemoryPackSerializer.Serialize(_order);
[MethodImpl(MethodImplOptions.NoInlining)]
- public void Deserialize() => AcJsonDeserializer.Deserialize(_serialized);
+ public void Deserialize() => MemoryPackSerializer.Deserialize(_serialized);
}
private sealed class MessagePackBenchmark : ISerializerBenchmark
diff --git a/AyCode.Core.Tests/AyCode.Core.Tests.csproj b/AyCode.Core.Tests/AyCode.Core.Tests.csproj
index 1bf6239..eceee77 100644
--- a/AyCode.Core.Tests/AyCode.Core.Tests.csproj
+++ b/AyCode.Core.Tests/AyCode.Core.Tests.csproj
@@ -11,6 +11,7 @@
+
diff --git a/AyCode.Core.Tests/TestModels/SharedTestModels.cs b/AyCode.Core.Tests/TestModels/SharedTestModels.cs
index 2ab95a8..906c765 100644
--- a/AyCode.Core.Tests/TestModels/SharedTestModels.cs
+++ b/AyCode.Core.Tests/TestModels/SharedTestModels.cs
@@ -3,6 +3,7 @@ using AyCode.Core.Interfaces;
using AyCode.Core.Serializers.Attributes;
using AyCode.Core.Serializers.Binaries;
using AyCode.Core.Serializers.Jsons;
+using MemoryPack;
using MessagePack;
using MongoDB.Bson.Serialization.Attributes;
using Newtonsoft.Json;
@@ -53,9 +54,10 @@ public enum TestUserRole
/// Shared tag/label - used across multiple entities for cross-reference testing.
/// Implements IId<int> for semantic $id/$ref serialization.
///
+[MemoryPackable]
[AcBinarySerializable]
[MessagePackObject]
-public class SharedTag : IId
+public partial class SharedTag : IId
{
[Key(0)]
public int Id { get; set; }
@@ -77,9 +79,10 @@ public class SharedTag : IId
///
/// Shared category - for hierarchical cross-reference testing.
///
+[MemoryPackable]
[AcBinarySerializable]
[MessagePackObject]
-public class SharedCategory : IId
+public partial class SharedCategory : IId
{
[Key(0)]
public int Id { get; set; }
@@ -102,9 +105,10 @@ public class SharedCategory : IId
///
/// Shared user reference - appears in many places to test $ref deduplication.
///
+[MemoryPackable]
[AcBinarySerializable]
[MessagePackObject]
-public class SharedUser : IId
+public partial class SharedUser : IId
{
[Key(0)]
public int Id { get; set; }
@@ -131,9 +135,10 @@ public class SharedUser : IId
///
/// User preferences - non-IId nested object
///
+[MemoryPackable]
[AcBinarySerializable]
[MessagePackObject]
-public class UserPreferences
+public partial class UserPreferences
{
[AcStringIntern(true)]
[Key(0)]
@@ -156,9 +161,10 @@ public class UserPreferences
/// Non-IId metadata class - uses Newtonsoft PreserveReferencesHandling (numeric $id/$ref).
/// Does NOT implement IId, so uses standard Newtonsoft reference tracking.
///
+[MemoryPackable]
[AcBinarySerializable]
[MessagePackObject]
-public class MetadataInfo
+public partial class MetadataInfo
{
[AcStringIntern(true)]
[Key(0)]
@@ -183,9 +189,10 @@ public class MetadataInfo
///
/// Level 1: Main order - root of the hierarchy
///
+[MemoryPackable]
[AcBinarySerializable]
[MessagePackObject]
-public class TestOrder : IId
+public partial class TestOrder : IId
{
[Key(0)]
public int Id { get; set; }
@@ -232,6 +239,7 @@ public class TestOrder : IId
public List NoMergeItems { get; set; } = [];
// Parent reference - ignored by all serializers to prevent circular references
+ [MemoryPackIgnore]
[JsonIgnore]
[IgnoreMember]
[BsonIgnore]
@@ -241,9 +249,10 @@ public class TestOrder : IId
///
/// Level 2: Order item with pallets
///
+[MemoryPackable]
[AcBinarySerializable]
[MessagePackObject]
-public class TestOrderItem : IId
+public partial class TestOrderItem : IId
{
[Key(0)]
public int Id { get; set; }
@@ -270,6 +279,7 @@ public class TestOrderItem : IId
public MetadataInfo? ItemMetadata { get; set; }
// Parent reference - ignored by all serializers to prevent circular references
+ [MemoryPackIgnore]
[JsonIgnore]
[IgnoreMember]
[BsonIgnore]
@@ -279,9 +289,10 @@ public class TestOrderItem : IId
///
/// Level 3: Pallet containing measurements
///
+[MemoryPackable]
[AcBinarySerializable]
[MessagePackObject]
-public class TestPallet : IId
+public partial class TestPallet : IId
{
[Key(0)]
public int Id { get; set; }
@@ -311,6 +322,7 @@ public class TestPallet : IId
public MetadataInfo? PalletMetadata { get; set; }
// Parent reference - ignored by all serializers to prevent circular references
+ [MemoryPackIgnore]
[JsonIgnore]
[IgnoreMember]
[BsonIgnore]
@@ -320,9 +332,10 @@ public class TestPallet : IId
///
/// Level 4: Measurement with multiple points
///
+[MemoryPackable]
[AcBinarySerializable]
[MessagePackObject]
-public class TestMeasurement : IId
+public partial class TestMeasurement : IId
{
[Key(0)]
public int Id { get; set; }
@@ -344,6 +357,7 @@ public class TestMeasurement : IId
public SharedUser? Operator { get; set; }
// Parent reference - ignored by all serializers to prevent circular references
+ [MemoryPackIgnore]
[JsonIgnore]
[IgnoreMember]
[BsonIgnore]
@@ -353,9 +367,10 @@ public class TestMeasurement : IId
///
/// Level 5: Deepest level - measurement point
///
+[MemoryPackable]
[AcBinarySerializable]
[MessagePackObject]
-public class TestMeasurementPoint : IId
+public partial class TestMeasurementPoint : IId
{
[Key(0)]
public int Id { get; set; }
@@ -373,6 +388,7 @@ public class TestMeasurementPoint : IId
public SharedUser? Verifier { get; set; }
// Parent reference - ignored by all serializers to prevent circular references
+ [MemoryPackIgnore]
[JsonIgnore]
[IgnoreMember]
[BsonIgnore]
@@ -449,8 +465,9 @@ public class TestOrderWithNullableCollections
///
/// Class with all primitive types for WASM/serialization testing
///
+[MemoryPackable]
[AcBinarySerializable]
-public class PrimitiveTestClass
+public partial class PrimitiveTestClass
{
public int IntValue { get; set; }
public long LongValue { get; set; }
diff --git a/AyCode.Core/Serializers/Binaries/AcBinarySerializer.cs b/AyCode.Core/Serializers/Binaries/AcBinarySerializer.cs
index 5e02695..8e3fb30 100644
--- a/AyCode.Core/Serializers/Binaries/AcBinarySerializer.cs
+++ b/AyCode.Core/Serializers/Binaries/AcBinarySerializer.cs
@@ -912,10 +912,13 @@ public static partial class AcBinarySerializer
return;
}
- if (context.StringInternEligible && context.IsValidForInterningString(value.Length))
- {
- context.StringInternEligible = false;
+ // Read and immediately reset — prevents flag from leaking to subsequent WriteString calls
+ // (e.g. from TryWritePrimitive, WriteDictionary, or when IsValidForInterningString is false)
+ var internEligible = context.StringInternEligible;
+ context.StringInternEligible = false;
+ if (internEligible && context.IsValidForInterningString(value.Length))
+ {
if (context.TryConsumeWritePlanEntry(out var planEntry))
{
ValidateWritePlanString(in planEntry, value);
diff --git a/AyCode.Core/Serializers/Binaries/AcBinarySerializerOptions.cs b/AyCode.Core/Serializers/Binaries/AcBinarySerializerOptions.cs
index bbc3c38..a41a6df 100644
--- a/AyCode.Core/Serializers/Binaries/AcBinarySerializerOptions.cs
+++ b/AyCode.Core/Serializers/Binaries/AcBinarySerializerOptions.cs
@@ -84,7 +84,7 @@ public sealed class AcBinarySerializerOptions : AcSerializerOptions
///
public bool UseMetadata { get; set; } = false;
- public bool UseGeneratedCode { get; set; } = false;
+ public bool UseGeneratedCode { get; set; } = true;
///
/// When true, checks for duplicate property name hashes during serialization (UseMetadata mode).