Skip to content

Commit 956a9cd

Browse files
release v2.2.1
## 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
1 parent c9f7cb6 commit 956a9cd

File tree

8 files changed

+137
-11
lines changed

8 files changed

+137
-11
lines changed

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,13 @@ Plausibly the fastest and most flexible binary serialization library for C# proj
2626

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

29-
- Support **type check** (guarantees data integrity)
29+
- Support **polymorphism**
3030

3131
- High **performance** with low GC allocation
3232

33-
- Support **polymorphism**
33+
- Support **type check** (guarantees data integrity)
34+
35+
- Contains **version tolerance** (i.e. add/remove fields, change field type, etc)
3436

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

src/Nino.Core/Reader.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ public Reader(Span<byte> buffer)
1414
_data = buffer;
1515
}
1616

17+
public bool Eof
18+
{
19+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
20+
get => _data.IsEmpty;
21+
}
22+
1723
[MethodImpl(MethodImplOptions.AggressiveInlining)]
1824
public void Read<T>(out T value) where T : unmanaged
1925
{

src/Nino.Generator/DeserializerGenerator.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,14 @@ private static void GenerateDeserializeImplementation(ITypeSymbol typeSymbol, st
160160
[MethodImpl(MethodImplOptions.AggressiveInlining)]
161161
public static void Deserialize(out {{typeFullName}} value, ref Reader reader)
162162
{
163+
#if {{NinoTypeHelper.WeakVersionToleranceSymbol}}
164+
if (reader.Eof)
165+
{
166+
value = default;
167+
return;
168+
}
169+
#endif
170+
163171
""");
164172

165173
if (!typeSymbol.IsValueType)
@@ -389,6 +397,14 @@ private static string GeneratePrivateDeserializeImplMethodBody(string typeName,
389397
[MethodImpl(MethodImplOptions.AggressiveInlining)]
390398
public static void Deserialize{{typeParam}}(out {{typeName}} value, ref Reader reader) {{genericConstraint}}
391399
{
400+
#if {{NinoTypeHelper.WeakVersionToleranceSymbol}}
401+
if (reader.Eof)
402+
{
403+
value = default;
404+
return;
405+
}
406+
#endif
407+
392408
reader.Read(out value);
393409
}
394410
""";

src/Nino.Generator/EmbedTypeDeserializerGenerator.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,14 @@ private static string GenerateArraySerialization(string prefix, string elemType,
332332
[MethodImpl(MethodImplOptions.AggressiveInlining)]
333333
public static void Deserialize(out {{elemType}}[] value, ref Reader reader)
334334
{
335+
#if {{NinoTypeHelper.WeakVersionToleranceSymbol}}
336+
if (reader.Eof)
337+
{
338+
value = default;
339+
return;
340+
}
341+
#endif
342+
335343
reader.Read(out ushort typeId);
336344
337345
switch (typeId)
@@ -367,6 +375,14 @@ private static string GenerateDictionarySerialization(string type1, string type2
367375
[MethodImpl(MethodImplOptions.AggressiveInlining)]
368376
public static void Deserialize(out {{typeFullName}} value, ref Reader reader)
369377
{
378+
#if {{NinoTypeHelper.WeakVersionToleranceSymbol}}
379+
if (reader.Eof)
380+
{
381+
value = default;
382+
return;
383+
}
384+
#endif
385+
370386
reader.Read(out ushort typeId);
371387
372388
switch (typeId)
@@ -402,6 +418,14 @@ private static string GenerateCollectionSerialization(string prefix, string elem
402418
[MethodImpl(MethodImplOptions.AggressiveInlining)]
403419
public static void Deserialize(out {{sigTypeFullname}} value, ref Reader reader)
404420
{
421+
#if {{NinoTypeHelper.WeakVersionToleranceSymbol}}
422+
if (reader.Eof)
423+
{
424+
value = default;
425+
return;
426+
}
427+
#endif
428+
405429
{{elemType}}[] arr;
406430
{{prefix}}(out arr, ref reader);
407431
if (arr == null)
@@ -425,6 +449,14 @@ private static void GenerateNullableStructMethods(StringBuilder sb, string prefi
425449
[MethodImpl(MethodImplOptions.AggressiveInlining)]
426450
public static void Deserialize(out {{typeFullName}}? value, ref Reader reader)
427451
{
452+
#if {{NinoTypeHelper.WeakVersionToleranceSymbol}}
453+
if (reader.Eof)
454+
{
455+
value = default;
456+
return;
457+
}
458+
#endif
459+
428460
reader.Read(out ushort typeId);
429461
430462
switch (typeId)
@@ -451,6 +483,14 @@ private static void GenerateKvpStructMethods(StringBuilder sb, string prefix1, s
451483
[MethodImpl(MethodImplOptions.AggressiveInlining)]
452484
public static void Deserialize(out KeyValuePair<{{type1}}, {{type2}}> value, ref Reader reader)
453485
{
486+
#if {{NinoTypeHelper.WeakVersionToleranceSymbol}}
487+
if (reader.Eof)
488+
{
489+
value = default;
490+
return;
491+
}
492+
#endif
493+
454494
{{type1}} key;
455495
{{type2}} val;
456496
{{prefix1}}(out key, ref reader);

src/Nino.Generator/NinoTypeHelper.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ namespace Nino.Generator;
1111

1212
public static class NinoTypeHelper
1313
{
14+
public const string WeakVersionToleranceSymbol = "WEAK_VERSION_TOLERANCE";
15+
1416
public static IncrementalValuesProvider<CSharpSyntaxNode> GetTypeSyntaxes(
1517
this IncrementalGeneratorInitializationContext context)
1618
{

src/Nino.UnitTests/Nino.UnitTests.csproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@
99
<TargetFramework>net6.0</TargetFramework>
1010
</PropertyGroup>
1111

12+
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
13+
<DefineConstants>TRACE;WEAK_VERSION_TOLERANCE</DefineConstants>
14+
</PropertyGroup>
15+
16+
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
17+
<DefineConstants>TRACE;WEAK_VERSION_TOLERANCE</DefineConstants>
18+
</PropertyGroup>
19+
1220
<ItemGroup>
1321
<PackageReference Include="System.Buffers" Version="4.5.1"/>
1422
<PackageReference Include="System.Memory" Version="4.5.5"/>

src/Nino.UnitTests/SimpleTests.cs

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,49 @@ namespace Nino.UnitTests
99
[TestClass]
1010
public class SimpleTests
1111
{
12+
[TestMethod]
13+
public void TestDeserializeOldData()
14+
{
15+
SaveData data = new SaveData
16+
{
17+
Id = 1,
18+
Name = "Test",
19+
};
20+
21+
//from serialization old version of data
22+
/*
23+
* [NinoType(false)]
24+
public class SaveData
25+
{
26+
[NinoMember(1)] public int Id;
27+
[NinoMember(2)] public string Name;
28+
}
29+
*/
30+
31+
//require symbol WEAK_VERSION_TOLERANCE to be defined
32+
#if WEAK_VERSION_TOLERANCE
33+
Span<byte> oldData = stackalloc byte[]
34+
{
35+
26, 0, 1, 0, 0, 0, 1, 0, 4, 0, 0, 0, 84, 0, 101, 0, 115, 0, 116, 0
36+
};
37+
Deserializer.Deserialize(oldData, out SaveData result);
38+
Assert.AreEqual(data.Id, result.Id);
39+
Assert.AreEqual(data.Name, result.Name);
40+
Assert.AreEqual(default, result.NewField1);
41+
Assert.AreEqual(default, result.NewField2);
42+
#else
43+
//should throw out of range exception
44+
Assert.ThrowsException<IndexOutOfRangeException>(() =>
45+
{
46+
Span<byte> oldData = stackalloc byte[]
47+
{
48+
26, 0, 1, 0, 0, 0, 1, 0, 4, 0, 0, 0, 84, 0, 101, 0, 115, 0, 116, 0
49+
};
50+
Deserializer.Deserialize(oldData, out SaveData _);
51+
});
52+
#endif
53+
}
54+
1255
[TestMethod]
1356
public void TestRecordStruct()
1457
{
@@ -30,17 +73,17 @@ public void TestRecordStruct()
3073

3174
Deserializer.Deserialize(bytes, out SimpleRecordStruct2 result2);
3275
Assert.AreEqual(record2, result2);
33-
76+
3477
SimpleRecordStruct2<int> record3 = new SimpleRecordStruct2<int>(1, 1234);
3578
bytes = record3.Serialize();
3679
Assert.IsNotNull(bytes);
37-
80+
3881
Deserializer.Deserialize(bytes, out SimpleRecordStruct2<int> result3);
3982
Assert.AreEqual(record3, result3);
40-
83+
4184
SimpleRecordStruct2<string> record4 = new SimpleRecordStruct2<string>(1, "Test");
4285
bytes = record4.Serialize();
43-
86+
4487
Deserializer.Deserialize(bytes, out SimpleRecordStruct2<string> result4);
4588
Assert.AreEqual(record4, result4);
4689
}
@@ -94,23 +137,23 @@ public void TestRecords()
94137
Assert.AreEqual(result4.Flag, false);
95138
result4.Flag = true;
96139
Assert.AreEqual(record4, result4);
97-
140+
98141
SimpleRecord5 record5 = new SimpleRecord5(1, "Test", DateTime.Today)
99142
{
100143
Flag = true,
101144
ShouldNotIgnore = 1234
102145
};
103-
146+
104147
bytes = record5.Serialize();
105148
Assert.IsNotNull(bytes);
106-
149+
107150
Deserializer.Deserialize(bytes, out SimpleRecord5 result5);
108151
Assert.AreEqual(record5.ShouldNotIgnore, result5.ShouldNotIgnore);
109-
152+
110153
SimpleRecord6<int> record6 = new SimpleRecord6<int>(1, 1234);
111154
bytes = record6.Serialize();
112155
Assert.IsNotNull(bytes);
113-
156+
114157
Deserializer.Deserialize(bytes, out SimpleRecord6<int> result6);
115158
Assert.AreEqual(record6, result6);
116159
}

src/Nino.UnitTests/TestClass.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@
55

66
namespace Nino.UnitTests
77
{
8+
[NinoType(false)]
9+
public class SaveData
10+
{
11+
[NinoMember(1)] public int Id;
12+
[NinoMember(2)] public string Name;
13+
[NinoMember(3)] public DateTime NewField1;
14+
[NinoMember(4)] public Generic<int> NewField2;
15+
}
16+
817
[NinoType]
918
public struct GenericStruct<T>
1019
{

0 commit comments

Comments
 (0)