Skip to content

Commit

Permalink
release v2.2.1
Browse files Browse the repository at this point in the history
## Nino.Serialization v2.2.1
- [Feat] Support a more flexible version tolerance, useful for adding serialize members for a checkpoint data type remaining the capability to deserialize the old data type
  • Loading branch information
JasonXuDeveloper committed Nov 11, 2024
1 parent c9f7cb6 commit 956a9cd
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 11 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@ Plausibly the fastest and most flexible binary serialization library for C# proj

- Support all **Embed** serializable types (i.e. `Dictionary<Int, List<SupportedType[]>>`)

- Support **type check** (guarantees data integrity)
- Support **polymorphism**

- High **performance** with low GC allocation

- Support **polymorphism**
- Support **type check** (guarantees data integrity)

- Contains **version tolerance** (i.e. add/remove fields, change field type, etc)

- Support **cross-project** (C# Project) type serialization (i.e. serialize a class with member of types in A.dll from B.dll)

Expand Down
6 changes: 6 additions & 0 deletions src/Nino.Core/Reader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ public Reader(Span<byte> buffer)
_data = buffer;
}

public bool Eof
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _data.IsEmpty;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Read<T>(out T value) where T : unmanaged
{
Expand Down
16 changes: 16 additions & 0 deletions src/Nino.Generator/DeserializerGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,14 @@ private static void GenerateDeserializeImplementation(ITypeSymbol typeSymbol, st
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Deserialize(out {{typeFullName}} value, ref Reader reader)
{
#if {{NinoTypeHelper.WeakVersionToleranceSymbol}}
if (reader.Eof)
{
value = default;
return;
}
#endif
""");

if (!typeSymbol.IsValueType)
Expand Down Expand Up @@ -389,6 +397,14 @@ private static string GeneratePrivateDeserializeImplMethodBody(string typeName,
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Deserialize{{typeParam}}(out {{typeName}} value, ref Reader reader) {{genericConstraint}}
{
#if {{NinoTypeHelper.WeakVersionToleranceSymbol}}
if (reader.Eof)
{
value = default;
return;
}
#endif
reader.Read(out value);
}
""";
Expand Down
40 changes: 40 additions & 0 deletions src/Nino.Generator/EmbedTypeDeserializerGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,14 @@ private static string GenerateArraySerialization(string prefix, string elemType,
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Deserialize(out {{elemType}}[] value, ref Reader reader)
{
#if {{NinoTypeHelper.WeakVersionToleranceSymbol}}
if (reader.Eof)
{
value = default;
return;
}
#endif
reader.Read(out ushort typeId);
switch (typeId)
Expand Down Expand Up @@ -367,6 +375,14 @@ private static string GenerateDictionarySerialization(string type1, string type2
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Deserialize(out {{typeFullName}} value, ref Reader reader)
{
#if {{NinoTypeHelper.WeakVersionToleranceSymbol}}
if (reader.Eof)
{
value = default;
return;
}
#endif
reader.Read(out ushort typeId);
switch (typeId)
Expand Down Expand Up @@ -402,6 +418,14 @@ private static string GenerateCollectionSerialization(string prefix, string elem
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Deserialize(out {{sigTypeFullname}} value, ref Reader reader)
{
#if {{NinoTypeHelper.WeakVersionToleranceSymbol}}
if (reader.Eof)
{
value = default;
return;
}
#endif
{{elemType}}[] arr;
{{prefix}}(out arr, ref reader);
if (arr == null)
Expand All @@ -425,6 +449,14 @@ private static void GenerateNullableStructMethods(StringBuilder sb, string prefi
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Deserialize(out {{typeFullName}}? value, ref Reader reader)
{
#if {{NinoTypeHelper.WeakVersionToleranceSymbol}}
if (reader.Eof)
{
value = default;
return;
}
#endif
reader.Read(out ushort typeId);
switch (typeId)
Expand All @@ -451,6 +483,14 @@ private static void GenerateKvpStructMethods(StringBuilder sb, string prefix1, s
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Deserialize(out KeyValuePair<{{type1}}, {{type2}}> value, ref Reader reader)
{
#if {{NinoTypeHelper.WeakVersionToleranceSymbol}}
if (reader.Eof)
{
value = default;
return;
}
#endif
{{type1}} key;
{{type2}} val;
{{prefix1}}(out key, ref reader);
Expand Down
2 changes: 2 additions & 0 deletions src/Nino.Generator/NinoTypeHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ namespace Nino.Generator;

public static class NinoTypeHelper
{
public const string WeakVersionToleranceSymbol = "WEAK_VERSION_TOLERANCE";

public static IncrementalValuesProvider<CSharpSyntaxNode> GetTypeSyntaxes(
this IncrementalGeneratorInitializationContext context)
{
Expand Down
8 changes: 8 additions & 0 deletions src/Nino.UnitTests/Nino.UnitTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DefineConstants>TRACE;WEAK_VERSION_TOLERANCE</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DefineConstants>TRACE;WEAK_VERSION_TOLERANCE</DefineConstants>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="System.Buffers" Version="4.5.1"/>
<PackageReference Include="System.Memory" Version="4.5.5"/>
Expand Down
61 changes: 52 additions & 9 deletions src/Nino.UnitTests/SimpleTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,49 @@ namespace Nino.UnitTests
[TestClass]
public class SimpleTests
{
[TestMethod]
public void TestDeserializeOldData()
{
SaveData data = new SaveData
{
Id = 1,
Name = "Test",
};

//from serialization old version of data
/*
* [NinoType(false)]
public class SaveData
{
[NinoMember(1)] public int Id;
[NinoMember(2)] public string Name;
}
*/

//require symbol WEAK_VERSION_TOLERANCE to be defined
#if WEAK_VERSION_TOLERANCE
Span<byte> oldData = stackalloc byte[]
{
26, 0, 1, 0, 0, 0, 1, 0, 4, 0, 0, 0, 84, 0, 101, 0, 115, 0, 116, 0
};
Deserializer.Deserialize(oldData, out SaveData result);
Assert.AreEqual(data.Id, result.Id);
Assert.AreEqual(data.Name, result.Name);
Assert.AreEqual(default, result.NewField1);
Assert.AreEqual(default, result.NewField2);
#else
//should throw out of range exception
Assert.ThrowsException<IndexOutOfRangeException>(() =>
{
Span<byte> oldData = stackalloc byte[]
{
26, 0, 1, 0, 0, 0, 1, 0, 4, 0, 0, 0, 84, 0, 101, 0, 115, 0, 116, 0
};
Deserializer.Deserialize(oldData, out SaveData _);
});
#endif
}

[TestMethod]
public void TestRecordStruct()
{
Expand All @@ -30,17 +73,17 @@ public void TestRecordStruct()

Deserializer.Deserialize(bytes, out SimpleRecordStruct2 result2);
Assert.AreEqual(record2, result2);

SimpleRecordStruct2<int> record3 = new SimpleRecordStruct2<int>(1, 1234);
bytes = record3.Serialize();
Assert.IsNotNull(bytes);

Deserializer.Deserialize(bytes, out SimpleRecordStruct2<int> result3);
Assert.AreEqual(record3, result3);

SimpleRecordStruct2<string> record4 = new SimpleRecordStruct2<string>(1, "Test");
bytes = record4.Serialize();

Deserializer.Deserialize(bytes, out SimpleRecordStruct2<string> result4);
Assert.AreEqual(record4, result4);
}
Expand Down Expand Up @@ -94,23 +137,23 @@ public void TestRecords()
Assert.AreEqual(result4.Flag, false);
result4.Flag = true;
Assert.AreEqual(record4, result4);

SimpleRecord5 record5 = new SimpleRecord5(1, "Test", DateTime.Today)
{
Flag = true,
ShouldNotIgnore = 1234
};

bytes = record5.Serialize();
Assert.IsNotNull(bytes);

Deserializer.Deserialize(bytes, out SimpleRecord5 result5);
Assert.AreEqual(record5.ShouldNotIgnore, result5.ShouldNotIgnore);

SimpleRecord6<int> record6 = new SimpleRecord6<int>(1, 1234);
bytes = record6.Serialize();
Assert.IsNotNull(bytes);

Deserializer.Deserialize(bytes, out SimpleRecord6<int> result6);
Assert.AreEqual(record6, result6);
}
Expand Down
9 changes: 9 additions & 0 deletions src/Nino.UnitTests/TestClass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@

namespace Nino.UnitTests
{
[NinoType(false)]
public class SaveData
{
[NinoMember(1)] public int Id;
[NinoMember(2)] public string Name;
[NinoMember(3)] public DateTime NewField1;
[NinoMember(4)] public Generic<int> NewField2;
}

[NinoType]
public struct GenericStruct<T>
{
Expand Down

0 comments on commit 956a9cd

Please sign in to comment.