From 18fd38b32e744ceff6aee0464686cf5139c9ca39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?JasonXuDeveloper=20-=20=E5=82=91?= Date: Tue, 11 Jul 2023 19:35:15 +1000 Subject: [PATCH] [update] nino.serialization v1.2.0 fixed #57 #58 #74 --- Docs/Serialization.md | 263 ++-- ...ino_Test_BuildTestDataCodeGen_Serialize.cs | 98 +- .../Nino_Test_CollectionTest_Serialize.cs | 29 +- .../Nino_Test_ComplexData_Serialize.cs | 34 +- .../Nino_Test_CustomTypeTest_Serialize.cs | 35 +- .../Generated/Nino_Test_Data_Serialize.cs | 73 +- ...o_Test_IncludeAllClassCodeGen_Serialize.cs | 44 +- .../Nino_Test_NestedData2_Serialize.cs | 27 +- .../Nino_Test_NestedData_Serialize.cs | 26 +- .../Nino_Test_NotIncludeAllClass_Serialize.cs | 44 +- .../Nino/Serialization/CodeGenerator.cs | 184 +-- .../Serialization/Deserializer.Generic.cs | 127 +- .../Assets/Nino/Serialization/Deserializer.cs | 117 +- .../Serialization/Interfaces/INinoWrapper.cs | 6 +- .../Nino/Serialization/Reader.Generic.cs | 111 +- .../Assets/Nino/Serialization/Reader.cs | 189 +-- .../Nino/Serialization/Serializer.Generic.cs | 297 ++++- .../Nino/Serialization/Serializer.Helper.cs | 346 +++++ .../Assets/Nino/Serialization/Serializer.cs | 410 ++---- .../Assets/Nino/Serialization/TypeModel.cs | 106 +- .../Wrappers/Common/NinoWrapperBase.cs | 20 +- .../Wrappers/Primitives/Basics.cs | 210 +-- .../Wrappers/Primitives/Decimals.cs | 143 +- .../Wrappers/Primitives/Integers.cs | 395 +++--- .../Nino/Serialization/Writer.Generic.cs | 216 ++-- .../Assets/Nino/Serialization/Writer.cs | 365 +----- .../Nino/Shared/IO/Stream/DeflateStream.cs | 5 + Nino_Unity/Assets/Nino/Test/BuildTest2.cs | 1 - Nino_Unity/Assets/Nino/Test/Data.cs | 7 +- .../Nino/Test/Editor/Serialization/Test1.cs | 33 +- .../Nino/Test/Editor/Serialization/Test10.cs | 10 - .../Nino/Test/Editor/Serialization/Test2.cs | 33 +- .../Nino/Test/Editor/Serialization/Test3.cs | 14 +- .../Nino/Test/Editor/Serialization/Test4.cs | 7 - .../Nino/Test/Editor/Serialization/Test5.cs | 216 +++- .../Nino/Test/Editor/Serialization/Test6.cs | 186 ++- .../Nino/Test/Editor/Serialization/Test7.cs | 156 ++- .../Assets/Nino/Test/MessagePackGenerated.cs | 14 +- .../MongoDB.Shared/GlobalAssemblyInfo.cs | 23 - .../AutoStreamingSettings.asset | 21 + Nino_Unity/ProjectSettings/ProjectVersion.txt | 4 +- .../UnityConnectSettings.asset | 2 + .../VersionControlSettings.asset | 8 + Performance/Serialization.md | 1145 ++++++++--------- README.md | 13 +- ..._Benchmark_Models_AccessToken_Serialize.cs | 62 + ...Benchmark_Models_AccountMerge_Serialize.cs | 59 + .../Nino_Benchmark_Models_Answer_Serialize.cs | 116 ++ .../Nino_Benchmark_Models_Badge_Serialize.cs | 65 + ...Nino_Benchmark_Models_Comment_Serialize.cs | 77 ++ .../Nino_Benchmark_Models_Data_Serialize.cs | 67 + ...o_Benchmark_Models_NestedData_Serialize.cs | 26 +- ..._Benchmark_Models_AccessToken_Serialize.cs | 38 - ...Benchmark_Models_AccountMerge_Serialize.cs | 36 - .../Nino_Benchmark_Models_Answer_Serialize.cs | 74 -- .../Nino_Benchmark_Models_Badge_Serialize.cs | 40 - ...Nino_Benchmark_Models_Comment_Serialize.cs | 48 - .../Nino_Benchmark_Models_Data_Serialize.cs | 48 - .../Serialization/Models/Data.cs | 10 +- .../Serialization/SerializationBenchmark.cs | 4 +- .../Serializers/NinoSerializer.cs | 21 +- src/Nino.Serialization/CodeGenerator.cs | 194 +-- .../Deserializer.Generic.cs | 127 +- src/Nino.Serialization/Deserializer.cs | 117 +- .../Interfaces/INinoWrapper.cs | 6 +- .../Nino.Serialization.csproj | 8 +- src/Nino.Serialization/README.md | 4 +- src/Nino.Serialization/Reader.Generic.cs | 111 +- src/Nino.Serialization/Reader.cs | 189 +-- src/Nino.Serialization/Serializer.Generic.cs | 297 ++++- src/Nino.Serialization/Serializer.Helper.cs | 346 +++++ src/Nino.Serialization/Serializer.cs | 410 ++---- src/Nino.Serialization/TypeModel.cs | 85 +- .../Wrappers/Common/NinoWrapperBase.cs | 20 +- .../Wrappers/Primitives/Basics.cs | 210 +-- .../Wrappers/Primitives/Decimals.cs | 143 +- .../Wrappers/Primitives/Integers.cs | 395 +++--- src/Nino.Serialization/Writer.Generic.cs | 216 ++-- src/Nino.Serialization/Writer.cs | 365 +----- .../CodeGenSerializationTest.cs | 4 +- .../ComplexSerializationTest.cs | 69 +- .../Generated/Nino_UnitTests_A_Serialize.cs | 46 + .../Generated/Nino_UnitTests_C_Serialize.cs | 26 +- src/Nino.UnitTests/IssueTest.cs | 18 +- src/Nino.UnitTests/Nino.UnitTests.csproj | 4 +- .../Generated/Nino_UnitTests_A_Serialize.cs | 32 - .../PrimitivesSerializationTest.cs | 5 +- 87 files changed, 5111 insertions(+), 4940 deletions(-) create mode 100644 Nino_Unity/Assets/Nino/Serialization/Serializer.Helper.cs delete mode 100644 Nino_Unity/Assets/ThirdParty/Mongo/MongoDB.Shared/GlobalAssemblyInfo.cs create mode 100644 Nino_Unity/ProjectSettings/AutoStreamingSettings.asset create mode 100644 Nino_Unity/ProjectSettings/VersionControlSettings.asset create mode 100644 src/Nino.Benchmark/Generated/Nino_Benchmark_Models_AccessToken_Serialize.cs create mode 100644 src/Nino.Benchmark/Generated/Nino_Benchmark_Models_AccountMerge_Serialize.cs create mode 100644 src/Nino.Benchmark/Generated/Nino_Benchmark_Models_Answer_Serialize.cs create mode 100644 src/Nino.Benchmark/Generated/Nino_Benchmark_Models_Badge_Serialize.cs create mode 100644 src/Nino.Benchmark/Generated/Nino_Benchmark_Models_Comment_Serialize.cs create mode 100644 src/Nino.Benchmark/Generated/Nino_Benchmark_Models_Data_Serialize.cs rename src/Nino.Benchmark/{Nino => }/Generated/Nino_Benchmark_Models_NestedData_Serialize.cs (52%) delete mode 100644 src/Nino.Benchmark/Nino/Generated/Nino_Benchmark_Models_AccessToken_Serialize.cs delete mode 100644 src/Nino.Benchmark/Nino/Generated/Nino_Benchmark_Models_AccountMerge_Serialize.cs delete mode 100644 src/Nino.Benchmark/Nino/Generated/Nino_Benchmark_Models_Answer_Serialize.cs delete mode 100644 src/Nino.Benchmark/Nino/Generated/Nino_Benchmark_Models_Badge_Serialize.cs delete mode 100644 src/Nino.Benchmark/Nino/Generated/Nino_Benchmark_Models_Comment_Serialize.cs delete mode 100644 src/Nino.Benchmark/Nino/Generated/Nino_Benchmark_Models_Data_Serialize.cs create mode 100644 src/Nino.Serialization/Serializer.Helper.cs create mode 100644 src/Nino.UnitTests/Generated/Nino_UnitTests_A_Serialize.cs rename src/Nino.UnitTests/{Nino => }/Generated/Nino_UnitTests_C_Serialize.cs (51%) delete mode 100644 src/Nino.UnitTests/Nino/Generated/Nino_UnitTests_A_Serialize.cs diff --git a/Docs/Serialization.md b/Docs/Serialization.md index 7146791..deee89d 100644 --- a/Docs/Serialization.md +++ b/Docs/Serialization.md @@ -1,6 +1,6 @@ # 序列化模块使用方法 -## 非Unity平台 +## 非Unity平台(`v1.2.0`之前) 非Unity平台使用Nino,可以**根据需求开启**原生压缩解压代码,**开启后序列化和反序列化时的GC会变得非常的低(KB级别甚至Bytes级别)** @@ -20,6 +20,14 @@ ## 注意事项 +```Nino.Serialization v1.2.0```与其**之前**的**所有版本**都**不兼容**,升级Nino后需要用新版```Writer/Serializer``` **重新导出** 一份数据,才能被最新版的```Reader/Deserializer```正常解析,同时需要生成新的代码!!! + +> 这个版本去掉了多态,同时去掉了数字类型压缩,改造了代码生成 + + + + + ```Nino.Serialization v1.1.2```与其**之前**的**所有版本**都**不兼容**,升级Nino后需要用新版```Writer/Serializer``` **重新导出** 一份数据,才能被最新版的```Reader/Deserializer```正常解析!!! > 这个版本开始支持了多态了,所以Array/List/HashSet/Queue/Stack等集合类型的二进制格式有变化 @@ -86,11 +94,7 @@ public partial class NotIncludeAllClass > 建议每个需要Nino序列化/反序列化的类和结构体用partial定义,这样可以生成代码 > -> 推荐```NotIncludeAllClass```的写法,给每个字段或属性单独打```NinoMember```标签,这样性能最好,体积最小 -> -> **```IncludeAllClass```的写法(自动收集),会导致生成出来的体积较大,序列化反序列化速度慢,但是可以通过生成代码优化**(非ILRuntime下) -> -> **自动收集的类型或结构体,强烈建议通过生成代码来提高性能,以及优化体积,但是需要注意,每次更新字段或属性后需要重新生成代码来更新** +> **强烈建议通过生成代码来提高性能,但是需要注意,每次更新字段或属性后需要重新生成代码来更新** @@ -100,21 +104,16 @@ public partial class NotIncludeAllClass - byte, sbyte, short, ushort, int, uint, long, ulong, double, float, decimal, char, string, bool, enum, DateTime - Nullable<任意支持Nino序列化的struct> -- List<上述类型>,HashSet<上述类型>,Queue<上述类型>,Stack<上述类型>,上述类型[] -- List<可Nino序列化类型>,HashSet<可Nino序列化类型>,Queue<可Nino序列化类型>,Stack<可Nino序列化类型>,可Nino序列化类型[] -- List<注册委托类型>,HashSet<注册委托类型>,Queue<注册委托类型>,Stack<注册委托类型>,注册委托类型[] -- Dictionary -- Dictionary<注册委托类型,注册委托类型> +- List<可Nino序列化类型>,HashSet<可Nino序列化类型>,Queue<可Nino序列化类型>,Stack<可Nino序列化类型>,可Nino序列化类型[], ICollection<可Nino序列化> +- Dictionary,IDictionary<可Nino序列化> - 可Nino序列化类型 - null -不支持序列化的成员类型(可以通过注册自定义委托实现): +不支持序列化的成员类型(可以通过注册自定义包装器实现): -- 任何非上述类型(ConcurrentQueue等) +- 任何非上述类型 -**针对某个类型注册自定义序列化委托后,记得注册该类型的自定义反序列化委托,不然会导致反序列化出错** - -**支持多态!!!** +**不支持多态!!!** ## 限制 @@ -123,42 +122,6 @@ public partial class NotIncludeAllClass -## 多态规则 - -**支持:** - -- 同类型序列化/反序列化 - - ```csharp - class A{} - class B: A{} - - ... - var buf = Serializer.Serialize((A)new B()); - var insOfA = Deserializer.Deserialize(buf); - ``` - - > 注意,这样操作会丢失全部B类型内的成员 - -- 数组/List/HashSet/Queue/Stack/字典 - - ```csharp - class A{} - class B: A{} - - ... - var buf = Serializer.Serialize>(new List(){new B()}); - var insOfLstA = Deserializer.DeserializeList(buf); - ``` - - > 注意,这样操作不会丢失```List```内的B对象的B类型成员数据 - > - > 数组/HashSet/Queue/Stack/字典在这里同理 - > - > HashSet/Queue/Stack记得用泛型方法去序列化和反序列化,不然不支持 - - - ## ILRuntime Nino支持ILRuntime的使用,但需要初始化ILRuntime: @@ -189,7 +152,7 @@ Nino支持ILRuntime的使用,但需要初始化ILRuntime: > > 需要注意的是,ILRuntime下生成与不生成代码的差距不是特别大 > -> ILRuntime下也支持多态! +> ILRuntime下也不支持多态! @@ -202,106 +165,39 @@ Nino支持ILRuntime的使用,但需要初始化ILRuntime: 使用方法: - 创建一个类型,并继承```NinoWrapperBase```,T是你需要序列化/反序列化的类型,也可以用泛型代替,可以自由发挥 -- 实现```public override void Serialize(T val, Writer writer)```,自行根据```Nino.Serialization.Writer```的公共接口来序列化T类型的数据即可 +- 实现```public override void Serialize(T val, ref Writer writer)```,自行根据```Nino.Serialization.Writer```的公共接口来序列化T类型的数据即可 - 实现```public override T Deserialize(Reader reader)```,自行根据```Nino.Serialization.Reader```的公共接口来实现反序列化T类型的数据即可 +- 实现`public overrid int GetSize(T val)`,自行返回该类型的长度即可 - 调用```WrapperManifest.AddWrapper(typeof(T), new NinoWrapperBase());```以注册接口包装器 示例: ```csharp -internal class DateTimeListWrapper : NinoWrapperBase> +public class Vector3Wrapper : NinoWrapperBase { - public override void Serialize(List val, Writer writer) + public override void Serialize(Vector3 val, ref Writer writer) { - writer.CompressAndWrite(val.Count); - foreach (var v in val) - { - writer.Write(v); - } + writer.Write(val.x); + writer.Write(val.y); + writer.Write(val.z); } - public override List Deserialize(Reader reader) + public override Vector3 Deserialize(Reader reader) { - int len = reader.ReadLength(); - var arr = new List(len); - int i = 0; - while (i++ < len) - { - arr.Add(reader.ReadDateTime()); - } - return arr; + return new Vector3(reader.Read(4), reader.Read(4), reader.Read(4)); + } + + public override int GetSize(Vector3 val) + { + return 12; } } //别忘了在某个地方调用下面的代码: -WrapperManifest.AddWrapper(typeof(DateTimeListWrapper), new DateTimeListWrapper()); -``` - - - -## 注册自定义序列化委托 - -给指定类型注册该委托后,全局序列化的时候遇到该类型会直接使用委托方法写入二进制数据 - -需要注意的是,不支持注册底层自带支持的类型的委托,**并且注册委托的方式处理值类型会产生GC和装箱开销,可以通过注册自定义包装器避免这个问题** - -使用方法: - -```csharp -Serializer.AddCustomImporter((val, writer) => - { - //TODO use writer to write - }); -``` - -T是需要注册的类型的泛型参数,val是T的实例,writer是用来写二进制的工具 - -示例: - -```csharp -Serializer.AddCustomImporter((val, writer) => - { - //write 3 float - writer.Write(val.x); - writer.Write(val.y); - writer.Write(val.z); - }); -``` - -这里我们写了个Vector3,将其x,y,z以float的方式写入 - -> 写入(U)Int/(U)Long可以用Write(U)Int32/Write(U)Int64,但是建议用CompressAndWrite接口,可以有效压缩体积 -> -> 写入Enum也要使用对应压缩接口,需要声明enum对应的数值类型,并且给enum的值转为ulong,例如writer.CompressAndWriteEnum(typeof(System.Byte), (ulong) value.En); - -## 注册自定义反序列化委托 - -给指定类型注册该委托后,全局翻序列化的时候遇到该类型会直接使用委托方法读取二进制数据并转为对象 - -需要注意的是,不支持注册底层自带支持的类型的委托,**并且注册委托的方式处理值类型会产生GC和拆箱开销,可以通过注册自定义包装器避免这个问题** - -使用方法: - -```csharp -Deserializer.AddCustomExporter(reader => - //TODO return T instance - ); +WrapperManifest.AddWrapper(typeof(Vector3), new Vector3Wrapper()); ``` -T是需要注册的类型的泛型参数,reader是用来读二进制的工具 -示例: - -```csharp -Deserializer.AddCustomExporter(reader => - new UnityEngine.Vector3(reader.ReadFloat(), reader.ReadFloat(), reader.ReadFloat())); -``` - -这里我们读了3个float作为xyz(因为写入的时候写3个float,xyz),创建了Vector3并返回 - ->如果写入(U)Int/(U)Long时用了压缩接口,那么读的时候要用DecompressAndReadNumber接口读取,并且需要转换类型,如(int)reader.DecompressAndReadNumber() -> ->读取Enum要用DecompressAndReadEnum(enum声明类型),enum默认是int类型的 ## 代码生成 @@ -309,7 +205,7 @@ Deserializer.AddCustomExporter(reader => - Unity下直接在菜单栏点击```Nino/Generator/Serialization Code```即可,代码会生成到```Assets/Nino/Generated```,也可以打开```Assets/Nino/Editor/SerializationHelper.cs```并修改内部的```ExportPath```参数 - 非Unity下调用```CodeGenerator.GenerateSerializationCodeForAllTypePossible```接口即可 -- **如果开启了自动收集字段和属性,生成代码和没生成代码,序列化的结果是不一样的,因此在导表读表的使用场景里,如果使用了自动收集,那么在生成代码后需要重新再导出一次文件(强烈建议不要开启自动收集,建议手动标记顺序)** +- **开启了自动收集字段和属性,生成代码和没生成代码,序列化的结果是一样的** > 不想生成代码的类或结构体可以打```[CodeGenIgnore]```标签到该类或结构体上,可以在性能对比的时候用这个(例如[这个真机测试](../Nino_Unity/Assets/Nino/Test/BuildTest.cs)) @@ -320,71 +216,114 @@ Deserializer.AddCustomExporter(reader => Nino支持以下三种压缩方式: - Zlib(高压缩率低性能) -- Lz4(平均压缩率高性能)【正在开发】 +- Lz4(平均压缩率高性能) - 无压缩(高性能但体积很大) > 序列化和反序列化的时候可以选择压缩方式,但是需要注意反序列化数据的时候,需要用和序列化时相同的压缩方式去反序列化 +> +> 注意,v1.2.0暂时仅支持无压缩 ## 序列化 ```csharp -Nino.Serialization.Serializer.Serialize(T val, CompressOption option = CompressOption.Zlib); +byte[] Nino.Serialization.Serializer.Serialize(T val); +byte[] Nino.Serialization.Serializer.Serialize(object val); ``` ```csharp -Nino.Serialization.Serializer.Serialize(object val, CompressOption option = CompressOption.Zlib); +int Nino.Serialization.Serializer.Serialize(Span buffer, in T val); +int Nino.Serialization.Serializer.Serialize(Span buffer, object val) ``` - - -> 如果没有指定的压缩模式,会使用Zlib -> -> 需要注意的是,涉及到字符串时,请确保序列化和反序列化的时候用的是同样的编码和同样的压缩方式 -> -> 老版本(1.1.0以下),需要指定Encoding参数,默认是UTF8 - 示范: ```csharp +//懒人写法 byte[] byteArr = Nino.Serialization.Serializer.Serialize(obj); + +//进阶写法:速度快且将近0GC的写法: + +//也可以搭配stackalloc使用 +Span stackMemory = stackalloc byte[1024];//请确保这个对象不可能超过1024字节 +int writtenSize = Nino.Serialization.Serializer.Serialize(stackMemory, obj); +//将stackMemory.Slice(writtenSize) 写入网络流之类的 +... +//也可以搭配ArrayPool使用 +int size = Nino.Serialization.Serializer.GetSize(obj); +byte[] arr = ArrayPool.Shared.Rent(size); +Nino.Serialization.Serializer.Serialize(new Span(arr, 0, size), obj); +//将arr的第0个到第size个字节写入流 +ArrayPool.Shared.Return(arr); ``` 传入需要序列化的类型作为泛型参数,以及该类型的实例,会返回二进制数组 -## 反序列化 +还有其他类型的序列化: ```csharp -Nino.Serialization.Deserializer.Deserialize(byte[] data, CompressOption option = CompressOption.Zlib); -Nino.Serialization.Deserializer.DeserializeArray(byte[] data, CompressOption option = CompressOption.Zlib); -Nino.Serialization.Deserializer.DeserializeNullable(byte[] data, CompressOption option = CompressOption.Zlib); -Nino.Serialization.Deserializer.DeserializeList(byte[] data, CompressOption option = CompressOption.Zlib); -Nino.Serialization.Deserializer.DeserializeHashSet(byte[] data, CompressOption option = CompressOption.Zlib); -Nino.Serialization.Deserializer.DeserializeQueue(byte[] data, CompressOption option = CompressOption.Zlib); -Nino.Serialization.Deserializer.DeserializeStack(byte[] data, CompressOption option = CompressOption.Zlib); +Serialize(T[] val); +Serialize(T? val); +Serialize(List val); +Serialize(HashSet val); +Serialize(Queue val); +Serialize(Stack val); +Serialize(Dictionary val); ``` + + +## 反序列化 + ```csharp -Nino.Serialization.Deserializer.Deserialize(Type type, byte[] data, CompressOption option = CompressOption.Zlib); +Nino.Serialization.Deserializer.Deserialize(byte[] data); +Nino.Serialization.Deserializer.Deserialize(Type type, byte[] data); +Nino.Serialization.Deserializer.DeserializeArray(byte[] data); +Nino.Serialization.Deserializer.DeserializeNullable(byte[] data); +Nino.Serialization.Deserializer.DeserializeList(byte[] data); +Nino.Serialization.Deserializer.DeserializeHashSet(byte[] data); +Nino.Serialization.Deserializer.DeserializeQueue(byte[] data); +Nino.Serialization.Deserializer.DeserializeStack(byte[] data); ``` -> data可以传```byte[]```或```ArraySegment```或```Span``` -> -> 如果没有指定的压缩模式,会使用Zlib +> data不仅可以传```byte[]```,还可以```ArraySegment```或```Span``` > -> 需要注意压缩模式问题,并且反序列化的对象需要能够创建(包含无参数的构造函数) -> -> 老版本(1.1.0以下),需要指定Encoding参数,默认是UTF8 示范: ```csharp +//假设这里byteArr是byte[] var obj = Nino.Serialization.Deserializer.Deserialize(byteArr); +... +//高级用法,假设网络层传来了数据(比如Pipeline),我们收到了ReadOnlySequence +//这样写性能最最最最好 +ReadOnlySequence data = xxxxx; +ObjClass obj; +if(data.IsSingleSegment) +{ + Span dataSpan = data.FirstSpan; + obj = Nino.Serialization.Deserializer.Deserialize(dataSpan); +} +else +{ + if(data.Length <= 1024) + { + Span stackMemory = stackalloc byte[(int)data.Length]; + data.CopyTo(stackMemory); + obj = Nino.Serialization.Deserializer.Deserialize(stackMemory); + } + else + { + byte[] arr = ArrayPool.Shared.Rent((int)data.Length); + obj = Nino.Serialization.Deserializer.Deserialize(new Span(arr, 0, (int)data.Length)); + ArrayPool.Shared.Return(arr); + } +} ``` 传入需要反序列化的类型作为泛型参数,以及序列化结果的二进制数组,会返回反序列化出的对象实例 diff --git a/Nino_Unity/Assets/Nino/Generated/Nino_Test_BuildTestDataCodeGen_Serialize.cs b/Nino_Unity/Assets/Nino/Generated/Nino_Test_BuildTestDataCodeGen_Serialize.cs index 486f29a..de666c2 100644 --- a/Nino_Unity/Assets/Nino/Generated/Nino_Test_BuildTestDataCodeGen_Serialize.cs +++ b/Nino_Unity/Assets/Nino/Generated/Nino_Test_BuildTestDataCodeGen_Serialize.cs @@ -1,13 +1,21 @@ /* this is generated by nino */ +using System.Runtime.CompilerServices; + namespace Nino.Test { public partial class BuildTestDataCodeGen { public static BuildTestDataCodeGen.SerializationHelper NinoSerializationHelper = new BuildTestDataCodeGen.SerializationHelper(); - public class SerializationHelper: Nino.Serialization.NinoWrapperBase + public unsafe class SerializationHelper: Nino.Serialization.NinoWrapperBase { #region NINO_CODEGEN - public override void Serialize(BuildTestDataCodeGen value, Nino.Serialization.Writer writer) + public SerializationHelper() + { + + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void Serialize(BuildTestDataCodeGen value, ref Nino.Serialization.Writer writer) { if(value == null) { @@ -15,19 +23,19 @@ public override void Serialize(BuildTestDataCodeGen value, Nino.Serialization.Wr return; } writer.Write(true); - writer.Write(value.a); - writer.Write(value.b); - writer.Write(value.c); - writer.Write(value.d); - writer.CompressAndWrite(ref value.e); - writer.CompressAndWrite(ref value.f); - writer.CompressAndWrite(ref value.g); - writer.CompressAndWrite(ref value.h); - writer.Write(value.i); - writer.Write(value.j); - writer.Write(value.k); - writer.Write(value.l); - writer.Write(value.m); + writer.Write(ref value.a, sizeof(System.Byte)); + writer.Write(ref value.b, sizeof(System.SByte)); + writer.Write(ref value.c, sizeof(System.Int16)); + writer.Write(ref value.d, sizeof(System.UInt16)); + writer.Write(ref value.e, sizeof(System.Int32)); + writer.Write(ref value.f, sizeof(System.UInt32)); + writer.Write(ref value.g, sizeof(System.Int64)); + writer.Write(ref value.h, sizeof(System.UInt64)); + writer.Write(ref value.i, sizeof(System.Single)); + writer.Write(ref value.j, sizeof(System.Double)); + writer.Write(ref value.k, sizeof(System.Decimal)); + writer.Write(ref value.l, sizeof(System.Boolean)); + writer.Write(ref value.m, sizeof(System.Char)); writer.Write(value.n); writer.Write(value.o); writer.Write(value.p); @@ -39,24 +47,25 @@ public override void Serialize(BuildTestDataCodeGen value, Nino.Serialization.Wr writer.Write(value.v); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override BuildTestDataCodeGen Deserialize(Nino.Serialization.Reader reader) { if(!reader.ReadBool()) return null; BuildTestDataCodeGen value = new BuildTestDataCodeGen(); - reader.Read(ref value.a, 1); - reader.Read(ref value.b, 1); - reader.Read(ref value.c, Nino.Shared.Mgr.ConstMgr.SizeOfShort); - reader.Read(ref value.d, Nino.Shared.Mgr.ConstMgr.SizeOfUShort); - reader.DecompressAndReadNumber(ref value.e); - reader.DecompressAndReadNumber(ref value.f); - reader.DecompressAndReadNumber(ref value.g); - reader.DecompressAndReadNumber(ref value.h); - reader.Read(ref value.i, Nino.Shared.Mgr.ConstMgr.SizeOfUInt); - reader.Read(ref value.j, Nino.Shared.Mgr.ConstMgr.SizeOfULong); - reader.Read(ref value.k, Nino.Shared.Mgr.ConstMgr.SizeOfDecimal); - reader.Read(ref value.l, 1); - reader.Read(ref value.m, Nino.Shared.Mgr.ConstMgr.SizeOfUShort); + reader.Read(ref value.a, sizeof(System.Byte)); + reader.Read(ref value.b, sizeof(System.SByte)); + reader.Read(ref value.c, sizeof(System.Int16)); + reader.Read(ref value.d, sizeof(System.UInt16)); + reader.Read(ref value.e, sizeof(System.Int32)); + reader.Read(ref value.f, sizeof(System.UInt32)); + reader.Read(ref value.g, sizeof(System.Int64)); + reader.Read(ref value.h, sizeof(System.UInt64)); + reader.Read(ref value.i, sizeof(System.Single)); + reader.Read(ref value.j, sizeof(System.Double)); + reader.Read(ref value.k, sizeof(System.Decimal)); + reader.Read(ref value.l, sizeof(System.Boolean)); + reader.Read(ref value.m, sizeof(System.Char)); value.n = reader.ReadString(); value.o = reader.ReadList(); value.p = reader.ReadList(); @@ -68,6 +77,39 @@ public override BuildTestDataCodeGen Deserialize(Nino.Serialization.Reader reade value.v = reader.ReadDictionary(); return value; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetSize(BuildTestDataCodeGen value) + { + if(value == null) + { + return 1; + } + int ret = 1; + ret += Nino.Serialization.Serializer.GetSize(value.a); + ret += Nino.Serialization.Serializer.GetSize(value.b); + ret += Nino.Serialization.Serializer.GetSize(value.c); + ret += Nino.Serialization.Serializer.GetSize(value.d); + ret += Nino.Serialization.Serializer.GetSize(value.e); + ret += Nino.Serialization.Serializer.GetSize(value.f); + ret += Nino.Serialization.Serializer.GetSize(value.g); + ret += Nino.Serialization.Serializer.GetSize(value.h); + ret += Nino.Serialization.Serializer.GetSize(value.i); + ret += Nino.Serialization.Serializer.GetSize(value.j); + ret += Nino.Serialization.Serializer.GetSize(value.k); + ret += Nino.Serialization.Serializer.GetSize(value.l); + ret += Nino.Serialization.Serializer.GetSize(value.m); + ret += Nino.Serialization.Serializer.GetSize(value.n); + ret += Nino.Serialization.Serializer.GetSize(value.o); + ret += Nino.Serialization.Serializer.GetSize(value.p); + ret += Nino.Serialization.Serializer.GetSize(value.q); + ret += Nino.Serialization.Serializer.GetSize(value.r); + ret += Nino.Serialization.Serializer.GetSize(value.s); + ret += Nino.Serialization.Serializer.GetSize(value.t); + ret += Nino.Serialization.Serializer.GetSize(value.u); + ret += Nino.Serialization.Serializer.GetSize(value.v); + return ret; + } #endregion } } diff --git a/Nino_Unity/Assets/Nino/Generated/Nino_Test_CollectionTest_Serialize.cs b/Nino_Unity/Assets/Nino/Generated/Nino_Test_CollectionTest_Serialize.cs index 8418b8e..960f649 100644 --- a/Nino_Unity/Assets/Nino/Generated/Nino_Test_CollectionTest_Serialize.cs +++ b/Nino_Unity/Assets/Nino/Generated/Nino_Test_CollectionTest_Serialize.cs @@ -1,13 +1,21 @@ /* this is generated by nino */ +using System.Runtime.CompilerServices; + namespace Nino.Test { public partial class CollectionTest { public static CollectionTest.SerializationHelper NinoSerializationHelper = new CollectionTest.SerializationHelper(); - public class SerializationHelper: Nino.Serialization.NinoWrapperBase + public unsafe class SerializationHelper: Nino.Serialization.NinoWrapperBase { #region NINO_CODEGEN - public override void Serialize(CollectionTest value, Nino.Serialization.Writer writer) + public SerializationHelper() + { + + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void Serialize(CollectionTest value, ref Nino.Serialization.Writer writer) { if(value == null) { @@ -22,6 +30,7 @@ public override void Serialize(CollectionTest value, Nino.Serialization.Writer w writer.Write(value.e); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override CollectionTest Deserialize(Nino.Serialization.Reader reader) { if(!reader.ReadBool()) @@ -34,6 +43,22 @@ public override CollectionTest Deserialize(Nino.Serialization.Reader reader) value.e = reader.ReadDictionary(); return value; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetSize(CollectionTest value) + { + if(value == null) + { + return 1; + } + int ret = 1; + ret += Nino.Serialization.Serializer.GetSize(value.a); + ret += Nino.Serialization.Serializer.GetSize(value.b); + ret += Nino.Serialization.Serializer.GetSize(value.c); + ret += Nino.Serialization.Serializer.GetSize(value.d); + ret += Nino.Serialization.Serializer.GetSize(value.e); + return ret; + } #endregion } } diff --git a/Nino_Unity/Assets/Nino/Generated/Nino_Test_ComplexData_Serialize.cs b/Nino_Unity/Assets/Nino/Generated/Nino_Test_ComplexData_Serialize.cs index d643485..83ed16f 100644 --- a/Nino_Unity/Assets/Nino/Generated/Nino_Test_ComplexData_Serialize.cs +++ b/Nino_Unity/Assets/Nino/Generated/Nino_Test_ComplexData_Serialize.cs @@ -1,13 +1,21 @@ /* this is generated by nino */ +using System.Runtime.CompilerServices; + namespace Nino.Test { public partial class ComplexData { public static ComplexData.SerializationHelper NinoSerializationHelper = new ComplexData.SerializationHelper(); - public class SerializationHelper: Nino.Serialization.NinoWrapperBase + public unsafe class SerializationHelper: Nino.Serialization.NinoWrapperBase { #region NINO_CODEGEN - public override void Serialize(ComplexData value, Nino.Serialization.Writer writer) + public SerializationHelper() + { + + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void Serialize(ComplexData value, ref Nino.Serialization.Writer writer) { if(value == null) { @@ -27,6 +35,7 @@ public override void Serialize(ComplexData value, Nino.Serialization.Writer writ writer.Write(value.j); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override ComplexData Deserialize(Nino.Serialization.Reader reader) { if(!reader.ReadBool()) @@ -44,6 +53,27 @@ public override ComplexData Deserialize(Nino.Serialization.Reader reader) value.j = reader.ReadArray>(); return value; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetSize(ComplexData value) + { + if(value == null) + { + return 1; + } + int ret = 1; + ret += Nino.Serialization.Serializer.GetSize(value.a); + ret += Nino.Serialization.Serializer.GetSize(value.b); + ret += Nino.Serialization.Serializer.GetSize(value.c); + ret += Nino.Serialization.Serializer.GetSize(value.d); + ret += Nino.Serialization.Serializer.GetSize(value.e); + ret += Nino.Serialization.Serializer.GetSize(value.f); + ret += Nino.Serialization.Serializer.GetSize(value.g); + ret += Nino.Serialization.Serializer.GetSize(value.h); + ret += Nino.Serialization.Serializer.GetSize(value.i); + ret += Nino.Serialization.Serializer.GetSize(value.j); + return ret; + } #endregion } } diff --git a/Nino_Unity/Assets/Nino/Generated/Nino_Test_CustomTypeTest_Serialize.cs b/Nino_Unity/Assets/Nino/Generated/Nino_Test_CustomTypeTest_Serialize.cs index 7e67af7..9d42158 100644 --- a/Nino_Unity/Assets/Nino/Generated/Nino_Test_CustomTypeTest_Serialize.cs +++ b/Nino_Unity/Assets/Nino/Generated/Nino_Test_CustomTypeTest_Serialize.cs @@ -1,13 +1,21 @@ /* this is generated by nino */ +using System.Runtime.CompilerServices; + namespace Nino.Test { public partial class CustomTypeTest { public static CustomTypeTest.SerializationHelper NinoSerializationHelper = new CustomTypeTest.SerializationHelper(); - public class SerializationHelper: Nino.Serialization.NinoWrapperBase + public unsafe class SerializationHelper: Nino.Serialization.NinoWrapperBase { #region NINO_CODEGEN - public override void Serialize(CustomTypeTest value, Nino.Serialization.Writer writer) + public SerializationHelper() + { + + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void Serialize(CustomTypeTest value, ref Nino.Serialization.Writer writer) { if(value == null) { @@ -16,7 +24,7 @@ public override void Serialize(CustomTypeTest value, Nino.Serialization.Writer w } writer.Write(true); writer.WriteCommonVal(value.v3); - writer.Write(value.dt); + writer.Write(ref value.dt, sizeof(System.DateTime)); writer.WriteCommonVal>(value.ni); writer.Write(value.qs); writer.WriteCommonVal(value.m); @@ -24,13 +32,14 @@ public override void Serialize(CustomTypeTest value, Nino.Serialization.Writer w writer.Write(value.dict2); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override CustomTypeTest Deserialize(Nino.Serialization.Reader reader) { if(!reader.ReadBool()) return null; CustomTypeTest value = new CustomTypeTest(); value.v3 = reader.ReadCommonVal(); - value.dt = reader.ReadDateTime(); + reader.Read(ref value.dt, sizeof(System.DateTime)); value.ni = reader.ReadCommonVal>(); value.qs = reader.ReadList(); value.m = reader.ReadCommonVal(); @@ -38,6 +47,24 @@ public override CustomTypeTest Deserialize(Nino.Serialization.Reader reader) value.dict2 = reader.ReadDictionary(); return value; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetSize(CustomTypeTest value) + { + if(value == null) + { + return 1; + } + int ret = 1; + ret += Nino.Serialization.Serializer.GetSize(value.v3); + ret += Nino.Serialization.Serializer.GetSize(value.dt); + ret += Nino.Serialization.Serializer.GetSize(value.ni); + ret += Nino.Serialization.Serializer.GetSize(value.qs); + ret += Nino.Serialization.Serializer.GetSize(value.m); + ret += Nino.Serialization.Serializer.GetSize(value.dict); + ret += Nino.Serialization.Serializer.GetSize(value.dict2); + return ret; + } #endregion } } diff --git a/Nino_Unity/Assets/Nino/Generated/Nino_Test_Data_Serialize.cs b/Nino_Unity/Assets/Nino/Generated/Nino_Test_Data_Serialize.cs index d4d28e9..a896db9 100644 --- a/Nino_Unity/Assets/Nino/Generated/Nino_Test_Data_Serialize.cs +++ b/Nino_Unity/Assets/Nino/Generated/Nino_Test_Data_Serialize.cs @@ -1,47 +1,66 @@ /* this is generated by nino */ +using System.Runtime.CompilerServices; + namespace Nino.Test { - public partial class Data + public partial struct Data { public static Data.SerializationHelper NinoSerializationHelper = new Data.SerializationHelper(); - public class SerializationHelper: Nino.Serialization.NinoWrapperBase + public unsafe class SerializationHelper: Nino.Serialization.NinoWrapperBase { #region NINO_CODEGEN - public override void Serialize(Data value, Nino.Serialization.Writer writer) + public SerializationHelper() + { + int ret = 1; + ret += sizeof(System.Int32); + ret += sizeof(System.Int16); + ret += sizeof(System.Int64); + ret += sizeof(System.Single); + ret += sizeof(System.Decimal); + ret += sizeof(System.Double); + ret += sizeof(System.Boolean); + ret += sizeof(Nino.Test.TestEnum); + Nino.Serialization.Serializer.SetFixedSize(ret); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void Serialize(Data value, ref Nino.Serialization.Writer writer) { - if(value == null) - { - writer.Write(false); - return; - } + writer.Write(true); - writer.CompressAndWrite(ref value.x); - writer.Write(value.y); - writer.CompressAndWrite(ref value.z); - writer.Write(value.f); - writer.Write(value.d); - writer.Write(value.db); - writer.Write(value.bo); - writer.CompressAndWriteEnum(value.en); - writer.Write(value.name); + writer.Write(ref value.x, sizeof(System.Int32)); + writer.Write(ref value.y, sizeof(System.Int16)); + writer.Write(ref value.z, sizeof(System.Int64)); + writer.Write(ref value.f, sizeof(System.Single)); + writer.Write(ref value.d, sizeof(System.Decimal)); + writer.Write(ref value.db, sizeof(System.Double)); + writer.Write(ref value.bo, sizeof(System.Boolean)); + writer.WriteEnum(value.en); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override Data Deserialize(Nino.Serialization.Reader reader) { if(!reader.ReadBool()) - return null; + return default; Data value = new Data(); - reader.DecompressAndReadNumber(ref value.x); - reader.Read(ref value.y, Nino.Shared.Mgr.ConstMgr.SizeOfShort); - reader.DecompressAndReadNumber(ref value.z); - reader.Read(ref value.f, Nino.Shared.Mgr.ConstMgr.SizeOfUInt); - reader.Read(ref value.d, Nino.Shared.Mgr.ConstMgr.SizeOfDecimal); - reader.Read(ref value.db, Nino.Shared.Mgr.ConstMgr.SizeOfULong); - reader.Read(ref value.bo, 1); - reader.DecompressAndReadEnum(ref value.en); - value.name = reader.ReadString(); + reader.Read(ref value.x, sizeof(System.Int32)); + reader.Read(ref value.y, sizeof(System.Int16)); + reader.Read(ref value.z, sizeof(System.Int64)); + reader.Read(ref value.f, sizeof(System.Single)); + reader.Read(ref value.d, sizeof(System.Decimal)); + reader.Read(ref value.db, sizeof(System.Double)); + reader.Read(ref value.bo, sizeof(System.Boolean)); + reader.ReadEnum(ref value.en); return value; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetSize(Data value) + { + + return Nino.Serialization.Serializer.GetFixedSize(); + } #endregion } } diff --git a/Nino_Unity/Assets/Nino/Generated/Nino_Test_IncludeAllClassCodeGen_Serialize.cs b/Nino_Unity/Assets/Nino/Generated/Nino_Test_IncludeAllClassCodeGen_Serialize.cs index d0ba018..4fbb0a7 100644 --- a/Nino_Unity/Assets/Nino/Generated/Nino_Test_IncludeAllClassCodeGen_Serialize.cs +++ b/Nino_Unity/Assets/Nino/Generated/Nino_Test_IncludeAllClassCodeGen_Serialize.cs @@ -1,13 +1,21 @@ /* this is generated by nino */ +using System.Runtime.CompilerServices; + namespace Nino.Test { public partial class IncludeAllClassCodeGen { public static IncludeAllClassCodeGen.SerializationHelper NinoSerializationHelper = new IncludeAllClassCodeGen.SerializationHelper(); - public class SerializationHelper: Nino.Serialization.NinoWrapperBase + public unsafe class SerializationHelper: Nino.Serialization.NinoWrapperBase { #region NINO_CODEGEN - public override void Serialize(IncludeAllClassCodeGen value, Nino.Serialization.Writer writer) + public SerializationHelper() + { + + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void Serialize(IncludeAllClassCodeGen value, ref Nino.Serialization.Writer writer) { if(value == null) { @@ -15,23 +23,39 @@ public override void Serialize(IncludeAllClassCodeGen value, Nino.Serialization. return; } writer.Write(true); - writer.CompressAndWrite(ref value.a); - writer.CompressAndWrite(ref value.b); - writer.Write(value.c); - writer.Write(value.d); + writer.Write(ref value.a, sizeof(System.Int32)); + writer.Write(ref value.b, sizeof(System.Int64)); + writer.Write(ref value.c, sizeof(System.Single)); + writer.Write(ref value.d, sizeof(System.Double)); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override IncludeAllClassCodeGen Deserialize(Nino.Serialization.Reader reader) { if(!reader.ReadBool()) return null; IncludeAllClassCodeGen value = new IncludeAllClassCodeGen(); - reader.DecompressAndReadNumber(ref value.a); - reader.DecompressAndReadNumber(ref value.b); - reader.Read(ref value.c, Nino.Shared.Mgr.ConstMgr.SizeOfUInt); - reader.Read(ref value.d, Nino.Shared.Mgr.ConstMgr.SizeOfULong); + reader.Read(ref value.a, sizeof(System.Int32)); + reader.Read(ref value.b, sizeof(System.Int64)); + reader.Read(ref value.c, sizeof(System.Single)); + reader.Read(ref value.d, sizeof(System.Double)); return value; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetSize(IncludeAllClassCodeGen value) + { + if(value == null) + { + return 1; + } + int ret = 1; + ret += Nino.Serialization.Serializer.GetSize(value.a); + ret += Nino.Serialization.Serializer.GetSize(value.b); + ret += Nino.Serialization.Serializer.GetSize(value.c); + ret += Nino.Serialization.Serializer.GetSize(value.d); + return ret; + } #endregion } } diff --git a/Nino_Unity/Assets/Nino/Generated/Nino_Test_NestedData2_Serialize.cs b/Nino_Unity/Assets/Nino/Generated/Nino_Test_NestedData2_Serialize.cs index 93bf5da..1f48182 100644 --- a/Nino_Unity/Assets/Nino/Generated/Nino_Test_NestedData2_Serialize.cs +++ b/Nino_Unity/Assets/Nino/Generated/Nino_Test_NestedData2_Serialize.cs @@ -1,13 +1,21 @@ /* this is generated by nino */ +using System.Runtime.CompilerServices; + namespace Nino.Test { public partial class NestedData2 { public static NestedData2.SerializationHelper NinoSerializationHelper = new NestedData2.SerializationHelper(); - public class SerializationHelper: Nino.Serialization.NinoWrapperBase + public unsafe class SerializationHelper: Nino.Serialization.NinoWrapperBase { #region NINO_CODEGEN - public override void Serialize(NestedData2 value, Nino.Serialization.Writer writer) + public SerializationHelper() + { + + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void Serialize(NestedData2 value, ref Nino.Serialization.Writer writer) { if(value == null) { @@ -20,6 +28,7 @@ public override void Serialize(NestedData2 value, Nino.Serialization.Writer writ writer.Write(value.vs); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override NestedData2 Deserialize(Nino.Serialization.Reader reader) { if(!reader.ReadBool()) @@ -30,6 +39,20 @@ public override NestedData2 Deserialize(Nino.Serialization.Reader reader) value.vs = reader.ReadList(); return value; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetSize(NestedData2 value) + { + if(value == null) + { + return 1; + } + int ret = 1; + ret += Nino.Serialization.Serializer.GetSize(value.name); + ret += Nino.Serialization.Serializer.GetSize(value.ps); + ret += Nino.Serialization.Serializer.GetSize(value.vs); + return ret; + } #endregion } } diff --git a/Nino_Unity/Assets/Nino/Generated/Nino_Test_NestedData_Serialize.cs b/Nino_Unity/Assets/Nino/Generated/Nino_Test_NestedData_Serialize.cs index 84b541d..e6688da 100644 --- a/Nino_Unity/Assets/Nino/Generated/Nino_Test_NestedData_Serialize.cs +++ b/Nino_Unity/Assets/Nino/Generated/Nino_Test_NestedData_Serialize.cs @@ -1,13 +1,21 @@ /* this is generated by nino */ +using System.Runtime.CompilerServices; + namespace Nino.Test { public partial class NestedData { public static NestedData.SerializationHelper NinoSerializationHelper = new NestedData.SerializationHelper(); - public class SerializationHelper: Nino.Serialization.NinoWrapperBase + public unsafe class SerializationHelper: Nino.Serialization.NinoWrapperBase { #region NINO_CODEGEN - public override void Serialize(NestedData value, Nino.Serialization.Writer writer) + public SerializationHelper() + { + + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void Serialize(NestedData value, ref Nino.Serialization.Writer writer) { if(value == null) { @@ -19,6 +27,7 @@ public override void Serialize(NestedData value, Nino.Serialization.Writer write writer.Write(value.ps); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override NestedData Deserialize(Nino.Serialization.Reader reader) { if(!reader.ReadBool()) @@ -28,6 +37,19 @@ public override NestedData Deserialize(Nino.Serialization.Reader reader) value.ps = reader.ReadArray(); return value; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetSize(NestedData value) + { + if(value == null) + { + return 1; + } + int ret = 1; + ret += Nino.Serialization.Serializer.GetSize(value.name); + ret += Nino.Serialization.Serializer.GetSize(value.ps); + return ret; + } #endregion } } diff --git a/Nino_Unity/Assets/Nino/Generated/Nino_Test_NotIncludeAllClass_Serialize.cs b/Nino_Unity/Assets/Nino/Generated/Nino_Test_NotIncludeAllClass_Serialize.cs index 476e0eb..bdaab0a 100644 --- a/Nino_Unity/Assets/Nino/Generated/Nino_Test_NotIncludeAllClass_Serialize.cs +++ b/Nino_Unity/Assets/Nino/Generated/Nino_Test_NotIncludeAllClass_Serialize.cs @@ -1,13 +1,21 @@ /* this is generated by nino */ +using System.Runtime.CompilerServices; + namespace Nino.Test { public partial class NotIncludeAllClass { public static NotIncludeAllClass.SerializationHelper NinoSerializationHelper = new NotIncludeAllClass.SerializationHelper(); - public class SerializationHelper: Nino.Serialization.NinoWrapperBase + public unsafe class SerializationHelper: Nino.Serialization.NinoWrapperBase { #region NINO_CODEGEN - public override void Serialize(NotIncludeAllClass value, Nino.Serialization.Writer writer) + public SerializationHelper() + { + + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void Serialize(NotIncludeAllClass value, ref Nino.Serialization.Writer writer) { if(value == null) { @@ -15,23 +23,39 @@ public override void Serialize(NotIncludeAllClass value, Nino.Serialization.Writ return; } writer.Write(true); - writer.CompressAndWrite(ref value.a); - writer.CompressAndWrite(ref value.b); - writer.Write(value.c); - writer.Write(value.d); + writer.Write(ref value.a, sizeof(System.Int32)); + writer.Write(ref value.b, sizeof(System.Int64)); + writer.Write(ref value.c, sizeof(System.Single)); + writer.Write(ref value.d, sizeof(System.Double)); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override NotIncludeAllClass Deserialize(Nino.Serialization.Reader reader) { if(!reader.ReadBool()) return null; NotIncludeAllClass value = new NotIncludeAllClass(); - reader.DecompressAndReadNumber(ref value.a); - reader.DecompressAndReadNumber(ref value.b); - reader.Read(ref value.c, Nino.Shared.Mgr.ConstMgr.SizeOfUInt); - reader.Read(ref value.d, Nino.Shared.Mgr.ConstMgr.SizeOfULong); + reader.Read(ref value.a, sizeof(System.Int32)); + reader.Read(ref value.b, sizeof(System.Int64)); + reader.Read(ref value.c, sizeof(System.Single)); + reader.Read(ref value.d, sizeof(System.Double)); return value; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetSize(NotIncludeAllClass value) + { + if(value == null) + { + return 1; + } + int ret = 1; + ret += Nino.Serialization.Serializer.GetSize(value.a); + ret += Nino.Serialization.Serializer.GetSize(value.b); + ret += Nino.Serialization.Serializer.GetSize(value.c); + ret += Nino.Serialization.Serializer.GetSize(value.d); + return ret; + } #endregion } } diff --git a/Nino_Unity/Assets/Nino/Serialization/CodeGenerator.cs b/Nino_Unity/Assets/Nino/Serialization/CodeGenerator.cs index d5ded0c..9bff4d5 100644 --- a/Nino_Unity/Assets/Nino/Serialization/CodeGenerator.cs +++ b/Nino_Unity/Assets/Nino/Serialization/CodeGenerator.cs @@ -6,6 +6,7 @@ using Nino.Shared.Util; using System.Reflection; using System.Collections.Generic; +using System.Runtime.CompilerServices; namespace Nino.Serialization { @@ -93,21 +94,30 @@ public static void GenerateSerializationCode(Type type, string outputPath = "Nin //code template string template = @"/* this is generated by nino */ +using System.Runtime.CompilerServices; + {namespace} {start} public partial struct {type} { public static {type}.SerializationHelper NinoSerializationHelper = new {type}.SerializationHelper(); - public class SerializationHelper: Nino.Serialization.NinoWrapperBase<{type}> + public unsafe class SerializationHelper: Nino.Serialization.NinoWrapperBase<{type}> { #region NINO_CODEGEN - public override void Serialize({type} value, Nino.Serialization.Writer writer) + public SerializationHelper() + { +{ctor} + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void Serialize({type} value, ref Nino.Serialization.Writer writer) { {nullCheck} writer.Write(true); {members} } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override {type} Deserialize(Nino.Serialization.Reader reader) { if(!reader.ReadBool()) @@ -115,6 +125,13 @@ public override void Serialize({type} value, Nino.Serialization.Writer writer) {type} value = new {type}(); {fields} } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetSize({type} value) + { + {sizeNull} +{size} + } #endregion } } @@ -123,17 +140,21 @@ public override void Serialize({type} value, Nino.Serialization.Writer writer) { template = template.Replace("struct", "class"); template = template.Replace("{nullCheck}", @"if(value == null) -{ - writer.Write(false); - return; -}"); + { + writer.Write(false); + return; + }"); template = template.Replace("{returnNull}", "return null;"); + template = template.Replace("{sizeNull}", @"if(value == null) + { + return 1; + }"); } else { template = template.Replace("{nullCheck}", @""); template = template.Replace("{returnNull}", "return default;"); - + template = template.Replace("{sizeNull}", @""); } //replace namespace @@ -186,7 +207,7 @@ public override void Serialize({type} value, Nino.Serialization.Writer writer) if (mt.IsEnum) { sb.Append( - $" writer.CompressAndWriteEnum<{BeautifulLongTypeName(mt)}>(value.{member.Name});\n"); + $" writer.WriteEnum<{BeautifulLongTypeName(mt)}>(value.{member.Name});\n"); } //array/list else if (mt.IsArray || (mt.IsGenericType && mt.GetGenericTypeDefinition() == ConstMgr.ListDefType)) @@ -201,7 +222,8 @@ public override void Serialize({type} value, Nino.Serialization.Writer writer) //basic type else { - sb.Append($" {GetSerializeBasicTypeStatement(mt, $"value.{member.Name}", member is PropertyInfo)};\n"); + sb.Append( + $" {GetSerializeBasicTypeStatement(mt, $"value.{member.Name}", member is PropertyInfo)};\n"); } } @@ -228,12 +250,12 @@ public override void Serialize({type} value, Nino.Serialization.Writer writer) if (member is PropertyInfo) { sb.Append( - $" value.{member.Name} = reader.DecompressAndReadEnum<{BeautifulLongTypeName(mt)}>();\n"); + $" value.{member.Name} = reader.ReadEnum<{BeautifulLongTypeName(mt)}>();\n"); } else { sb.Append( - $" reader.DecompressAndReadEnum<{BeautifulLongTypeName(mt)}>(ref value.{member.Name});\n"); + $" reader.ReadEnum<{BeautifulLongTypeName(mt)}>(ref value.{member.Name});\n"); } } //array/list @@ -250,7 +272,7 @@ public override void Serialize({type} value, Nino.Serialization.Writer writer) throw new NotSupportedException( "can not serialize multidimensional array, use jagged array instead"); } - + sb.Append( $" value.{member.Name} = reader.ReadArray<{BeautifulLongTypeName(elemType)}>();\n"); } @@ -275,20 +297,7 @@ public override void Serialize({type} value, Nino.Serialization.Writer writer) { string val = GetDeserializeBasicTypeStatement(mt, member is PropertyInfo, $"value.{member.Name}"); - switch (Type.GetTypeCode(mt)) - { - case TypeCode.Int32: - case TypeCode.UInt32: - case TypeCode.Int64: - case TypeCode.UInt64: - sb.Append($" {val}\n"); - break; - default: - sb.Append(FullDeserializeStatement(mt, member is PropertyInfo) - ? $" {val}\n" - : $" value.{member.Name} = {val};\n"); - break; - } + sb.Append($" {val}\n"); } } @@ -301,6 +310,49 @@ public override void Serialize({type} value, Nino.Serialization.Writer writer) #endregion + #region getsize + + sb.Clear(); + if (TypeModel.IsUnmanaged(type)) + { + sb.Append($" return Nino.Serialization.Serializer.GetFixedSize<{BeautifulLongTypeName(type)}>();"); + } + else + { + sb.Append(" int ret = 1;\n"); + foreach (var member in members) + { + sb.Append( + $" ret += Nino.Serialization.Serializer.GetSize(value.{member.Name});\n"); + } + sb.Append(" return ret;"); + } + + //replace template fields + template = template.Replace("{size}", sb.ToString()); + + #endregion + + #region ctor + + sb.Clear(); + if (TypeModel.IsUnmanaged(type)) + { + sb.Append(" int ret = 1;\n"); + foreach (var member in members) + { + var mt = member is FieldInfo fi ? fi.FieldType : ((PropertyInfo)member).PropertyType; + sb.Append( + $" ret += sizeof({BeautifulLongTypeName(mt)});\n"); + } + sb.Append($" Nino.Serialization.Serializer.SetFixedSize<{BeautifulLongTypeName(type)}>(ret);"); + } + + //replace template fields + template = template.Replace("{ctor}", sb.ToString()); + + #endregion + //save path var output = Path.Combine(ConstMgr.AssetPath, outputPath); if (!Directory.Exists(output)) @@ -329,31 +381,6 @@ public override void Serialize({type} value, Nino.Serialization.Writer writer) #endif } - private static bool FullDeserializeStatement(Type type, bool isProperty) - { - if (isProperty) return false; - switch (Type.GetTypeCode(type)) - { - case TypeCode.Byte: - case TypeCode.SByte: - case TypeCode.Int16: - case TypeCode.UInt16: - case TypeCode.Boolean: - case TypeCode.Double: - case TypeCode.Single: - case TypeCode.Decimal: - case TypeCode.Char: - return true; - default: - if ((type.IsGenericType && type.GetGenericTypeDefinition() == ConstMgr.DictDefType)) - { - return true; - } - - return false; - } - } - // ReSharper disable CognitiveComplexity private static string GetDeserializeBasicTypeStatement(Type mt, bool isProperty, string val = "", string space = " ") @@ -365,55 +392,33 @@ private static string GetDeserializeBasicTypeStatement(Type mt, bool isProperty, case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: - return isProperty - ? $"{val} = reader.DecompressAndReadNumber<{BeautifulLongTypeName(mt)}>();" - : $"reader.DecompressAndReadNumber<{BeautifulLongTypeName(mt)}>(ref {val});"; case TypeCode.Byte: - return isProperty ? "reader.ReadByte()" : $"reader.Read(ref {val}, 1);"; case TypeCode.SByte: - return isProperty ? "reader.ReadSByte()" : $"reader.Read(ref {val}, 1);"; case TypeCode.Int16: - return isProperty - ? "reader.ReadInt16()" - : $"reader.Read(ref {val}, Nino.Shared.Mgr.ConstMgr.SizeOfShort);"; case TypeCode.UInt16: - return isProperty - ? "reader.ReadUInt16()" - : $"reader.Read(ref {val}, Nino.Shared.Mgr.ConstMgr.SizeOfUShort);"; - case TypeCode.String: - return "reader.ReadString()"; case TypeCode.Boolean: - return isProperty ? "reader.ReadBool()" : $"reader.Read(ref {val}, 1);"; case TypeCode.Double: - return isProperty - ? "reader.ReadDouble()" - : $"reader.Read(ref {val}, Nino.Shared.Mgr.ConstMgr.SizeOfULong);"; case TypeCode.Single: - return isProperty - ? "reader.ReadSingle()" - : $"reader.Read(ref {val}, Nino.Shared.Mgr.ConstMgr.SizeOfUInt);"; case TypeCode.Decimal: - return isProperty - ? "reader.ReadDecimal()" - : $"reader.Read(ref {val}, Nino.Shared.Mgr.ConstMgr.SizeOfDecimal);"; case TypeCode.Char: - return isProperty - ? "reader.ReadChar()" - : $"reader.Read(ref {val}, Nino.Shared.Mgr.ConstMgr.SizeOfUShort);"; case TypeCode.DateTime: - return "reader.ReadDateTime()"; + return isProperty + ? $"{val} = reader.Read<{BeautifulLongTypeName(mt)}>(sizeof({BeautifulLongTypeName(mt)}));" + : $"reader.Read<{BeautifulLongTypeName(mt)}>(ref {val}, sizeof({BeautifulLongTypeName(mt)}));"; + case TypeCode.String: + return $"{val} = reader.ReadString();"; default: if (GetValidNinoClass(mt, false)) { - return $"{BeautifulLongTypeName(mt)}.NinoSerializationHelper.Deserialize(reader)"; + return $"{val} = {BeautifulLongTypeName(mt)}.NinoSerializationHelper.Deserialize(reader)"; } - + //enum if (mt.IsEnum) { return isProperty - ? $"reader.DecompressAndReadEnum<{BeautifulLongTypeName(mt)}>()" - : $"reader.DecompressAndReadEnum<{BeautifulLongTypeName(mt)}>(ref {val});"; + ? $"{val} = reader.ReadEnum<{BeautifulLongTypeName(mt)}>();" + : $"reader.ReadEnum<{BeautifulLongTypeName(mt)}>(ref {val});"; } if (mt.IsArray || @@ -429,15 +434,16 @@ private static string GetDeserializeBasicTypeStatement(Type mt, bool isProperty, throw new NotSupportedException( "can not serialize multidimensional array, use jagged array instead"); } - + builder.Append( - $"reader.ReadArray<{BeautifulLongTypeName(elemType)}>();\n"); + $"{val} = reader.ReadArray<{BeautifulLongTypeName(elemType)}>();\n"); } else { builder.Append( - $"reader.ReadList<{BeautifulLongTypeName(elemType)}>();\n"); + $"{val} = reader.ReadList<{BeautifulLongTypeName(elemType)}>();\n"); } + return builder.ToString(); } @@ -453,7 +459,7 @@ private static string GetDeserializeBasicTypeStatement(Type mt, bool isProperty, return builder.ToString(); } - return $"reader.ReadCommonVal<{BeautifulLongTypeName(mt)}>()"; + return $"{val} = reader.ReadCommonVal<{BeautifulLongTypeName(mt)}>();"; } } @@ -468,18 +474,20 @@ private static string GetSerializeBasicTypeStatement(Type mt, string val, bool i case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: - return isProperty ? $"writer.CompressAndWrite({val})" : $"writer.CompressAndWrite(ref {val})"; case TypeCode.Byte: case TypeCode.SByte: case TypeCode.Int16: case TypeCode.UInt16: - case TypeCode.String: case TypeCode.Boolean: case TypeCode.Double: case TypeCode.Single: case TypeCode.Decimal: case TypeCode.Char: case TypeCode.DateTime: + return isProperty + ? $"writer.Write({val})" + : $"writer.Write(ref {val}, sizeof({BeautifulLongTypeName(mt)}))"; + case TypeCode.String: return $"writer.Write({val})"; default: if (GetValidNinoClass(mt, false)) diff --git a/Nino_Unity/Assets/Nino/Serialization/Deserializer.Generic.cs b/Nino_Unity/Assets/Nino/Serialization/Deserializer.Generic.cs index 554043f..7de3e7e 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Deserializer.Generic.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Deserializer.Generic.cs @@ -13,34 +13,30 @@ public static partial class Deserializer /// /// /// - /// /// - public static T[] DeserializeArray(byte[] data, CompressOption option = CompressOption.Zlib) - => DeserializeArray(new Span(data), option); + public static T[] DeserializeArray(byte[] data) + => DeserializeArray(new Span(data)); /// /// Deserialize an array NinoSerialize object /// /// /// - /// /// - public static T[] DeserializeArray(ArraySegment data, CompressOption option = CompressOption.Zlib) - => DeserializeArray(new Span(data.Array, data.Offset, data.Count), option); + public static T[] DeserializeArray(ArraySegment data) + => DeserializeArray(new Span(data.Array, data.Offset, data.Count)); /// /// Deserialize an array of NinoSerialize object /// /// /// - /// /// - public static T[] DeserializeArray(Span data, CompressOption option = CompressOption.Zlib) + public static T[] DeserializeArray(Span data) { var type = typeof(T[]); var reader = ObjectPool.Request(); - reader.Init(data, data.Length, - TypeModel.IsNonCompressibleType(type) ? CompressOption.NoCompression : option); + reader.Init(data, data.Length); /* * NO GC DESERIALIZATION ATTEMPT @@ -64,37 +60,32 @@ public static T[] DeserializeArray(Span data, CompressOption option = C /// /// /// - /// /// - public static T? DeserializeNullable(byte[] data, CompressOption option = CompressOption.Zlib) + public static T? DeserializeNullable(byte[] data) where T : struct - => DeserializeNullable(new Span(data), option); + => DeserializeNullable(new Span(data)); /// /// Deserialize a nullable of NinoSerialize struct /// /// /// - /// /// - public static T? DeserializeNullable(ArraySegment data, CompressOption option = CompressOption.Zlib) + public static T? DeserializeNullable(ArraySegment data) where T : struct - => DeserializeNullable(new Span(data.Array, data.Offset, data.Count), option); + => DeserializeNullable(new Span(data.Array, data.Offset, data.Count)); /// /// Deserialize a nullable of NinoSerialize struct /// /// /// - /// /// - public static T? DeserializeNullable(Span data, CompressOption option = CompressOption.Zlib) + public static T? DeserializeNullable(Span data) where T : struct { - var type = typeof(T?); var reader = ObjectPool.Request(); - reader.Init(data, data.Length, - TypeModel.IsNonCompressibleType(type) ? CompressOption.NoCompression : option); + reader.Init(data, data.Length); //attempt to deserialize using generic method return reader.ReadNullable(); @@ -109,40 +100,36 @@ public static T[] DeserializeArray(Span data, CompressOption option = C /// /// /// - /// /// - public static List DeserializeList(byte[] data, CompressOption option = CompressOption.Zlib) - => DeserializeList(new Span(data), option); + public static List DeserializeList(byte[] data) + => DeserializeList(new Span(data)); /// /// Deserialize a list of NinoSerialize object /// /// /// - /// /// - public static List DeserializeList(ArraySegment data, CompressOption option = CompressOption.Zlib) - => DeserializeList(new Span(data.Array, data.Offset, data.Count), option); + public static List DeserializeList(ArraySegment data) + => DeserializeList(new Span(data.Array, data.Offset, data.Count)); /// /// Deserialize a list of NinoSerialize object /// /// /// - /// /// - public static List DeserializeList(Span data, CompressOption option = CompressOption.Zlib) + public static List DeserializeList(Span data) { var type = typeof(List); var reader = ObjectPool.Request(); - reader.Init(data, data.Length, - TypeModel.IsNonCompressibleType(type) ? CompressOption.NoCompression : option); + reader.Init(data, data.Length); /* * NO GC DESERIALIZATION ATTEMPT */ //basic type - if (TryDeserializeWrapperType(typeof(List), reader, false, true, out List ret)) + if (TryDeserializeWrapperType(type, reader, false, true, out List ret)) { return ret; } @@ -160,41 +147,36 @@ public static List DeserializeList(Span data, CompressOption option /// /// /// - /// /// - public static HashSet DeserializeHashSet(byte[] data, CompressOption option = CompressOption.Zlib) - => DeserializeHashSet(new Span(data), option); + public static HashSet DeserializeHashSet(byte[] data) + => DeserializeHashSet(new Span(data)); /// /// Deserialize a HashSet of NinoSerialize object /// /// /// - /// /// - public static HashSet DeserializeHashSet(ArraySegment data, - CompressOption option = CompressOption.Zlib) - => DeserializeHashSet(new Span(data.Array, data.Offset, data.Count), option); + public static HashSet DeserializeHashSet(ArraySegment data) + => DeserializeHashSet(new Span(data.Array, data.Offset, data.Count)); /// /// Deserialize a HashSet of NinoSerialize object /// /// /// - /// /// - public static HashSet DeserializeHashSet(Span data, CompressOption option = CompressOption.Zlib) + public static HashSet DeserializeHashSet(Span data) { var type = typeof(HashSet); var reader = ObjectPool.Request(); - reader.Init(data, data.Length, - TypeModel.IsNonCompressibleType(type) ? CompressOption.NoCompression : option); + reader.Init(data, data.Length); /* * NO GC DESERIALIZATION ATTEMPT */ //basic type - if (TryDeserializeWrapperType(typeof(HashSet), reader, false, true, out HashSet ret)) + if (TryDeserializeWrapperType(type, reader, false, true, out HashSet ret)) { return ret; } @@ -212,40 +194,36 @@ public static HashSet DeserializeHashSet(Span data, CompressOption o /// /// /// - /// /// - public static Queue DeserializeQueue(byte[] data, CompressOption option = CompressOption.Zlib) - => DeserializeQueue(new Span(data), option); + public static Queue DeserializeQueue(byte[] data) + => DeserializeQueue(new Span(data)); /// /// Deserialize a Queue of NinoSerialize object /// /// /// - /// /// - public static Queue DeserializeQueue(ArraySegment data, CompressOption option = CompressOption.Zlib) - => DeserializeQueue(new Span(data.Array, data.Offset, data.Count), option); + public static Queue DeserializeQueue(ArraySegment data) + => DeserializeQueue(new Span(data.Array, data.Offset, data.Count)); /// /// Deserialize a Queue of NinoSerialize object /// /// /// - /// /// - public static Queue DeserializeQueue(Span data, CompressOption option = CompressOption.Zlib) + public static Queue DeserializeQueue(Span data) { var type = typeof(Queue); var reader = ObjectPool.Request(); - reader.Init(data, data.Length, - TypeModel.IsNonCompressibleType(type) ? CompressOption.NoCompression : option); + reader.Init(data, data.Length); /* * NO GC DESERIALIZATION ATTEMPT */ //basic type - if (TryDeserializeWrapperType(typeof(Queue), reader, false, true, out Queue ret)) + if (TryDeserializeWrapperType(type, reader, false, true, out Queue ret)) { return ret; } @@ -263,40 +241,36 @@ public static Queue DeserializeQueue(Span data, CompressOption optio /// /// /// - /// /// - public static Stack DeserializeStack(byte[] data, CompressOption option = CompressOption.Zlib) - => DeserializeStack(new Span(data), option); + public static Stack DeserializeStack(byte[] data) + => DeserializeStack(new Span(data)); /// /// Deserialize a Stack of NinoSerialize object /// /// /// - /// /// - public static Stack DeserializeStack(ArraySegment data, CompressOption option = CompressOption.Zlib) - => DeserializeStack(new Span(data.Array, data.Offset, data.Count), option); + public static Stack DeserializeStack(ArraySegment data) + => DeserializeStack(new Span(data.Array, data.Offset, data.Count)); /// /// Deserialize a Stack of NinoSerialize object /// /// /// - /// /// - public static Stack DeserializeStack(Span data, CompressOption option = CompressOption.Zlib) + public static Stack DeserializeStack(Span data) { var type = typeof(Stack); var reader = ObjectPool.Request(); - reader.Init(data, data.Length, - TypeModel.IsNonCompressibleType(type) ? CompressOption.NoCompression : option); + reader.Init(data, data.Length); /* * NO GC DESERIALIZATION ATTEMPT */ //basic type - if (TryDeserializeWrapperType(typeof(Stack), reader, false, true, out Stack ret)) + if (TryDeserializeWrapperType(type, reader, false, true, out Stack ret)) { return ret; } @@ -315,11 +289,9 @@ public static Stack DeserializeStack(Span data, CompressOption optio /// /// /// - /// /// - public static Dictionary DeserializeDictionary(byte[] data, - CompressOption option = CompressOption.Zlib) - => DeserializeDictionary(new Span(data), option); + public static Dictionary DeserializeDictionary(byte[] data) + => DeserializeDictionary(new Span(data)); /// /// Deserialize a Dictionary of NinoSerialize object @@ -327,11 +299,9 @@ public static Dictionary DeserializeDictionary(byte[ /// /// /// - /// /// - public static Dictionary DeserializeDictionary(ArraySegment data, - CompressOption option = CompressOption.Zlib) - => DeserializeDictionary(new Span(data.Array, data.Offset, data.Count), option); + public static Dictionary DeserializeDictionary(ArraySegment data) + => DeserializeDictionary(new Span(data.Array, data.Offset, data.Count)); /// /// Deserialize a Dictionary of NinoSerialize object @@ -339,21 +309,18 @@ public static Dictionary DeserializeDictionary(Array /// /// /// - /// /// - public static Dictionary DeserializeDictionary(Span data, - CompressOption option = CompressOption.Zlib) + public static Dictionary DeserializeDictionary(Span data) { var type = typeof(Dictionary); var reader = ObjectPool.Request(); - reader.Init(data, data.Length, - TypeModel.IsNonCompressibleType(type) ? CompressOption.NoCompression : option); + reader.Init(data, data.Length); /* * NO GC DESERIALIZATION ATTEMPT */ //basic type - if (TryDeserializeWrapperType(typeof(Dictionary), reader, false, true, + if (TryDeserializeWrapperType(type, reader, false, true, out Dictionary ret)) { return ret; diff --git a/Nino_Unity/Assets/Nino/Serialization/Deserializer.cs b/Nino_Unity/Assets/Nino/Serialization/Deserializer.cs index ed4d367..8273981 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Deserializer.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Deserializer.cs @@ -3,7 +3,6 @@ using Nino.Shared.Mgr; using System.Reflection; using System.Collections; -using System.Collections.Generic; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; @@ -12,71 +11,58 @@ namespace Nino.Serialization public static partial class Deserializer { /// - /// Custom Exporter delegate that reads bytes to object + /// Deserialize a NinoSerialize object /// - internal delegate T ExporterDelegate(Reader reader); + /// + /// + /// + public static T Deserialize(byte[] data) + => Deserialize(new Span(data), null); /// - /// Add custom Exporter of all type T objects + /// Deserialize a NinoSerialize object /// - /// /// - public static void AddCustomExporter(Func func) - { - var type = typeof(T); - if (WrapperManifest.TryGetWrapper(type, out var wrapper)) - { - ((GenericWrapper)wrapper).Exporter = func.Invoke; - return; - } - - GenericWrapper genericWrapper = new GenericWrapper - { - Exporter = func.Invoke - }; - WrapperManifest.AddWrapper(typeof(T), genericWrapper); - } + /// + /// + public static T Deserialize(ArraySegment data) + => Deserialize(new Span(data.Array, data.Offset, data.Count), null); /// /// Deserialize a NinoSerialize object /// /// /// - /// /// - public static T Deserialize(byte[] data, CompressOption option = CompressOption.Zlib) - => Deserialize(new Span(data), null, option); + public static T Deserialize(Span data) + => Deserialize(data, null); /// /// Deserialize a NinoSerialize object /// - /// + /// /// - /// /// - public static T Deserialize(ArraySegment data, CompressOption option = CompressOption.Zlib) - => Deserialize(new Span(data.Array, data.Offset, data.Count), null, option); + public static object Deserialize(Type type, byte[] data) + => Deserialize(type, null, new Span(data), null); /// /// Deserialize a NinoSerialize object /// /// /// - /// /// - public static object Deserialize(Type type, byte[] data, CompressOption option = CompressOption.Zlib) - => Deserialize(type, null, new Span(data), null, option); + public static object Deserialize(Type type, ArraySegment data) + => Deserialize(type, null, new Span(data.Array, data.Offset, data.Count), null); /// /// Deserialize a NinoSerialize object /// /// /// - /// /// - public static object Deserialize(Type type, ArraySegment data, - CompressOption option = CompressOption.Zlib) - => Deserialize(type, null, new Span(data.Array, data.Offset, data.Count), null, option); + public static object Deserialize(Type type, Span data) + => Deserialize(type, null, data, null); /// /// Deserialize a NinoSerialize object @@ -84,19 +70,17 @@ public static object Deserialize(Type type, ArraySegment data, /// /// /// - /// /// /// internal static T Deserialize(Span data, Reader reader, - CompressOption option = CompressOption.Zlib, [MarshalAs(UnmanagedType.U1)] bool returnDispose = true) + [MarshalAs(UnmanagedType.U1)] bool returnDispose = true) { Type type = typeof(T); if (reader == null) { reader = ObjectPool.Request(); - reader.Init(data, data.Length, - TypeModel.IsNonCompressibleType(type) ? CompressOption.NoCompression : option); + reader.Init(data, data.Length); } /* @@ -117,7 +101,7 @@ internal static T Deserialize(Span data, Reader reader, /* * GC DESERIALIZATION WHILE T IS STRUCT */ - var result = Deserialize(type, null, data, reader, option, returnDispose); + var result = Deserialize(type, null, data, reader, returnDispose); if (result != null) return (T)result; ObjectPool.Return(reader); return default; @@ -130,19 +114,17 @@ internal static T Deserialize(Span data, Reader reader, /// /// /// - /// /// /// /// /// internal static object Deserialize(Type type, object val, Span data, Reader reader, - CompressOption option = CompressOption.Zlib, [MarshalAs(UnmanagedType.U1)] bool returnDispose = true) + [MarshalAs(UnmanagedType.U1)] bool returnDispose = true) { if (reader == null) { reader = ObjectPool.Request(); - reader.Init(data, data.Length, - TypeModel.IsNonCompressibleType(type) ? CompressOption.NoCompression : option); + reader.Init(data, data.Length); } //array @@ -222,51 +204,18 @@ internal static object Deserialize(Type type, object val, Span data, Reade } //start Deserialize - //only include all model need this - if (model.IncludeAll) + foreach (var member in model.Members) { - //read len - var len = reader.ReadLength(); - Dictionary values = ObjectPool>.Request(); - values.Clear(); - //read elements key by key - for (int i = 0; i < len; i++) - { - var key = reader.ReadString(); - var typeFullName = reader.ReadString(); - var value = Deserialize(Type.GetType(typeFullName), ConstMgr.Null, ConstMgr.Null, reader, - option, false); - values.Add(key, value); - } - - //set elements - foreach (var member in model.Members) + //if end, skip + if (reader.EndOfReader) { - //try get same member and set it - if (values.TryGetValue(member.Name, out var ret)) - { - SetMember(member, val, ret); - } + break; } - values.Clear(); - ObjectPool>.Return(values); - } - else - { - foreach (var member in model.Members) - { - //if end, skip - if (reader.EndOfReader) - { - break; - } - - type = member is FieldInfo fi ? fi.FieldType : ((PropertyInfo)member).PropertyType; + type = member is FieldInfo fi ? fi.FieldType : ((PropertyInfo)member).PropertyType; - //read basic values - SetMember(member, val, Deserialize(type, ConstMgr.Null, Span.Empty, reader, option, false)); - } + //read basic values + SetMember(member, val, Deserialize(type, ConstMgr.Null, Span.Empty, reader, false)); } if (returnDispose) @@ -450,7 +399,7 @@ private static bool TryDeserializeEnum(Type type, Reader reader, if (TypeModel.IsEnum(type)) { var underlyingType = Enum.GetUnderlyingType(type); - var ret = reader.DecompressAndReadEnum(underlyingType); + var ret = reader.ReadEnum(underlyingType); #if ILRuntime if (type is ILRuntime.Reflection.ILRuntimeType) { diff --git a/Nino_Unity/Assets/Nino/Serialization/Interfaces/INinoWrapper.cs b/Nino_Unity/Assets/Nino/Serialization/Interfaces/INinoWrapper.cs index c2aad16..e88bc93 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Interfaces/INinoWrapper.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Interfaces/INinoWrapper.cs @@ -2,13 +2,15 @@ namespace Nino.Serialization { public interface INinoWrapper { - void Serialize(T val, Writer writer); + void Serialize(T val, ref Writer writer); T Deserialize(Reader reader); + int GetSize(T val); } public interface INinoWrapper { - void Serialize(object val, Writer writer); + void Serialize(object val, ref Writer writer); object Deserialize(Reader reader); + int GetSize(object val); } } \ No newline at end of file diff --git a/Nino_Unity/Assets/Nino/Serialization/Reader.Generic.cs b/Nino_Unity/Assets/Nino/Serialization/Reader.Generic.cs index a45f605..fa1a1fc 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Reader.Generic.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Reader.Generic.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace Nino.Serialization { @@ -15,83 +16,16 @@ public unsafe partial class Reader /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public T ReadCommonVal() => - Deserializer.Deserialize(buffer.AsSpan(position, _length - position), this, _option, - false); - - /// - /// Decompress number for int32, int64, uint32, uint64 - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public T DecompressAndReadNumber() where T : unmanaged - { - T result = default; - DecompressAndReadNumber(ref result); - return result; - } - - /// - /// Decompress number for int32, int64, uint32, uint64 - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void DecompressAndReadNumber(ref T result) where T : unmanaged - { - if (EndOfReader) - { - result = default; - return; - } - - ref var type = ref GetCompressType(); - fixed (T* ptr = &result) - { - switch (type) - { - case CompressType.Byte: - Unsafe.As(ref result) = ReadByte(); - return; - case CompressType.SByte: - Unsafe.InitBlock(ptr, 255, (uint)sizeof(T)); - Unsafe.As(ref result) = ReadSByte(); - return; - case CompressType.Int16: - Unsafe.InitBlock(ptr, 255, (uint)sizeof(T)); - Unsafe.As(ref result) = ReadInt16(); - return; - case CompressType.UInt16: - Unsafe.As(ref result) = ReadUInt16(); - return; - case CompressType.Int32: - Unsafe.InitBlock(ptr, 255, (uint)sizeof(T)); - Unsafe.As(ref result) = ReadInt32(); - return; - case CompressType.UInt32: - Unsafe.As(ref result) = ReadUInt32(); - return; - case CompressType.Int64: - Unsafe.InitBlock(ptr, 255, (uint)sizeof(T)); - Unsafe.As(ref result) = ReadInt64(); - return; - case CompressType.UInt64: - Unsafe.As(ref result) = ReadUInt64(); - return; - default: - throw new InvalidOperationException("invalid compress type"); - } - } - } + Deserializer.Deserialize(buffer.AsSpan(position, _length - position), this, false); /// /// Compress and write enum /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public T DecompressAndReadEnum() + public T ReadEnum() { T val = default; - DecompressAndReadEnum(ref val); + ReadEnum(ref val); return val; } @@ -100,7 +34,7 @@ public T DecompressAndReadEnum() /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void DecompressAndReadEnum(ref T val) + public void ReadEnum(ref T val) { if (EndOfReader) return; @@ -118,18 +52,17 @@ public void DecompressAndReadEnum(ref T val) case TypeCode.UInt16: Unsafe.As(ref val) = ReadUInt16(); return; - //need to consider compress case TypeCode.Int32: - Unsafe.As(ref val) = DecompressAndReadNumber(); + Unsafe.As(ref val) = ReadInt32(); return; case TypeCode.UInt32: - Unsafe.As(ref val) = DecompressAndReadNumber(); + Unsafe.As(ref val) = ReadUInt32(); return; case TypeCode.Int64: - Unsafe.As(ref val) = DecompressAndReadNumber(); + Unsafe.As(ref val) = ReadInt64(); return; case TypeCode.UInt64: - Unsafe.As(ref val) = DecompressAndReadNumber(); + Unsafe.As(ref val) = ReadUInt64(); return; } } @@ -139,16 +72,16 @@ public void DecompressAndReadEnum(ref T val) /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - private T Read(int len) where T : unmanaged + public T Read(int len) where T : unmanaged { if (EndOfReader) { return default; } - var ptr = buffer.Data + position; + var ret = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T))); position += len; - return Unsafe.Read(ptr); + return ret; } /// @@ -166,7 +99,7 @@ public void Read(ref T val, int len) where T : unmanaged return; } - val = Unsafe.Read(buffer.Data + position); + val = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T))); position += len; } @@ -205,8 +138,7 @@ public T[] ReadArray() int i = 0; while (i < len) { - arr[i++] = (T)ReadCommonVal( - TypeModel.AllTypes.TryGetValue(ReadInt32(), out var type) ? type : typeof(T)); + arr[i++] = ReadCommonVal(); } return arr; @@ -228,8 +160,7 @@ public List ReadList() //read item while (len-- > 0) { - lst.Add((T)ReadCommonVal( - TypeModel.AllTypes.TryGetValue(ReadInt32(), out var type) ? type : typeof(T))); + lst.Add(ReadCommonVal()); } return lst; @@ -251,8 +182,7 @@ public HashSet ReadHashSet() //read item while (len-- > 0) { - lst.Add((T)ReadCommonVal( - TypeModel.AllTypes.TryGetValue(ReadInt32(), out var type) ? type : typeof(T))); + lst.Add(ReadCommonVal()); } return lst; @@ -274,8 +204,7 @@ public Queue ReadQueue() //read item while (len-- > 0) { - lst.Enqueue((T)ReadCommonVal( - TypeModel.AllTypes.TryGetValue(ReadInt32(), out var type) ? type : typeof(T))); + lst.Enqueue(ReadCommonVal()); } return lst; @@ -317,10 +246,8 @@ public Dictionary ReadDictionary() //read item while (len-- > 0) { - var key = (TKey)ReadCommonVal( - TypeModel.AllTypes.TryGetValue(ReadInt32(), out var type) ? type : typeof(TKey)); - var val = (TValue)ReadCommonVal( - TypeModel.AllTypes.TryGetValue(ReadInt32(), out type) ? type : typeof(TValue)); + var key = ReadCommonVal(); + var val = ReadCommonVal(); dic.Add(key, val); } diff --git a/Nino_Unity/Assets/Nino/Serialization/Reader.cs b/Nino_Unity/Assets/Nino/Serialization/Reader.cs index 41ea44e..5109e8b 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Reader.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Reader.cs @@ -3,7 +3,6 @@ using Nino.Shared.Mgr; using System.Collections; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; namespace Nino.Serialization { @@ -32,11 +31,6 @@ public unsafe partial class Reader /// private int _length; - /// - /// compress option - /// - private CompressOption _option; - /// /// End of Reader /// @@ -54,10 +48,9 @@ public Reader() /// /// /// - /// - public Reader(byte[] data, int outputLength, CompressOption option = CompressOption.Zlib) + public Reader(byte[] data, int outputLength) { - Init(data, outputLength, option); + Init(data, outputLength); } /// @@ -65,9 +58,8 @@ public Reader(byte[] data, int outputLength, CompressOption option = CompressOpt /// /// /// - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void Init(IntPtr data, int outputLength, CompressOption option) + private void Init(IntPtr data, int outputLength) { if (buffer == null) { @@ -85,11 +77,6 @@ private void Init(IntPtr data, int outputLength, CompressOption option) buffer.CopyFrom((byte*)data, 0, 0, outputLength); position = 0; _length = outputLength; - _option = option; - if (_option == CompressOption.Zlib) - { - Marshal.FreeHGlobal(data); - } } /// @@ -97,24 +84,12 @@ private void Init(IntPtr data, int outputLength, CompressOption option) /// /// /// - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Init(Span data, int outputLength, CompressOption compressOption) + public void Init(Span data, int outputLength) { - switch (compressOption) + fixed (byte* ptr = &data.GetPinnableReference()) { - case CompressOption.NoCompression: - fixed (byte* ptr = &data.GetPinnableReference()) - { - Init((IntPtr)ptr, outputLength, compressOption); - } - - break; - case CompressOption.Lz4: - throw new NotSupportedException("not support lz4 yet"); - case CompressOption.Zlib: - Init(CompressMgr.Decompress(data.ToArray(), out var length), length, compressOption); - break; + Init((IntPtr)ptr, outputLength); } } @@ -123,24 +98,12 @@ public void Init(Span data, int outputLength, CompressOption compressOptio /// /// /// - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Init(byte[] data, int outputLength, CompressOption compressOption) + public void Init(byte[] data, int outputLength) { - switch (compressOption) + fixed (byte* ptr = data) { - case CompressOption.NoCompression: - fixed (byte* ptr = data) - { - Init((IntPtr)ptr, outputLength, compressOption); - } - - break; - case CompressOption.Lz4: - throw new NotSupportedException("not support lz4 yet"); - case CompressOption.Zlib: - Init(CompressMgr.Decompress(data, out var length), length, compressOption); - break; + Init((IntPtr)ptr, outputLength); } } @@ -149,12 +112,7 @@ public void Init(byte[] data, int outputLength, CompressOption compressOption) /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int ReadLength() - { - if (EndOfReader) return default; - - return DecompressAndReadNumber(); - } + public int ReadLength() => ReadInt32(); /// /// Read primitive value from binary writer, DO NOT USE THIS FOR CUSTOM EXPORTER @@ -163,81 +121,7 @@ public int ReadLength() /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public object ReadCommonVal(Type type) => - Deserializer.Deserialize(type, ConstMgr.Null, ConstMgr.Null, this, _option, false); - - /// - /// Decompress number for int32, int64, uint32, uint64 - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Obsolete("use generic method instead")] - public ulong DecompressAndReadNumber() - { - if (EndOfReader) return default; - - ref var type = ref GetCompressType(); - switch (type) - { - case CompressType.Byte: - return ReadByte(); - case CompressType.SByte: - return (ulong)ReadSByte(); - case CompressType.Int16: - return (ulong)ReadInt16(); - case CompressType.UInt16: - return ReadUInt16(); - case CompressType.Int32: - return (ulong)ReadInt32(); - case CompressType.UInt32: - return ReadUInt32(); - case CompressType.Int64: - return (ulong)ReadInt64(); - case CompressType.UInt64: - return ReadUInt64(); - default: - throw new InvalidOperationException("invalid compress type"); - } - } - - /// - /// Compress and write enum - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ulong DecompressAndReadEnum(Type enumType) - { - if (EndOfReader) return default; - - switch (TypeModel.GetTypeCode(enumType)) - { - case TypeCode.Byte: - return ReadByte(); - case TypeCode.SByte: - return (ulong)ReadSByte(); - case TypeCode.Int16: - return (ulong)ReadInt16(); - case TypeCode.UInt16: - return ReadUInt16(); - //need to consider compress - case TypeCode.Int32: - return (ulong)DecompressAndReadNumber(); - case TypeCode.UInt32: - return DecompressAndReadNumber(); - case TypeCode.Int64: - return (ulong)DecompressAndReadNumber(); - case TypeCode.UInt64: - return DecompressAndReadNumber(); - } - - return 0; - } - - /// - /// Get CompressType - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private ref CompressType GetCompressType() => ref *(CompressType*)(&buffer.Data[position++]); + Deserializer.Deserialize(type, ConstMgr.Null, ConstMgr.Null, this, false); /// /// Read a byte @@ -302,7 +186,7 @@ public DateTime ReadDateTime() { if (EndOfReader) return default; - return DateTime.FromOADate(ReadDouble()); + return Read(ConstMgr.SizeOfLong); } /// @@ -397,7 +281,7 @@ public string ReadString() if (EndOfReader) return default; if (!ReadBool()) return null; - int len = DecompressAndReadNumber(); + int len = ReadInt32(); //empty string -> no gc if (len == 0) { @@ -410,6 +294,37 @@ public string ReadString() return new string(chars, 0, len / ConstMgr.SizeOfUShort); } + /// + /// Compress and write enum + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ulong ReadEnum(Type enumType) + { + if (EndOfReader) return default; + + switch (TypeModel.GetTypeCode(enumType)) + { + case TypeCode.Byte: + return ReadByte(); + case TypeCode.SByte: + return (ulong)ReadSByte(); + case TypeCode.Int16: + return (ulong)ReadInt16(); + case TypeCode.UInt16: + return ReadUInt16(); + case TypeCode.Int32: + return (ulong)ReadInt32(); + case TypeCode.UInt32: + return ReadUInt32(); + case TypeCode.Int64: + return (ulong)ReadInt64(); + case TypeCode.UInt64: + return ReadUInt64(); + } + + return 0; + } + /// /// Read Array /// @@ -444,9 +359,7 @@ public Array ReadArray(Type type) int i = 0; while (i < len) { - var obj = Deserializer.Deserialize( - TypeModel.AllTypes.TryGetValue(ReadInt32(), out type) ? type : elemType, ConstMgr.Null, - ConstMgr.Null, this, _option, false); + var obj = ReadCommonVal(elemType); #if ILRuntime arr.SetValue(ILRuntime.CLR.Utils.Extensions.CheckCLRTypes(elemType, obj), i++); continue; @@ -499,9 +412,7 @@ public IList ReadList(Type type) int i = 0; while (i++ < len) { - var obj = Deserializer.Deserialize( - TypeModel.AllTypes.TryGetValue(ReadInt32(), out type) ? type : elemType, ConstMgr.Null, - ConstMgr.Null, this, _option, false); + var obj = ReadCommonVal(elemType); #if ILRuntime arr?.Add(ILRuntime.CLR.Utils.Extensions.CheckCLRTypes(elemType, obj)); continue; @@ -561,13 +472,9 @@ public IDictionary ReadDictionary(Type type) while (i++ < len) { //read key - var key = Deserializer.Deserialize( - TypeModel.AllTypes.TryGetValue(ReadInt32(), out type) ? type : keyType, ConstMgr.Null, - ConstMgr.Null, this, _option, false); + var key = ReadCommonVal(keyType); //read value - var val = Deserializer.Deserialize( - TypeModel.AllTypes.TryGetValue(ReadInt32(), out type) ? type : valueType, ConstMgr.Null, - ConstMgr.Null, this, _option, false); + var val = ReadCommonVal(valueType); //add #if ILRuntime diff --git a/Nino_Unity/Assets/Nino/Serialization/Serializer.Generic.cs b/Nino_Unity/Assets/Nino/Serialization/Serializer.Generic.cs index 2594e2c..7c60631 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Serializer.Generic.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Serializer.Generic.cs @@ -1,4 +1,5 @@ -using Nino.Shared.IO; +using System; +using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; @@ -6,30 +7,181 @@ namespace Nino.Serialization { public static partial class Serializer { + /// + /// Attempt to serialize hard-coded types + code gen types + custom delegate types + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TrySerializeWrapperType(Type type, ref T value, ref Writer writer) + { + //basic type + if (!WrapperManifest.TryGetWrapper(type, out var wrapper)) + { + return false; + } + + if (wrapper is NinoWrapperBase @base) + { + @base.Serialize(value, ref writer); + } + else + { + wrapper.Serialize(value, ref writer); + } + + return true; + } + + /// + /// Attempt to serialize enum + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TrySerializeEnumType(Type type, ref T value, ref Writer writer) + { + //enum + if (!TypeModel.IsEnum(type)) + { + return false; + } + + writer.WriteEnum(value); + return true; + } + + /// + /// Attempt to serialize code gen type (first time only) + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TrySerializeCodeGenType(Type type, ref T value, ref Writer writer) + { + //code generated type + if (!TypeModel.TryGetWrapper(type, out var wrapper)) + { + return false; + } + + //add wrapper + WrapperManifest.AddWrapper(type, wrapper); + + //start serialize + if (wrapper is NinoWrapperBase @base) + { + @base.Serialize(value, ref writer); + } + else + { + wrapper.Serialize(value, ref writer); + } + + return true; + } + + /// + /// Attempt to serialize array + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TrySerializeArray(ref T value, ref Writer writer) + { + //array + if (!(value is Array arr)) + { + return false; + } + + writer.Write(arr); + return true; + } + + /// + /// Attempt to serialize list (boxed) + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TrySerializeList(ref T value, ref Writer writer) + { + if (!(value is IList lst)) + { + return false; + } + + writer.Write(lst); + return true; + } + + /// + /// Attempt to serialize dict + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TrySerializeDict(ref T value, ref Writer writer) + { + if (!(value is IDictionary dict)) + { + return false; + } + + writer.Write(dict); + return true; + } + /// /// Serialize an array of NinoSerialize object /// /// /// - /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte[] Serialize(T[] val, CompressOption option = CompressOption.Zlib) + public static byte[] Serialize(T[] val) { - Writer writer = ObjectPool.Request(); - writer.Init(option); + int length = GetSize(in val); + if (length == 0) + { + return Array.Empty(); + } + + byte[] ret = new byte[length]; + if (val == null) + { + return ret; + } + + Writer writer = new Writer(ret.AsSpan(), 0); /* * HARD-CODED SERIALIZATION */ - if (TrySerializeWrapperType(typeof(T[]), val, writer, false, true, out var ret)) + if (TrySerializeWrapperType(typeof(T[]), ref val, ref writer)) { return ret; } //attempt to serialize using generic method writer.Write(val); - return Return(true, writer); + return ret; } /// @@ -37,17 +189,27 @@ public static byte[] Serialize(T[] val, CompressOption option = CompressOptio /// /// /// - /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte[] Serialize(T? val, CompressOption option = CompressOption.Zlib) where T : struct + public static byte[] Serialize(T? val) where T : struct { - Writer writer = ObjectPool.Request(); - writer.Init(option); + int length = GetSize(in val); + if (length == 0) + { + return Array.Empty(); + } + + byte[] ret = new byte[length]; + if (val == null) + { + return ret; + } + + Writer writer = new Writer(ret.AsSpan(), 0); //attempt to serialize using generic method writer.Write(val); - return Return(true, writer); + return ret; } /// @@ -55,25 +217,35 @@ public static byte[] Serialize(T? val, CompressOption option = CompressOption /// /// /// - /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte[] Serialize(List val, CompressOption option = CompressOption.Zlib) + public static byte[] Serialize(List val) { - Writer writer = ObjectPool.Request(); - writer.Init(option); + int length = GetSize(in val); + if (length == 0) + { + return Array.Empty(); + } + + byte[] ret = new byte[length]; + if (val == null) + { + return ret; + } + + Writer writer = new Writer(ret.AsSpan(), 0); /* * HARD-CODED SERIALIZATION */ - if (TrySerializeWrapperType(typeof(List), val, writer, false, true, out var ret)) + if (TrySerializeWrapperType(typeof(List), ref val, ref writer)) { return ret; } //attempt to serialize using generic method writer.Write(val); - return Return(true, writer); + return ret; } /// @@ -81,25 +253,35 @@ public static byte[] Serialize(List val, CompressOption option = CompressO /// /// /// - /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte[] Serialize(HashSet val, CompressOption option = CompressOption.Zlib) + public static byte[] Serialize(HashSet val) { - Writer writer = ObjectPool.Request(); - writer.Init(option); + int length = GetSize(in val); + if (length == 0) + { + return Array.Empty(); + } + + byte[] ret = new byte[length]; + if (val == null) + { + return ret; + } + + Writer writer = new Writer(ret.AsSpan(), 0); /* * HARD-CODED SERIALIZATION */ - if (TrySerializeWrapperType(typeof(HashSet), val, writer, false, true, out var ret)) + if (TrySerializeWrapperType(typeof(HashSet), ref val, ref writer)) { return ret; } //attempt to serialize using generic method writer.Write(val); - return Return(true, writer); + return ret; } /// @@ -107,25 +289,35 @@ public static byte[] Serialize(HashSet val, CompressOption option = Compre /// /// /// - /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte[] Serialize(Queue val, CompressOption option = CompressOption.Zlib) + public static byte[] Serialize(Queue val) { - Writer writer = ObjectPool.Request(); - writer.Init(option); + int length = GetSize(in val); + if (length == 0) + { + return Array.Empty(); + } + + byte[] ret = new byte[length]; + if (val == null) + { + return ret; + } + + Writer writer = new Writer(ret.AsSpan(), 0); /* * HARD-CODED SERIALIZATION */ - if (TrySerializeWrapperType(typeof(Queue), val, writer, false, true, out var ret)) + if (TrySerializeWrapperType(typeof(Queue), ref val, ref writer)) { return ret; } //attempt to serialize using generic method writer.Write(val); - return Return(true, writer); + return ret; } /// @@ -133,25 +325,35 @@ public static byte[] Serialize(Queue val, CompressOption option = Compress /// /// /// - /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte[] Serialize(Stack val, CompressOption option = CompressOption.Zlib) + public static byte[] Serialize(Stack val) { - Writer writer = ObjectPool.Request(); - writer.Init(option); + int length = GetSize(in val); + if (length == 0) + { + return Array.Empty(); + } + + byte[] ret = new byte[length]; + if (val == null) + { + return ret; + } + + Writer writer = new Writer(ret.AsSpan(), 0); /* * HARD-CODED SERIALIZATION */ - if (TrySerializeWrapperType(typeof(Stack), val, writer, false, true, out var ret)) + if (TrySerializeWrapperType(typeof(Stack), ref val, ref writer)) { return ret; } //attempt to serialize using generic method writer.Write(val); - return Return(true, writer); + return ret; } /// @@ -160,26 +362,35 @@ public static byte[] Serialize(Stack val, CompressOption option = Compress /// /// /// - /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte[] Serialize(Dictionary val, - CompressOption option = CompressOption.Zlib) + public static byte[] Serialize(Dictionary val) { - Writer writer = ObjectPool.Request(); - writer.Init(option); + int length = GetSize(in val); + if (length == 0) + { + return Array.Empty(); + } + + byte[] ret = new byte[length]; + if (val == null) + { + return ret; + } + + Writer writer = new Writer(ret.AsSpan(), 0); /* * HARD-CODED SERIALIZATION */ - if (TrySerializeWrapperType(typeof(Dictionary), val, writer, false, true, out var ret)) + if (TrySerializeWrapperType(typeof(Dictionary), ref val, ref writer)) { return ret; } //attempt to serialize using generic method writer.Write(val); - return Return(true, writer); + return ret; } } } \ No newline at end of file diff --git a/Nino_Unity/Assets/Nino/Serialization/Serializer.Helper.cs b/Nino_Unity/Assets/Nino/Serialization/Serializer.Helper.cs new file mode 100644 index 0000000..0205c69 --- /dev/null +++ b/Nino_Unity/Assets/Nino/Serialization/Serializer.Helper.cs @@ -0,0 +1,346 @@ +// Serializer.Helper.cs +// +// Author: +// JasonXuDeveloper(傑) +// +// Copyright (c) 2023 Nino + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using Nino.Shared.Mgr; + +namespace Nino.Serialization +{ + public static partial class Serializer + { + private static readonly Dictionary FixedSizeCache = new Dictionary() + { + { typeof(bool), 1 }, + { typeof(byte), 1 }, + { typeof(sbyte), 1 }, + { typeof(char), 2 }, + { typeof(short), 2 }, + { typeof(ushort), 2 }, + { typeof(int), 4 }, + { typeof(uint), 4 }, + { typeof(long), 8 }, + { typeof(ulong), 8 }, + { typeof(float), 4 }, + { typeof(double), 8 }, + { typeof(decimal), 16 }, + { typeof(DateTime), 8 }, + { typeof(TimeSpan), 8 }, + { typeof(Guid), 16 }, + { typeof(IntPtr), 8 }, + { typeof(UIntPtr), 8 }, + }; + + public static int GetFixedSize() where T : unmanaged + { + if (FixedSizeCache.TryGetValue(typeof(T), out var size)) + { + return size; + } + + return -1; + } + + public static void SetFixedSize(int size) where T : unmanaged + { + FixedSizeCache[typeof(T)] = size; + } + + public static int GetSize(in T val = default, Dictionary members = null) + { + var type = typeof(T); + int size = 0; + if (TypeModel.IsEnum(type)) type = type.GetEnumUnderlyingType(); + + //nullable + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) + { + type = type.GetGenericArguments()[0]; + size += 1; + } + + if (val == null) return 1; + + if (FixedSizeCache.TryGetValue(type, out var size2)) + { + return size + size2; + } + + if (!WrapperManifest.TryGetWrapper(type, out var wrapper)) + { + //code generated type + if (TypeModel.TryGetWrapper(type, out wrapper)) + { + //add wrapper + WrapperManifest.AddWrapper(type, wrapper); + } + } + + if (wrapper != null) + { + if (wrapper is NinoWrapperBase @base) + { + return size + @base.GetSize(val); + } + + return size + wrapper.GetSize(val); + } + + return GetSize(type, val, members); + } + + public static int GetSize(Type type, object obj, Dictionary members = null) + { + if (TypeModel.IsEnum(type)) type = type.GetEnumUnderlyingType(); + + int size = 0; + bool isGeneric = type.IsGenericType; + Type genericTypeDef = null; + Type[] genericArgs = null; + if (isGeneric) + { + genericTypeDef = type.GetGenericTypeDefinition(); + genericArgs = type.GetGenericArguments(); + } + + //nullable + if (genericTypeDef != null && genericTypeDef == typeof(Nullable<>)) + { + type = genericArgs[0]; + size += 1; + } + + if (obj == null) return 1; + + if (FixedSizeCache.TryGetValue(type, out var size2)) + { + return size + size2; + } + + if (!WrapperManifest.TryGetWrapper(type, out var wrapper)) + { + //code generated type + if (TypeModel.TryGetWrapper(type, out wrapper)) + { + //add wrapper + WrapperManifest.AddWrapper(type, wrapper); + } + } + + if (wrapper != null) + { + return size + wrapper.GetSize(obj); + } + + size = 1; //null indicator + + if (type == ConstMgr.ObjectType) + { + type = obj.GetType(); + } + + if (type.IsArray) + { + var elementType = type.GetElementType(); + var array = obj as Array; + if (array == null) + { + return size; + } + + size += 4; //length + if (array.Length == 0) return size; + + if (elementType != null && FixedSizeCache.TryGetValue(elementType, out var eleSize)) + { + size += eleSize * array.Length; + return size; + } + + foreach (var item in array) + { + size += GetSize(elementType, item); + } + + return size; + } + + if (isGeneric && genericTypeDef != null) + { + switch (genericTypeDef) + { + case var _ when genericTypeDef.GetInterface(nameof(IList)) != null: + var lstElemType = genericArgs[0]; + var lst = obj as ICollection; + if (lst == null) + { + return size; + } + + size += 4; //length + if (lst.Count == 0) return size; + + if (FixedSizeCache.TryGetValue(lstElemType, out var lstEleSize)) + { + size += lstEleSize * lst.Count; + return size; + } + + foreach (var item in lst) + { + size += GetSize(lstElemType, item); + } + + return size; + case var _ when genericTypeDef.GetInterface(nameof(IDictionary)) != null: + var keyType = genericArgs[0]; + var valueType = genericArgs[1]; + var dict = obj as IDictionary; + if (dict == null) + { + return size; + } + + size += 4; //length + if (dict.Count == 0) return size; + + bool hasKeySize = FixedSizeCache.TryGetValue(keyType, out var keySize); + bool hasValueSize = FixedSizeCache.TryGetValue(valueType, out var valueSize); + + if (hasKeySize && hasValueSize) + { + size += (keySize + valueSize) * dict.Count; + return size; + } + + if (hasKeySize) + { + size += keySize * dict.Count; + foreach (var item in dict.Values) + { + size += GetSize(valueType, item); + } + + return size; + } + + if (hasValueSize) + { + size += valueSize * dict.Count; + foreach (var item in dict.Keys) + { + size += GetSize(keyType, item); + } + + return size; + } + + foreach (DictionaryEntry item in dict) + { + size += GetSize(keyType, item.Key); + size += GetSize(valueType, item.Value); + } + + return size; + case var _ when genericTypeDef.GetInterface(nameof(ICollection)) != null: + var elementType2 = genericArgs[0]; + var collection = obj as ICollection; + if (collection == null) + { + return size; + } + + size += 4; //length + if (collection.Count == 0) return size; + + if (FixedSizeCache.TryGetValue(elementType2, out var eleSize)) + { + size += eleSize * collection.Count; + return size; + } + + foreach (var item in collection) + { + size += GetSize(elementType2, item); + } + + return size; + case var _ when genericTypeDef.GetInterface(nameof(IEnumerable)) != null: + var elementType = genericArgs[0]; + var enumerable = obj as IEnumerable; + if (enumerable == null) + { + return size; + } + + size += 4; //length + + var enumerator = enumerable.GetEnumerator(); + if (!enumerator.MoveNext()) return size; + do + { + size += GetSize(elementType, enumerator.Current); + } while (enumerator.MoveNext()); + + return size; + } + } + + //Nino serializable type + TypeModel.TryGetModel(type, out var model); + + //invalid model + if (model != null && !model.Valid) + { + throw new InvalidOperationException($"Invalid model for type {type}"); + } + + //generate model + if (model == null) + { + model = TypeModel.CreateModel(type); + } + + var isFixed = true; + foreach (var member in model.Members) + { + Type memberType; + object memberObj; + switch (member) + { + case FieldInfo fi: + memberType = fi.FieldType; + memberObj = fi.GetValue(obj); + break; + case PropertyInfo pi: + memberType = pi.PropertyType; + memberObj = pi.GetValue(obj); + break; + default: + throw new Exception("Invalid member type"); + } + + if (members != null) + { + members[member] = memberObj; + } + + size += GetSize(memberType, memberObj); + if (!FixedSizeCache.ContainsKey(memberType)) + { + isFixed = false; + } + } + + if (isFixed) + FixedSizeCache[type] = size; + return size; + } + } +} \ No newline at end of file diff --git a/Nino_Unity/Assets/Nino/Serialization/Serializer.cs b/Nino_Unity/Assets/Nino/Serialization/Serializer.cs index e6e93cc..8b6b4a2 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Serializer.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Serializer.cs @@ -1,106 +1,103 @@ using System; -using Nino.Shared.IO; -using Nino.Shared.Mgr; +using System.Collections.Generic; using System.Reflection; -using System.Collections; -using System.Runtime.InteropServices; using System.Runtime.CompilerServices; +using Nino.Shared.IO; namespace Nino.Serialization { public static partial class Serializer { /// - /// Custom importer delegate that writes object to writer - /// - internal delegate void ImporterDelegate(T val, Writer writer); - - /// - /// Add custom importer of all type T objects + /// Serialize a NinoSerialize object /// - /// /// - public static void AddCustomImporter(Action action) + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] Serialize(in T val) { - var type = typeof(T); - if (WrapperManifest.TryGetWrapper(type, out var wrapper)) + Dictionary fields = ObjectPool>.Request(); + fields.Clear(); + int length = GetSize(in val, fields); + if (length == 0) { - ((GenericWrapper)wrapper).Importer = action.Invoke; - return; + return Array.Empty(); } - GenericWrapper genericWrapper = new GenericWrapper - { - Importer = action.Invoke - }; - WrapperManifest.AddWrapper(type, genericWrapper); + byte[] ret = new byte[length]; + Serialize(ret.AsSpan(), in val, fields); + ObjectPool>.Return(fields); + return ret; } /// /// Serialize a NinoSerialize object /// /// + /// /// - /// - /// + /// + /// actual written size [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte[] Serialize(T val, CompressOption option = CompressOption.Zlib) + public static int Serialize(Span buffer, in T val, Dictionary fields = null) { - Writer writer = ObjectPool.Request(); - writer.Init(option); - return Serialize(typeof(T), val, writer, option); + if (val == null) + { + buffer[0] = 0; + return 1; + } + + return Serialize(typeof(T), val, fields, buffer, 0); } /// /// Serialize a NinoSerialize object /// /// - /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte[] Serialize(object val, CompressOption option = CompressOption.Zlib) + public static byte[] Serialize(object val) { - Writer writer = ObjectPool.Request(); - writer.Init(option); - return Serialize(val is null ? typeof(void) : val.GetType(), val, writer, option); + Dictionary fields = ObjectPool>.Request(); + fields.Clear(); + int length = GetSize(in val, fields); + if (length == 0) + { + return Array.Empty(); + } + + byte[] ret = new byte[length]; + if (val == null) + { + ObjectPool>.Return(fields); + return ret; + } + Serialize(val.GetType(), val, fields, ret.AsSpan(), 0); + ObjectPool>.Return(fields); + return ret; } /// /// Serialize a NinoSerialize object /// - /// - /// - /// - /// - /// + /// + /// /// - /// - /// - // ReSharper disable CognitiveComplexity - internal static byte[] Serialize(Type type, T value, Writer writer, - CompressOption option = CompressOption.Zlib, [MarshalAs(UnmanagedType.U1)] bool returnValue = true) - // ReSharper restore CognitiveComplexity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int Serialize(Span buffer, object val) { - bool boxed = false; - Type tType = typeof(T); - if (type != tType || tType == ConstMgr.ObjectType) + if (val == null) { - if (type != ConstMgr.ObjectType) - { - boxed = true; - } - else - { - if (value == null) - { - throw new InvalidOperationException("Failed to retrieve unbox type"); - } - - type = value.GetType(); - boxed = true; - } + buffer[0] = 0; + return 1; } + return Serialize(val.GetType(), val, null, buffer, 0); + } + + internal static int Serialize(Type type, T value, Dictionary fields ,Span buffer, int pos) + { //ILRuntime #if ILRuntime if(value is ILRuntime.Runtime.Intepreter.ILTypeInstance ins) @@ -111,61 +108,57 @@ internal static byte[] Serialize(Type type, T value, Writer writer, type = type.ResolveRealType(); #endif - if (writer == null) - { - writer = ObjectPool.Request(); - } + Writer writer = new Writer(buffer, pos); - if (returnValue) + //null check + if (value == null) { - writer.Init(TypeModel.IsNonCompressibleType(type) ? CompressOption.NoCompression : option); + writer.Write(false); // false -> is null + return writer.Position; } /* * HARD-CODED SERIALIZATION */ - if (TrySerializeWrapperType(type, value, writer, boxed, returnValue, out var ret)) + if (TrySerializeWrapperType(type, ref value, ref writer)) { - return ret; + return writer.Position; } - if (TrySerializeEnumType(type, value, writer, returnValue, out ret)) + if (TrySerializeEnumType(type, ref value, ref writer)) { - return ret; + return writer.Position; } - if (TrySerializeCodeGenType(type, value, writer, boxed, returnValue, out ret)) + if (TrySerializeCodeGenType(type, ref value, ref writer)) { - return ret; + return writer.Position; } - if (TrySerializeArray(value, writer, returnValue, out ret)) + if (TrySerializeArray(ref value, ref writer)) { - return ret; + return writer.Position; } //generic if (type.IsGenericType) { - if (TrySerializeList(value, writer, returnValue, out ret)) + if (TrySerializeList(ref value, ref writer)) { - return ret; + return writer.Position; } - if (TrySerializeDict(value, writer, returnValue, out ret)) + if (TrySerializeDict(ref value, ref writer)) { - return ret; + return writer.Position; } } /* * CUSTOM STRUCT/CLASS SERIALIZATION */ - if (WriteNullCheck(value, writer, returnValue, out ret)) - { - return ret; - } + writer.Write(true); //true -> not null //Get Attribute that indicates a class/struct to be serialized TypeModel.TryGetModel(type, out var model); @@ -173,8 +166,7 @@ internal static byte[] Serialize(Type type, T value, Writer writer, //invalid model if (model != null && !model.Valid) { - ObjectPool.Return(writer); - return ConstMgr.Null; + return 0; } //generate model @@ -183,13 +175,6 @@ internal static byte[] Serialize(Type type, T value, Writer writer, model = TypeModel.CreateModel(type); } - //only include all model need this - if (model.IncludeAll) - { - //write len - writer.CompressAndWrite(model.Members.Count); - } - //serialize all recorded members foreach (var member in model.Members) { @@ -198,247 +183,26 @@ internal static byte[] Serialize(Type type, T value, Writer writer, { case FieldInfo fo: type = fo.FieldType; - obj = fo.GetValue(value); + if(fields == null || !fields.TryGetValue(fo, out obj)) + { + obj = fo.GetValue(value); + } break; case PropertyInfo po: type = po.PropertyType; - obj = po.GetValue(value); + if (fields == null || !fields.TryGetValue(po, out obj)) + { + obj = po.GetValue(value); + } break; default: - return null; + return writer.Position; } - //only include all model need this - if (model.IncludeAll) - { - writer.Write(member.Name); - writer.Write(type.AssemblyQualifiedName); - } - - Serialize(type, obj, writer, option, false); - } - - return Return(returnValue, writer); - } - - /// - /// Attempt to serialize hard-coded types + code gen types + custom delegate types - /// - /// - /// - /// - /// - /// - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TrySerializeWrapperType(Type type, T value, Writer writer, - [MarshalAs(UnmanagedType.U1)] bool boxed, [MarshalAs(UnmanagedType.U1)] bool returnValue, - out byte[] ret) - { - //basic type - if (!WrapperManifest.TryGetWrapper(type, out var wrapper)) - { - ret = ConstMgr.Null; - return false; - } - - if (boxed) - { - wrapper.Serialize(value, writer); - } - else - { - ((NinoWrapperBase)wrapper).Serialize(value, writer); - } - - ret = Return(returnValue, writer); - return true; - } - - /// - /// Attempt to serialize enum - /// - /// - /// - /// - /// - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TrySerializeEnumType(Type type, T value, Writer writer, - [MarshalAs(UnmanagedType.U1)] bool returnValue, out byte[] ret) - { - //enum - if (!TypeModel.IsEnum(type)) - { - ret = ConstMgr.Null; - return false; - } - - writer.CompressAndWriteEnum(value); - ret = Return(returnValue, writer); - return true; - } - - /// - /// Attempt to serialize code gen type (first time only) - /// - /// - /// - /// - /// - /// - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TrySerializeCodeGenType(Type type, T value, Writer writer, - [MarshalAs(UnmanagedType.U1)] bool boxed, [MarshalAs(UnmanagedType.U1)] bool returnValue, - out byte[] ret) - { - //code generated type - if (!TypeModel.TryGetWrapper(type, out var wrapper)) - { - ret = ConstMgr.Null; - return false; - } - - //add wrapper - WrapperManifest.AddWrapper(type, wrapper); - - //start serialize - if (boxed) - { - wrapper.Serialize(value, writer); - } - else - { - ((NinoWrapperBase)wrapper).Serialize(value, writer); - } - - ret = Return(returnValue, writer); - return true; - } - - /// - /// Attempt to serialize array - /// - /// - /// - /// - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TrySerializeArray(T value, Writer writer, - [MarshalAs(UnmanagedType.U1)] bool returnValue, out byte[] ret) - { - //array - if (!(value is Array arr)) - { - ret = ConstMgr.Null; - return false; - } - - writer.Write(arr); - ret = Return(returnValue, writer); - return true; - } - - /// - /// Attempt to serialize list (boxed) - /// - /// - /// - /// - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TrySerializeList(T value, Writer writer, - [MarshalAs(UnmanagedType.U1)] bool returnValue, out byte[] ret) - { - if (!(value is IList lst)) - { - ret = ConstMgr.Null; - return false; - } - - writer.Write(lst); - ret = Return(returnValue, writer); - return true; - } - - /// - /// Attempt to serialize dict - /// - /// - /// - /// - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TrySerializeDict(T value, Writer writer, - [MarshalAs(UnmanagedType.U1)] bool returnValue, out byte[] ret) - { - if (!(value is IDictionary dict)) - { - ret = ConstMgr.Null; - return false; + writer.Position = Serialize(type, obj, null, buffer, writer.Position); } - writer.Write(dict); - ret = Return(returnValue, writer); - return true; - } - - /// - /// Check for null - /// - /// - /// - /// - /// - /// - /// true when null - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool WriteNullCheck(T value, Writer writer, - [MarshalAs(UnmanagedType.U1)] bool returnValue, out byte[] ret) - { - //null check - if (value == null) - { - writer.Write(false); // if null -> write false - ret = Return(returnValue, writer); - return true; - } - - writer.Write(true); // if not null -> write true - ret = ConstMgr.Null; - return false; - } - - /// - /// Get return value - /// - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static byte[] Return([MarshalAs(UnmanagedType.U1)] bool returnValue, Writer writer) - { - byte[] ret = ConstMgr.Null; - if (returnValue) - { - ret = writer.ToBytes(); - ObjectPool.Return(writer); - } - - return ret; + return writer.Position; } } } \ No newline at end of file diff --git a/Nino_Unity/Assets/Nino/Serialization/TypeModel.cs b/Nino_Unity/Assets/Nino/Serialization/TypeModel.cs index 748def4..ffa16c7 100644 --- a/Nino_Unity/Assets/Nino/Serialization/TypeModel.cs +++ b/Nino_Unity/Assets/Nino/Serialization/TypeModel.cs @@ -3,6 +3,7 @@ using Nino.Shared.Util; using System.Reflection; using System.Collections.Generic; +using System.Runtime.CompilerServices; using System.Threading; using Nino.Shared.IO; @@ -35,24 +36,6 @@ internal class TypeModel /// private static readonly Dictionary TypeModels = new Dictionary(10); - /// - /// Cached Models - /// - internal static Dictionary AllTypes = new Dictionary(100); - - static TypeModel() - { - var assemblies = AppDomain.CurrentDomain.GetAssemblies(); - foreach (var assembly in assemblies) - { - var types = assembly.GetTypes(); - foreach (var type in types) - { - AllTypes[type.GetHashCode()] = type; - } - } - } - /// /// Cached Models /// @@ -98,43 +81,12 @@ static TypeModel() { typeof(DateTime).GetTypeHashCode(), null }, }; - /// - /// No compression types - /// - private static readonly HashSet NoCompressionTypes = new HashSet() - { - typeof(int).GetTypeHashCode(), - typeof(uint).GetTypeHashCode(), - typeof(long).GetTypeHashCode(), - typeof(ulong).GetTypeHashCode(), - typeof(byte).GetTypeHashCode(), - typeof(sbyte).GetTypeHashCode(), - typeof(short).GetTypeHashCode(), - typeof(ushort).GetTypeHashCode(), - typeof(bool).GetTypeHashCode(), - typeof(char).GetTypeHashCode(), - typeof(decimal).GetTypeHashCode(), - typeof(double).GetTypeHashCode(), - typeof(float).GetTypeHashCode(), - typeof(DateTime).GetTypeHashCode(), - }; - /// /// Cached Models /// private static readonly ConcurrentDictionary IsEnumTypeCache = new ConcurrentDictionary(3, 30); - /// - /// Whether or not the type is a non compress type - /// - /// - /// - internal static bool IsNonCompressibleType(Type type) - { - return NoCompressionTypes.Contains(type.GetTypeHashCode()) || IsEnum(type); - } - /// /// Get a type code /// @@ -157,12 +109,42 @@ internal static TypeCode GetTypeCode(Type type) TypeCodes[hash] = ret = Type.GetTypeCode(type); return ret; } + + private static readonly ConcurrentDictionary IsManagedTypeCache = + new ConcurrentDictionary(); + + public static bool IsUnmanaged(Type type) + { + if (type.IsPrimitive || IsEnum(type)) return true; + if (!type.IsValueType) return false; + // check if we already know the answer + if (!IsManagedTypeCache.TryGetValue(type, out var ret)) + { + ret = true; + // otherwise check recursively + var fields = type + .GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); + foreach (var field in fields) + { + if (!IsUnmanaged(field.FieldType)) + { + ret = false; + break; + } + } + + IsManagedTypeCache[type] = ret; + } + + return ret; + } /// /// Get whether or not a type is enum /// /// /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool IsEnum(Type type) { if (IsEnumTypeCache.TryGetValue(type, out var ret)) return ret; @@ -176,6 +158,7 @@ internal static bool IsEnum(Type type) /// /// /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool TryGetWrapper(Type type, out INinoWrapper helper) { var hash = type.GetTypeHashCode(); @@ -281,7 +264,18 @@ internal static TypeModel CreateModel(Type type) //skip nino ignore var ig = p.GetCustomAttributes(NinoIgnoreType, true); if (ig.Length > 0) continue; - + } + + //has to have getter and setter + if (!(p.CanRead && p.CanWrite)) + { + if (model.IncludeAll) continue; + throw new InvalidOperationException( + $"Cannot read or write property {p.Name} in {type.FullName}, cannot Serialize or Deserialize this property"); + } + + if (model.IncludeAll) + { index++; } else @@ -291,14 +285,7 @@ internal static TypeModel CreateModel(Type type) if (ns.Length != 1) continue; index = ((NinoMemberAttribute)ns[0]).Index; } - - //has to have getter and setter - if (!(p.CanRead && p.CanWrite)) - { - throw new InvalidOperationException( - $"Cannot read or write property {p.Name} in {type.FullName}, cannot Serialize or Deserialize this property"); - } - + //record property dict.Add(index, p); } @@ -327,5 +314,4 @@ internal static TypeModel CreateModel(Type type) return model; } } -} - +} \ No newline at end of file diff --git a/Nino_Unity/Assets/Nino/Serialization/Wrappers/Common/NinoWrapperBase.cs b/Nino_Unity/Assets/Nino/Serialization/Wrappers/Common/NinoWrapperBase.cs index 35b40aa..897f114 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Wrappers/Common/NinoWrapperBase.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Wrappers/Common/NinoWrapperBase.cs @@ -1,18 +1,32 @@ +using System.Runtime.CompilerServices; + namespace Nino.Serialization { public abstract class NinoWrapperBase : INinoWrapper, INinoWrapper { - public abstract void Serialize(T val, Writer writer); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public abstract void Serialize(T val, ref Writer writer); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public abstract T Deserialize(Reader reader); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public abstract int GetSize(T val); - public void Serialize(object val, Writer writer) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Serialize(object val, ref Writer writer) { - Serialize((T)val, writer); + Serialize((T)val, ref writer); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] object INinoWrapper.Deserialize(Reader reader) { return Deserialize(reader); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int GetSize(object val) + { + return GetSize((T)val); + } } } \ No newline at end of file diff --git a/Nino_Unity/Assets/Nino/Serialization/Wrappers/Primitives/Basics.cs b/Nino_Unity/Assets/Nino/Serialization/Wrappers/Primitives/Basics.cs index 81cbddc..66c58ed 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Wrappers/Primitives/Basics.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Wrappers/Primitives/Basics.cs @@ -5,7 +5,7 @@ namespace Nino.Serialization { internal class BoolWrapper : NinoWrapperBase { - public override void Serialize(bool val, Writer writer) + public override void Serialize(bool val, ref Writer writer) { writer.Write(val); } @@ -14,27 +14,18 @@ public override bool Deserialize(Reader reader) { return reader.ReadBool(); } + + public override int GetSize(bool val) + { + return 1; + } } internal class BoolArrWrapper : NinoWrapperBase { - public override unsafe void Serialize(bool[] val, Writer writer) + public override void Serialize(bool[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - int len = val.Length; - writer.CompressAndWrite(ref len); - if (len > 0) - { - fixed (bool* ptr = val) - { - writer.Write((byte*)ptr, ref len); - } - } + writer.Write(val.AsSpan()); } public override unsafe bool[] Deserialize(Reader reader) @@ -57,19 +48,26 @@ public override unsafe bool[] Deserialize(Reader reader) return arr; } + + public override int GetSize(bool[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length; + } } internal class BoolListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { writer.Write(v); @@ -87,13 +85,20 @@ public override List Deserialize(Reader reader) { arr.Add(reader.ReadBool()); } + return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + return 1 + 4 + val.Count; + } } internal class CharWrapper : NinoWrapperBase { - public override void Serialize(char val, Writer writer) + public override void Serialize(char val, ref Writer writer) { writer.Write(val); } @@ -102,28 +107,18 @@ public override char Deserialize(Reader reader) { return reader.ReadChar(); } + + public override int GetSize(char val) + { + return 2; + } } internal class CharArrWrapper : NinoWrapperBase { - public override unsafe void Serialize(char[] val, Writer writer) + public override void Serialize(char[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - int len = val.Length; - writer.CompressAndWrite(ref len); - if (len > 0) - { - len *= 2; - fixed (char* ptr = val) - { - writer.Write((byte*)ptr, ref len); - } - } + writer.Write(val.AsSpan()); } public override unsafe char[] Deserialize(Reader reader) @@ -143,21 +138,29 @@ public override unsafe char[] Deserialize(Reader reader) reader.ReadToBuffer((byte*)arrPtr, len * 2); } } + return arr; } + + public override int GetSize(char[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length * 2; + } } internal class CharListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { writer.Write(v); @@ -175,13 +178,20 @@ public override List Deserialize(Reader reader) { arr.Add(reader.ReadChar()); } + return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + return 1 + 4 + val.Count * 2; + } } internal class StringWrapper : NinoWrapperBase { - public override void Serialize(string val, Writer writer) + public override void Serialize(string val, ref Writer writer) { writer.Write(val); } @@ -190,19 +200,26 @@ public override string Deserialize(Reader reader) { return reader.ReadString(); } + + public override int GetSize(string val) + { + if (val is null) return 1; + return 1 + 4 + val.Length * 2; + } } internal class StringArrWrapper : NinoWrapperBase { - public override void Serialize(string[] val, Writer writer) + public override void Serialize(string[] val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Length); + writer.Write(val.Length); foreach (var v in val) { writer.Write(v); @@ -219,21 +236,35 @@ public override string[] Deserialize(Reader reader) { arr[i++] = reader.ReadString(); } + return arr; } + + public override int GetSize(string[] val) + { + if (val is null) return 1; + int size = 1 + 4; + foreach (var v in val) + { + size += 1 + 4 + v.Length * 2; + } + + return size; + } } internal class StringListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { writer.Write(v); @@ -251,13 +282,26 @@ public override List Deserialize(Reader reader) { arr.Add(reader.ReadString()); } + return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + int size = 1 + 4; + foreach (var v in val) + { + size += 1 + 4 + v.Length * 2; + } + + return size; + } } internal class DateTimeWrapper : NinoWrapperBase { - public override void Serialize(DateTime val, Writer writer) + public override void Serialize(DateTime val, ref Writer writer) { writer.Write(val); } @@ -266,50 +310,60 @@ public override DateTime Deserialize(Reader reader) { return reader.ReadDateTime(); } + + public override int GetSize(DateTime val) + { + return 8; + } } internal class DateTimeArrWrapper : NinoWrapperBase { - public override void Serialize(DateTime[] val, Writer writer) + public override void Serialize(DateTime[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - writer.CompressAndWrite(val.Length); - foreach (var v in val) - { - writer.Write(v); - } + writer.Write(val.AsSpan()); } - public override DateTime[] Deserialize(Reader reader) + public override unsafe DateTime[] Deserialize(Reader reader) { if (!reader.ReadBool()) return null; int len = reader.ReadLength(); - var arr = new DateTime[len]; - int i = 0; - while (i < len) + DateTime[] arr; + if (len == 0) { - arr[i++] = reader.ReadDateTime(); + arr = Array.Empty(); } + else + { + arr = new DateTime[len]; + fixed (DateTime* arrPtr = arr) + { + reader.ReadToBuffer((byte*)arrPtr, len * 8); + } + } + return arr; } + + public override int GetSize(DateTime[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length * 8; + } } internal class DateTimeListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { writer.Write(v); @@ -326,34 +380,16 @@ public override List Deserialize(Reader reader) { arr.Add(reader.ReadDateTime()); } + return arr; } - } - internal class GenericWrapper : NinoWrapperBase - { - public Serializer.ImporterDelegate Importer; - public Deserializer.ExporterDelegate Exporter; - - public override void Serialize(T val, Writer writer) + public override int GetSize(List val) { - if (val == null) - { - writer.Write(false); - return; - } - writer.Write(true); - if(Importer == null) - throw new InvalidOperationException($"Importer is null for type: {typeof(T)}"); - Importer(val, writer); - } + if (val is null) return 1; + int size = 1 + 4 + val.Count * 8; - public override T Deserialize(Reader reader) - { - if (!reader.ReadBool()) return default; - if(Exporter == null) - throw new InvalidOperationException($"Exporter is null for type: {typeof(T)}"); - return Exporter(reader); + return size; } } } \ No newline at end of file diff --git a/Nino_Unity/Assets/Nino/Serialization/Wrappers/Primitives/Decimals.cs b/Nino_Unity/Assets/Nino/Serialization/Wrappers/Primitives/Decimals.cs index 4cd02ca..6a376bc 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Wrappers/Primitives/Decimals.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Wrappers/Primitives/Decimals.cs @@ -1,11 +1,13 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace Nino.Serialization { internal class FloatWrapper : NinoWrapperBase { - public override void Serialize(float val, Writer writer) + public override void Serialize(float val, ref Writer writer) { writer.Write(val); } @@ -14,28 +16,18 @@ public override float Deserialize(Reader reader) { return reader.ReadSingle(); } + + public override int GetSize(float val) + { + return 4; + } } internal class FloatArrWrapper : NinoWrapperBase { - public override unsafe void Serialize(float[] val, Writer writer) + public override void Serialize(float[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - int len = val.Length; - writer.CompressAndWrite(ref len); - if (len > 0) - { - len *= 4; - fixed (float* ptr = val) - { - writer.Write((byte*)ptr, ref len); - } - } + writer.Write(val.AsSpan()); } public override unsafe float[] Deserialize(Reader reader) @@ -55,21 +47,29 @@ public override unsafe float[] Deserialize(Reader reader) reader.ReadToBuffer((byte*)arrPtr, len * 4); } } + return arr; } + + public override int GetSize(float[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length * 4; + } } internal class FloatListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { writer.Write(v); @@ -86,13 +86,22 @@ public override List Deserialize(Reader reader) { arr.Add(reader.ReadSingle()); } + return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + int size = 1 + 4 + val.Count * 4; + + return size; + } } internal class DoubleWrapper : NinoWrapperBase { - public override void Serialize(double val, Writer writer) + public override void Serialize(double val, ref Writer writer) { writer.Write(val); } @@ -101,28 +110,18 @@ public override double Deserialize(Reader reader) { return reader.ReadDouble(); } + + public override int GetSize(double val) + { + return 8; + } } internal class DoubleArrWrapper : NinoWrapperBase { - public override unsafe void Serialize(double[] val, Writer writer) + public override void Serialize(double[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - int len = val.Length; - writer.CompressAndWrite(ref len); - if (len > 0) - { - len *= 8; - fixed (double* ptr = val) - { - writer.Write((byte*)ptr, ref len); - } - } + writer.Write(val.AsSpan()); } public override unsafe double[] Deserialize(Reader reader) @@ -142,21 +141,29 @@ public override unsafe double[] Deserialize(Reader reader) reader.ReadToBuffer((byte*)arrPtr, len * 8); } } + return arr; } + + public override int GetSize(double[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length * 8; + } } internal class DoubleListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { writer.Write(v); @@ -173,13 +180,22 @@ public override List Deserialize(Reader reader) { arr.Add(reader.ReadDouble()); } + return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + int size = 1 + 4 + val.Count * 8; + + return size; + } } internal class DecimalWrapper : NinoWrapperBase { - public override void Serialize(decimal val, Writer writer) + public override void Serialize(decimal val, ref Writer writer) { writer.Write(val); } @@ -188,28 +204,18 @@ public override decimal Deserialize(Reader reader) { return reader.ReadDecimal(); } + + public override int GetSize(decimal val) + { + return 16; + } } internal class DecimalArrWrapper : NinoWrapperBase { - public override unsafe void Serialize(decimal[] val, Writer writer) + public override void Serialize(decimal[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - int len = val.Length; - writer.CompressAndWrite(ref len); - if (len > 0) - { - len *= 16; - fixed (decimal* ptr = val) - { - writer.Write((byte*)ptr, ref len); - } - } + writer.Write(val.AsSpan()); } public override unsafe decimal[] Deserialize(Reader reader) @@ -229,21 +235,29 @@ public override unsafe decimal[] Deserialize(Reader reader) reader.ReadToBuffer((byte*)arrPtr, len * 16); } } + return arr; } + + public override int GetSize(decimal[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length * 16; + } } internal class DecimalListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { writer.Write(v); @@ -260,7 +274,16 @@ public override List Deserialize(Reader reader) { arr.Add(reader.ReadDecimal()); } + return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + int size = 1 + 4 + val.Count * 16; + + return size; + } } } \ No newline at end of file diff --git a/Nino_Unity/Assets/Nino/Serialization/Wrappers/Primitives/Integers.cs b/Nino_Unity/Assets/Nino/Serialization/Wrappers/Primitives/Integers.cs index 67847f6..be67ac2 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Wrappers/Primitives/Integers.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Wrappers/Primitives/Integers.cs @@ -5,7 +5,7 @@ namespace Nino.Serialization { internal class ByteWrapper : NinoWrapperBase { - public override void Serialize(byte val, Writer writer) + public override void Serialize(byte val, ref Writer writer) { writer.Write(val); } @@ -14,27 +14,18 @@ public override byte Deserialize(Reader reader) { return reader.ReadByte(); } + + public override int GetSize(byte val) + { + return 1; + } } internal class ByteArrWrapper : NinoWrapperBase { - public override unsafe void Serialize(byte[] val, Writer writer) + public override void Serialize(byte[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - int len = val.Length; - writer.CompressAndWrite(ref len); - if (len > 0) - { - fixed (byte* ptr = val) - { - writer.Write(ptr, ref len); - } - } + writer.Write(val.AsSpan()); } public override byte[] Deserialize(Reader reader) @@ -43,19 +34,26 @@ public override byte[] Deserialize(Reader reader) int len = reader.ReadLength(); return len != 0 ? reader.ReadBytes(len) : Array.Empty(); } + + public override int GetSize(byte[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length; + } } internal class ByteListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { writer.Write(v); @@ -76,11 +74,17 @@ public override List Deserialize(Reader reader) return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + return 1 + 4 + val.Count; + } } internal class SByteWrapper : NinoWrapperBase { - public override void Serialize(sbyte val, Writer writer) + public override void Serialize(sbyte val, ref Writer writer) { writer.Write(val); } @@ -89,27 +93,18 @@ public override sbyte Deserialize(Reader reader) { return reader.ReadSByte(); } + + public override int GetSize(sbyte val) + { + return 1; + } } internal class SByteArrWrapper : NinoWrapperBase { - public override unsafe void Serialize(sbyte[] val, Writer writer) + public override void Serialize(sbyte[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - int len = val.Length; - writer.CompressAndWrite(ref len); - if (len > 0) - { - fixed (sbyte* ptr = val) - { - writer.Write((byte*)ptr, ref len); - } - } + writer.Write(val.AsSpan()); } public override unsafe sbyte[] Deserialize(Reader reader) @@ -132,19 +127,26 @@ public override unsafe sbyte[] Deserialize(Reader reader) return arr; } + + public override int GetSize(sbyte[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length; + } } internal class SByteListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { writer.Write(v); @@ -162,13 +164,20 @@ public override List Deserialize(Reader reader) { arr.Add(reader.ReadSByte()); } + return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + return 1 + 4 + val.Count; + } } internal class ShortWrapper : NinoWrapperBase { - public override void Serialize(short val, Writer writer) + public override void Serialize(short val, ref Writer writer) { writer.Write(val); } @@ -177,28 +186,18 @@ public override short Deserialize(Reader reader) { return reader.ReadInt16(); } + + public override int GetSize(short val) + { + return 2; + } } internal class ShortArrWrapper : NinoWrapperBase { - public override unsafe void Serialize(short[] val, Writer writer) + public override void Serialize(short[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - int len = val.Length; - writer.CompressAndWrite(ref len); - if (len > 0) - { - len *= 2; - fixed (short* ptr = val) - { - writer.Write((byte*)ptr, ref len); - } - } + writer.Write(val.AsSpan()); } public override unsafe short[] Deserialize(Reader reader) @@ -218,21 +217,29 @@ public override unsafe short[] Deserialize(Reader reader) reader.ReadToBuffer((byte*)arrPtr, len * 2); } } + return arr; } + + public override int GetSize(short[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length * 2; + } } internal class ShortListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { writer.Write(v); @@ -250,13 +257,20 @@ public override List Deserialize(Reader reader) { arr.Add(reader.ReadInt16()); } + return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + return 1 + 4 + val.Count * 2; + } } internal class UShortWrapper : NinoWrapperBase { - public override void Serialize(ushort val, Writer writer) + public override void Serialize(ushort val, ref Writer writer) { writer.Write(val); } @@ -265,28 +279,18 @@ public override ushort Deserialize(Reader reader) { return reader.ReadUInt16(); } + + public override int GetSize(ushort val) + { + return 2; + } } internal class UShortArrWrapper : NinoWrapperBase { - public override unsafe void Serialize(ushort[] val, Writer writer) + public override void Serialize(ushort[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - int len = val.Length; - writer.CompressAndWrite(ref len); - if (len > 0) - { - len *= 2; - fixed (ushort* ptr = val) - { - writer.Write((byte*)ptr, ref len); - } - } + writer.Write(val.AsSpan()); } public override unsafe ushort[] Deserialize(Reader reader) @@ -306,21 +310,29 @@ public override unsafe ushort[] Deserialize(Reader reader) reader.ReadToBuffer((byte*)arrPtr, len * 2); } } + return arr; } + + public override int GetSize(ushort[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length * 2; + } } internal class UShortListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { writer.Write(v); @@ -338,69 +350,78 @@ public override List Deserialize(Reader reader) { arr.Add(reader.ReadUInt16()); } + return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + return 1 + 4 + val.Count * 2; + } } internal class IntWrapper : NinoWrapperBase { - public override void Serialize(int val, Writer writer) + public override void Serialize(int val, ref Writer writer) { - writer.CompressAndWrite(ref val); + writer.Write(val); } public override int Deserialize(Reader reader) { - return reader.DecompressAndReadNumber(); + return reader.ReadInt32(); + } + + public override int GetSize(int val) + { + return 4; } } internal class IntArrWrapper : NinoWrapperBase { - public override void Serialize(int[] val, Writer writer) + public override void Serialize(int[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - writer.CompressAndWrite(val.Length); - foreach (var v in val) - { - writer.CompressAndWrite(v); - } + writer.Write(val.AsSpan()); } - public override int[] Deserialize(Reader reader) + public override unsafe int[] Deserialize(Reader reader) { if (!reader.ReadBool()) return null; int len = reader.ReadLength(); var arr = new int[len]; //read item - int i = 0; - while (i < len) + fixed (int* arrPtr = arr) { - reader.DecompressAndReadNumber(ref arr[i++]); + reader.ReadToBuffer((byte*)arrPtr, len * 4); } + return arr; } + + public override int GetSize(int[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length * 4; + } } internal class IntListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { - writer.CompressAndWrite(v); + writer.Write(v); } } @@ -413,71 +434,80 @@ public override List Deserialize(Reader reader) int i = 0; while (i++ < len) { - arr.Add(reader.DecompressAndReadNumber()); + arr.Add(reader.ReadInt32()); } + return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + return 1 + 4 + val.Count * 4; + } } internal class UIntWrapper : NinoWrapperBase { - public override void Serialize(uint val, Writer writer) + public override void Serialize(uint val, ref Writer writer) { - writer.CompressAndWrite(ref val); + writer.Write(val); } public override uint Deserialize(Reader reader) { - return reader.DecompressAndReadNumber(); + return reader.ReadUInt32(); + } + + public override int GetSize(uint val) + { + return 4; } } internal class UIntArrWrapper : NinoWrapperBase { - public override void Serialize(uint[] val, Writer writer) + public override void Serialize(uint[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - writer.CompressAndWrite(val.Length); - foreach (var v in val) - { - writer.CompressAndWrite(v); - } + writer.Write(val.AsSpan()); } - public override uint[] Deserialize(Reader reader) + public override unsafe uint[] Deserialize(Reader reader) { if (!reader.ReadBool()) return null; int len = reader.ReadLength(); var arr = new uint[len]; //read item - int i = 0; - while (i < len) + fixed (uint* arrPtr = arr) { - reader.DecompressAndReadNumber(ref arr[i++]); + reader.ReadToBuffer((byte*)arrPtr, len * 4); } + return arr; } + + public override int GetSize(uint[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length * 4; + } } internal class UIntListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { - writer.CompressAndWrite(v); + writer.Write(v); } } @@ -490,71 +520,80 @@ public override List Deserialize(Reader reader) int i = 0; while (i++ < len) { - arr.Add(reader.DecompressAndReadNumber()); + arr.Add(reader.ReadUInt32()); } + return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + return 1 + 4 + val.Count * 4; + } } internal class LongWrapper : NinoWrapperBase { - public override void Serialize(long val, Writer writer) + public override void Serialize(long val, ref Writer writer) { - writer.CompressAndWrite(ref val); + writer.Write(val); } public override long Deserialize(Reader reader) { - return reader.DecompressAndReadNumber(); + return reader.ReadInt64(); + } + + public override int GetSize(long val) + { + return 8; } } internal class LongArrWrapper : NinoWrapperBase { - public override void Serialize(long[] val, Writer writer) + public override void Serialize(long[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - writer.CompressAndWrite(val.Length); - foreach (var v in val) - { - writer.CompressAndWrite(v); - } + writer.Write(val.AsSpan()); } - public override long[] Deserialize(Reader reader) + public override unsafe long[] Deserialize(Reader reader) { if (!reader.ReadBool()) return null; int len = reader.ReadLength(); var arr = new long[len]; //read item - int i = 0; - while (i < len) + fixed (long* arrPtr = arr) { - reader.DecompressAndReadNumber(ref arr[i++]); + reader.ReadToBuffer((byte*)arrPtr, len * 8); } + return arr; } + + public override int GetSize(long[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length * 8; + } } internal class LongListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { - writer.CompressAndWrite(v); + writer.Write(v); } } @@ -567,71 +606,80 @@ public override List Deserialize(Reader reader) int i = 0; while (i++ < len) { - arr.Add(reader.DecompressAndReadNumber()); + arr.Add(reader.ReadInt64()); } + return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + return 1 + 4 + val.Count * 8; + } } internal class ULongWrapper : NinoWrapperBase { - public override void Serialize(ulong val, Writer writer) + public override void Serialize(ulong val, ref Writer writer) { - writer.CompressAndWrite(ref val); + writer.Write(val); } public override ulong Deserialize(Reader reader) { - return reader.DecompressAndReadNumber(); + return reader.ReadUInt64(); + } + + public override int GetSize(ulong val) + { + return 8; } } internal class ULongArrWrapper : NinoWrapperBase { - public override void Serialize(ulong[] val, Writer writer) + public override void Serialize(ulong[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - writer.CompressAndWrite(val.Length); - foreach (var v in val) - { - writer.CompressAndWrite(v); - } + writer.Write(val.AsSpan()); } - public override ulong[] Deserialize(Reader reader) + public override unsafe ulong[] Deserialize(Reader reader) { if (!reader.ReadBool()) return null; int len = reader.ReadLength(); var arr = new ulong[len]; //read item - int i = 0; - while (i < len) + fixed (ulong* arrPtr = arr) { - reader.DecompressAndReadNumber(ref arr[i++]); + reader.ReadToBuffer((byte*)arrPtr, len * 8); } + return arr; } + + public override int GetSize(ulong[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length * 8; + } } internal class ULongListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { - writer.CompressAndWrite(v); + writer.Write(v); } } @@ -644,9 +692,16 @@ public override List Deserialize(Reader reader) int i = 0; while (i++ < len) { - arr.Add(reader.DecompressAndReadNumber()); + arr.Add(reader.ReadUInt64()); } + return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + return 1 + 4 + val.Count * 8; + } } } \ No newline at end of file diff --git a/Nino_Unity/Assets/Nino/Serialization/Writer.Generic.cs b/Nino_Unity/Assets/Nino/Serialization/Writer.Generic.cs index 3b9a6db..047f17b 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Writer.Generic.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Writer.Generic.cs @@ -1,12 +1,13 @@ using System; using System.IO; -using Nino.Shared.Mgr; using System.Collections.Generic; +using System.Runtime.InteropServices; using System.Runtime.CompilerServices; +using Nino.Shared.Mgr; namespace Nino.Serialization { - public partial class Writer + public ref partial struct Writer { /// /// Write primitive values, DO NOT USE THIS FOR CUSTOM IMPORTER @@ -14,8 +15,7 @@ public partial class Writer /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void WriteCommonVal(T val) => - Serializer.Serialize(typeof(T), val, this, option, false); + public void WriteCommonVal(T val) => Position = Serializer.Serialize(typeof(T), val, null, buffer, Position); /// /// Write primitive values, DO NOT USE THIS FOR CUSTOM IMPORTER @@ -25,7 +25,7 @@ public void WriteCommonVal(T val) => /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteCommonVal(Type type, T val) => - Serializer.Serialize(type, val, this, option, false); + Position = Serializer.Serialize(type, val, null, buffer, Position); /// /// Write unmanaged type @@ -33,80 +33,108 @@ public void WriteCommonVal(Type type, T val) => /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - private unsafe void Write(ref T val, byte len) where T : unmanaged + public void Write(ref T val, int len) where T : unmanaged { - Unsafe.Write(Unsafe.Add(buffer.Data, position), val); - position += len; + Unsafe.WriteUnaligned(ref buffer[Position], val); + Position += len; } /// - /// Compress and write enum + /// Write byte[] /// - /// + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public unsafe void CompressAndWriteEnum(T val) + public unsafe void Write(Span data) where T : unmanaged { - var type = typeof(T); - if (type == ConstMgr.ObjectType) + if (data == null) { - type = val.GetType(); - switch (TypeModel.GetTypeCode(type)) - { - case TypeCode.Byte: - buffer[position++] = Unsafe.Unbox(val); - return; - case TypeCode.SByte: - buffer[position++] = *(byte*)Unsafe.Unbox(val); - return; - case TypeCode.Int16: - Unsafe.As(ref buffer.AsSpan(position, 2).GetPinnableReference()) = - Unsafe.Unbox(val); - position += 2; - return; - case TypeCode.UInt16: - Unsafe.As(ref buffer.AsSpan(position, 2).GetPinnableReference()) = - Unsafe.Unbox(val); - position += 2; - return; - case TypeCode.Int32: - CompressAndWrite(ref Unsafe.Unbox(val)); - return; - case TypeCode.UInt32: - CompressAndWrite(ref Unsafe.Unbox(val)); - return; - case TypeCode.Int64: - CompressAndWrite(ref Unsafe.Unbox(val)); - return; - case TypeCode.UInt64: - CompressAndWrite(ref Unsafe.Unbox(val)); - return; - } + Write(false); + return; + } + + Write(true); + var len = data.Length; + Write(len); + len *= sizeof(T); + MemoryMarshal.AsBytes(data).CopyTo(buffer.Slice(Position, len)); + Position += len; + } + /// + /// write enum + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteEnum(T val) + { + //boxed + if (typeof(T) == ConstMgr.ObjectType) + { + WriteEnum((object)val); return; } + ref byte p = ref MemoryMarshal.GetReference(buffer); + switch (TypeModel.GetTypeCode(typeof(T))) + { + case TypeCode.Byte: + case TypeCode.SByte: + case TypeCode.Int16: + case TypeCode.UInt16: + case TypeCode.Int32: + case TypeCode.UInt32: + byte len = (byte)Unsafe.SizeOf(); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref p, Position), val); + Position += len; + return; + case TypeCode.Int64: + case TypeCode.UInt64: + Unsafe.WriteUnaligned(ref Unsafe.Add(ref p, Position), val); + Position += 8; + return; + } + } + + /// + /// write enum + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe void WriteEnum(object val) + { + var type = val.GetType(); + ref byte p = ref MemoryMarshal.GetReference(buffer); switch (TypeModel.GetTypeCode(type)) { case TypeCode.Byte: + buffer[Position++] = Unsafe.Unbox(val); + return; case TypeCode.SByte: - Unsafe.Write(buffer.Data + position++, val); + buffer[Position++] = *(byte*)Unsafe.Unbox(val); return; case TypeCode.Int16: + Unsafe.WriteUnaligned(ref Unsafe.Add(ref p, Position), Unsafe.Unbox(val)); + Position += 2; + return; case TypeCode.UInt16: - Unsafe.Write(buffer.Data + position, val); - position += 2; + Unsafe.WriteUnaligned(ref Unsafe.Add(ref p, Position), Unsafe.Unbox(val)); + Position += 2; return; case TypeCode.Int32: - CompressAndWrite(ref Unsafe.As(ref val)); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref p, Position), Unsafe.Unbox(val)); + Position += 4; return; case TypeCode.UInt32: - CompressAndWrite(ref Unsafe.As(ref val)); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref p, Position), Unsafe.Unbox(val)); + Position += 4; return; case TypeCode.Int64: - CompressAndWrite(ref Unsafe.As(ref val)); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref p, Position), Unsafe.Unbox(val)); + Position += 8; return; case TypeCode.UInt64: - CompressAndWrite(ref Unsafe.As(ref val)); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref p, Position), Unsafe.Unbox(val)); + Position += 8; return; } } @@ -126,17 +154,18 @@ public void Write(T[] arr) } Write(true); + //write len + int len = arr.Length; + //empty - if (arr.Length == 0) + if (len == 0) { //write len - CompressAndWrite(0); + Write(0); return; } - //write len - int len = arr.Length; - CompressAndWrite(ref len); + Write(len); //write item int i = 0; while (i < len) @@ -149,7 +178,6 @@ public void Write(T[] arr) #else var eType = obj.GetType(); #endif - Write(eType.GetHashCode()); WriteCommonVal(eType, obj); } } @@ -188,16 +216,15 @@ public void Write(List lst) } Write(true); + int len = lst.Count; + //write len + Write(lst.Count); //empty - if (lst.Count == 0) + if (len == 0) { - //write len - CompressAndWrite(0); return; } - //write len - CompressAndWrite(lst.Count); //write item foreach (var c in lst) { @@ -205,11 +232,10 @@ public void Write(List lst) var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns ? ilIns.Type.ReflectionType : c.GetType(); + WriteCommonVal(eType, c); #else - var eType = c.GetType(); + WriteCommonVal(c); #endif - Write(eType.GetHashCode()); - WriteCommonVal(eType, c); } } @@ -229,16 +255,16 @@ public void Write(HashSet lst) } Write(true); + int len = lst.Count; + //write len + Write(len); //empty - if (lst.Count == 0) + if (len == 0) { //write len - CompressAndWrite(0); return; } - //write len - CompressAndWrite(lst.Count); //write item foreach (var c in lst) { @@ -246,11 +272,10 @@ public void Write(HashSet lst) var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns ? ilIns.Type.ReflectionType : c.GetType(); + WriteCommonVal(eType, c); #else - var eType = c.GetType(); + WriteCommonVal(c); #endif - Write(eType.GetHashCode()); - WriteCommonVal(eType, c); } } @@ -270,16 +295,16 @@ public void Write(Queue lst) } Write(true); + int len = lst.Count; + //write len + Write(len); //empty - if (lst.Count == 0) + if (len == 0) { //write len - CompressAndWrite(0); return; } - //write len - CompressAndWrite(lst.Count); //write item foreach (var c in lst) { @@ -287,11 +312,10 @@ public void Write(Queue lst) var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns ? ilIns.Type.ReflectionType : c.GetType(); + WriteCommonVal(eType, c); #else - var eType = c.GetType(); + WriteCommonVal(c); #endif - Write(eType.GetHashCode()); - WriteCommonVal(eType, c); } } @@ -311,16 +335,16 @@ public void Write(Stack lst) } Write(true); + int len = lst.Count; + //write len + Write(len); //empty - if (lst.Count == 0) + if (len == 0) { //write len - CompressAndWrite(0); return; } - //write len - CompressAndWrite(lst.Count); //write item foreach (var c in lst) { @@ -328,11 +352,10 @@ public void Write(Stack lst) var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns ? ilIns.Type.ReflectionType : c.GetType(); + WriteCommonVal(eType, c); #else - var eType = c.GetType(); + WriteCommonVal(c); #endif - Write(eType.GetHashCode()); - WriteCommonVal(eType, c); } } @@ -353,17 +376,16 @@ public void Write(Dictionary dictionary) } Write(true); + int len = dictionary.Count; + //write len + Write(len); //empty - if (dictionary.Count == 0) + if (len == 0) { //write len - CompressAndWrite(0); return; } - //write len - int len = dictionary.Count; - CompressAndWrite(ref len); //record keys var keys = dictionary.Keys; //write items @@ -374,22 +396,20 @@ public void Write(Dictionary dictionary) var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns ? ilIns.Type.ReflectionType : c.GetType(); + WriteCommonVal(eType, c); #else - var eType = c.GetType(); + WriteCommonVal(c); #endif - Write(eType.GetHashCode()); - WriteCommonVal(eType, c); //write val var val = dictionary[c]; #if ILRuntime eType = val is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns2 ? ilIns2.Type.ReflectionType : val.GetType(); + WriteCommonVal(eType, val); #else - eType = val.GetType(); + WriteCommonVal(val); #endif - Write(eType.GetHashCode()); - WriteCommonVal(eType, val); } } } diff --git a/Nino_Unity/Assets/Nino/Serialization/Writer.cs b/Nino_Unity/Assets/Nino/Serialization/Writer.cs index 85671e6..20c3b68 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Writer.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Writer.cs @@ -1,6 +1,5 @@ using System; using System.IO; -using Nino.Shared.IO; using Nino.Shared.Mgr; using System.Collections; using System.Runtime.CompilerServices; @@ -10,84 +9,27 @@ namespace Nino.Serialization /// /// A writer that writes serialization Data /// - public partial class Writer + public ref partial struct Writer { - /// - /// block size when creating buffer - /// - private const ushort BufferBlockSize = ushort.MaxValue; - /// /// Buffer that stores data /// - private ExtensibleBuffer buffer; - - /// - /// compress option - /// - private CompressOption option; + private Span buffer; /// /// Position of the current buffer /// - private int position; - - /// - /// Convert writer to byte - /// - /// - public byte[] ToBytes() - { - switch (option) - { - case CompressOption.Zlib: - return CompressMgr.Compress(buffer, position); - case CompressOption.Lz4: - throw new NotSupportedException("not support lz4 yet"); - case CompressOption.NoCompression: - return buffer.ToArray(0, position); - } - - return ConstMgr.Null; - } - - /// - /// Create a writer (needs to set up values) - /// - public Writer() - { - } + public int Position; /// /// Create a nino writer /// - /// - public Writer(CompressOption option = CompressOption.Zlib) + /// + /// + public Writer(Span buffer, int position) { - Init(option); - } - - /// - /// Init writer - /// - /// - public void Init(CompressOption compressOption) - { - if (buffer == null) - { - var peak = ObjectPool>.Peak(); - if (peak != null && peak.ExpandSize == BufferBlockSize) - { - buffer = ObjectPool>.Request(); - } - else - { - buffer = new ExtensibleBuffer(BufferBlockSize); - } - } - - position = 0; - option = compressOption; + this.buffer = buffer; + Position = position; } /// @@ -98,22 +40,7 @@ public void Init(CompressOption compressOption) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteCommonVal(Type type, object val) => - Serializer.Serialize(type, val, this, option, false); - - /// - /// Write byte[] - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public unsafe void Write(byte[] data) - { - var len = data.Length; - CompressAndWrite(len); - fixed (byte* ptr = data) - { - Write(ptr, ref len); - } - } + Position = Serializer.Serialize(type, val, null, buffer, Position); /// /// Write byte[] @@ -127,16 +54,16 @@ internal unsafe void Write(byte* data, ref int len) { while (len-- > 0) { - buffer[position++] = *data++; + buffer[Position++] = *data++; } return; } - buffer.CopyFrom(data, 0, position, len); - position += len; + Unsafe.CopyBlockUnaligned(ref buffer[Position], ref *data, (uint)len); + Position += len; } - + /// /// Write a double /// @@ -164,7 +91,7 @@ public void Write(float value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Write(DateTime value) { - Write(value.ToOADate()); + Write(ref value, ConstMgr.SizeOfLong); } /// @@ -185,7 +112,7 @@ public void Write(decimal d) [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Write(bool value) { - buffer[position++] = Unsafe.As(ref value); + Unsafe.WriteUnaligned(ref buffer[Position++], value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -211,8 +138,7 @@ public unsafe void Write(string val) if (val == string.Empty) { - Write((byte)CompressType.Byte); - Write((byte)0); + Write(0); return; } @@ -220,7 +146,7 @@ public unsafe void Write(string val) int len = strSpan.Length * ConstMgr.SizeOfUShort; fixed (char* first = &strSpan.GetPinnableReference()) { - CompressAndWrite(len); + Write(len); Write((byte*)first, ref len); } } @@ -234,7 +160,7 @@ public unsafe void Write(string val) [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Write(byte num) { - buffer[position++] = num; + buffer[Position++] = num; } /// @@ -244,7 +170,7 @@ public void Write(byte num) [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Write(sbyte num) { - buffer[position++] = Unsafe.As(ref num); + Unsafe.WriteUnaligned(ref buffer[Position++], num); } /// @@ -309,227 +235,6 @@ public void Write(ulong num) #endregion - #region write whole number without sign - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CompressAndWrite(ref ulong num) - { - if (num <= uint.MaxValue) - { - if (num <= ushort.MaxValue) - { - if (num <= byte.MaxValue) - { - buffer[position++] = (byte)CompressType.Byte; - Write(ref num, 1); - return; - } - - buffer[position++] = (byte)CompressType.UInt16; - Write(ref num, ConstMgr.SizeOfUShort); - return; - } - - buffer[position++] = (byte)CompressType.UInt32; - Write(ref num, ConstMgr.SizeOfUInt); - return; - } - - buffer[position++] = (byte)CompressType.UInt64; - Write(ref num, ConstMgr.SizeOfULong); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CompressAndWrite(ref uint num) - { - if (num <= ushort.MaxValue) - { - if (num <= byte.MaxValue) - { - buffer[position++] = (byte)CompressType.Byte; - Write(ref num, 1); - return; - } - - buffer[position++] = (byte)CompressType.UInt16; - Write(ref num, ConstMgr.SizeOfUShort); - return; - } - - buffer[position++] = (byte)CompressType.UInt32; - Write(ref num, ConstMgr.SizeOfUInt); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CompressAndWrite(ulong num) - { - ref var n = ref num; - CompressAndWrite(ref n); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CompressAndWrite(uint num) - { - ref var n = ref num; - CompressAndWrite(ref n); - } - - #endregion - - #region write whole number with sign - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CompressAndWrite(ref long num) - { - if (num < 0) - { - if (num >= int.MinValue) - { - if (num >= short.MinValue) - { - if (num >= sbyte.MinValue) - { - buffer[position++] = (byte)CompressType.SByte; - Write(ref num, 1); - return; - } - - buffer[position++] = (byte)CompressType.Int16; - Write(ref num, ConstMgr.SizeOfShort); - return; - } - - buffer[position++] = (byte)CompressType.Int32; - Write(ref num, ConstMgr.SizeOfInt); - return; - } - - buffer[position++] = (byte)CompressType.Int64; - Write(ref num, ConstMgr.SizeOfLong); - return; - } - - if (num <= int.MaxValue) - { - if (num <= short.MaxValue) - { - if (num <= byte.MaxValue) - { - buffer[position++] = (byte)CompressType.Byte; - Write(ref num, 1); - return; - } - - buffer[position++] = (byte)CompressType.UInt16; - Write(ref num, ConstMgr.SizeOfShort); - return; - } - - buffer[position++] = (byte)CompressType.UInt32; - Write(ref num, ConstMgr.SizeOfInt); - return; - } - - buffer[position++] = (byte)CompressType.UInt64; - Write(ref num, ConstMgr.SizeOfLong); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CompressAndWrite(ref int num) - { - if (num < 0) - { - if (num >= short.MinValue) - { - if (num >= sbyte.MinValue) - { - buffer[position++] = (byte)CompressType.SByte; - Write(ref num, 1); - return; - } - - buffer[position++] = (byte)CompressType.Int16; - Write(ref num, ConstMgr.SizeOfShort); - return; - } - - buffer[position++] = (byte)CompressType.Int32; - Write(ref num, ConstMgr.SizeOfInt); - return; - } - - if (num <= short.MaxValue) - { - if (num <= byte.MaxValue) - { - buffer[position++] = (byte)CompressType.Byte; - Write(ref num, 1); - return; - } - - buffer[position++] = (byte)CompressType.UInt16; - Write(ref num, ConstMgr.SizeOfShort); - return; - } - - buffer[position++] = (byte)CompressType.UInt32; - Write(ref num, ConstMgr.SizeOfInt); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CompressAndWrite(long num) - { - ref var n = ref num; - CompressAndWrite(ref n); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CompressAndWrite(int num) - { - ref var n = ref num; - CompressAndWrite(ref n); - } - - #endregion - - /// - /// Compress and write enum (no boxing) - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Obsolete("Please re-generate nino serialize code to use the latest api")] - public void CompressAndWriteEnum(Type type, ulong val) - { - switch (TypeModel.GetTypeCode(type)) - { - case TypeCode.Byte: - Write((byte)val); - return; - case TypeCode.SByte: - Write((sbyte)val); - return; - case TypeCode.Int16: - Write((short)val); - return; - case TypeCode.UInt16: - Write((ushort)val); - return; - case TypeCode.Int32: - CompressAndWrite((int)val); - return; - case TypeCode.UInt32: - CompressAndWrite((uint)val); - return; - case TypeCode.Int64: - CompressAndWrite((long)val); - return; - case TypeCode.UInt64: - CompressAndWrite(val); - return; - } - } - /// /// Write array /// @@ -545,17 +250,10 @@ public void Write(Array arr) } Write(true); - //empty - if (arr.Length == 0) - { - //write len - CompressAndWrite(0); - return; - } - //write len int len = arr.Length; - CompressAndWrite(ref len); + //empty + Write(len); //write item int i = 0; while (i < len) @@ -568,7 +266,6 @@ public void Write(Array arr) #else var eType = obj.GetType(); #endif - Write(eType.GetHashCode()); WriteCommonVal(eType, obj); } } @@ -588,16 +285,15 @@ public void Write(IList arr) } Write(true); + var len = arr.Count; + //write len + Write(len); //empty - if (arr.Count == 0) + if (len == 0) { - //write len - CompressAndWrite(0); return; } - //write len - CompressAndWrite(arr.Count); //write item foreach (var c in arr) { @@ -608,7 +304,6 @@ public void Write(IList arr) #else var eType = c.GetType(); #endif - Write(eType.GetHashCode()); WriteCommonVal(eType, c); } } @@ -628,17 +323,15 @@ public void Write(IDictionary dictionary) } Write(true); + //write len + int len = dictionary.Count; + Write(len); //empty if (dictionary.Count == 0) { - //write len - CompressAndWrite(0); return; } - //write len - int len = dictionary.Count; - CompressAndWrite(ref len); //record keys var keys = dictionary.Keys; //write items @@ -652,7 +345,6 @@ public void Write(IDictionary dictionary) #else var eType = c.GetType(); #endif - Write(eType.GetHashCode()); WriteCommonVal(eType, c); //write val var val = dictionary[c]; @@ -663,7 +355,6 @@ public void Write(IDictionary dictionary) #else eType = val.GetType(); #endif - Write(eType.GetHashCode()); WriteCommonVal(eType, val); } } diff --git a/Nino_Unity/Assets/Nino/Shared/IO/Stream/DeflateStream.cs b/Nino_Unity/Assets/Nino/Shared/IO/Stream/DeflateStream.cs index 1ca6194..f361f5f 100644 --- a/Nino_Unity/Assets/Nino/Shared/IO/Stream/DeflateStream.cs +++ b/Nino_Unity/Assets/Nino/Shared/IO/Stream/DeflateStream.cs @@ -374,7 +374,12 @@ internal class DeflateStreamNative private sealed class SafeDeflateStreamHandle : SafeHandle // ReSharper restore ClassNeverInstantiated.Local { +#if NET7_0_OR_GREATER + public override bool IsInvalid => handle.Equals(IntPtr.Zero); +#else public override bool IsInvalid => handle == IntPtr.Zero; +#endif + // ReSharper disable UnusedMember.Local private SafeDeflateStreamHandle() diff --git a/Nino_Unity/Assets/Nino/Test/BuildTest2.cs b/Nino_Unity/Assets/Nino/Test/BuildTest2.cs index 02554ae..962d954 100644 --- a/Nino_Unity/Assets/Nino/Test/BuildTest2.cs +++ b/Nino_Unity/Assets/Nino/Test/BuildTest2.cs @@ -62,7 +62,6 @@ private void Awake() db = 999.999999999999, bo = true, en = TestEnum.A, - name = "amnsdhfgurieksdjfhryeudjf" }; } diff --git a/Nino_Unity/Assets/Nino/Test/Data.cs b/Nino_Unity/Assets/Nino/Test/Data.cs index aecf8ed..93649d8 100644 --- a/Nino_Unity/Assets/Nino/Test/Data.cs +++ b/Nino_Unity/Assets/Nino/Test/Data.cs @@ -69,7 +69,7 @@ private string GetDictString(Dictionary> ddd) [ProtoContract] [NinoSerialize] [MessagePackObject] - public partial class Data + public partial struct Data { [ProtoMember(1)] [NinoMember(1)] [BsonElement] [Key(1)] public int x; @@ -95,12 +95,9 @@ public partial class Data [ProtoMember(8)] [NinoMember(8)] [BsonElement] [Key(8)] public TestEnum en; - [ProtoMember(9)] [NinoMember(9)] [BsonElement] [Key(9)] - public string name = ""; - public override string ToString() { - return $"{x},{y},{z},{f},{d},{db},{bo},{en},{name}"; + return $"{x},{y},{z},{f},{d},{db},{bo},{en}"; } } diff --git a/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test1.cs b/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test1.cs index cda0a9b..9f2d3eb 100644 --- a/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test1.cs +++ b/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test1.cs @@ -1,3 +1,4 @@ +using System; using System.IO; using System.Text; using Nino.Shared.Util; @@ -67,7 +68,6 @@ private static void DoTest(int max) db = 999.999999999999, bo = true, en = TestEnum.A, - name = GetString(20) }; } @@ -82,22 +82,32 @@ private static void DoTest(int max) #region Test Logger.D("Serialization Test", $"testing {max} objs"); - var sizeOfNestedData = Encoding.Default.GetByteCount(points.name) + - (sizeof(int) + sizeof(short) + sizeof(long) + sizeof(float) + sizeof(double) + - sizeof(decimal) + sizeof(bool) + sizeof(byte) + - Encoding.Default.GetByteCount(points.ps[0].name)) * points.ps.Length; - Logger.D("Serialization Test", $"marshal.sizeof struct: {sizeOfNestedData} bytes"); Logger.D("Serialization Test", "======================================"); //Nino var sw = new Stopwatch(); BeginSample("Nino"); sw.Restart(); - var bs = Nino.Serialization.Serializer.Serialize(points); - sw.Stop(); - EndSample(); - Logger.D("Serialization Test", $"Nino: {bs.Length} bytes in {sw.ElapsedMilliseconds}ms"); - long len = bs.Length; + int size = Nino.Serialization.Serializer.GetSize(points); + long len; + if (size <= 1024) + { + Span ret = stackalloc byte[size]; + Nino.Serialization.Serializer.Serialize(ret, points); + sw.Stop(); + EndSample(); + Logger.D("Serialization Test", $"Nino: {ret.Length} bytes in {sw.ElapsedMilliseconds}ms"); + len = ret.Length; + } + else + { + byte[] ret = new byte[size]; + Nino.Serialization.Serializer.Serialize(ret, points); + sw.Stop(); + EndSample(); + Logger.D("Serialization Test", $"Nino: {ret.Length} bytes in {sw.ElapsedMilliseconds}ms"); + len = ret.Length; + } var tm = sw.ElapsedMilliseconds; //Logger.D("Serialization Test",string.Join(",", bs)); @@ -105,6 +115,7 @@ private static void DoTest(int max) BeginSample("PB-net"); sw.Restart(); //we want byte[], pbnet returns stream + byte[] bs; //to be able to make it fair, we need to convert stream to byte[] using (var ms = new MemoryStream()) { diff --git a/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test10.cs b/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test10.cs index 8c12bde..1c29e8b 100644 --- a/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test10.cs +++ b/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test10.cs @@ -90,7 +90,6 @@ public static void Main() db = 999.999999999999, bo = true, en = TestEnum.A, - name = "asdfhudjh" }, new Data() { @@ -102,7 +101,6 @@ public static void Main() db = 999.999999999999, bo = true, en = TestEnum.A, - name = "asdfhudjh" } }, new Data[] @@ -117,7 +115,6 @@ public static void Main() db = 999.999999999999, bo = true, en = TestEnum.A, - name = "asdfhudjh" }, new Data() { @@ -129,7 +126,6 @@ public static void Main() db = 999.999999999999, bo = true, en = TestEnum.A, - name = "asdfhudjh" } } }; @@ -147,7 +143,6 @@ public static void Main() db = 999.999999999999, bo = true, en = TestEnum.A, - name = "asdfhudjh" }, new Data() { @@ -159,7 +154,6 @@ public static void Main() db = 999.999999999999, bo = true, en = TestEnum.A, - name = "asdfhudjh" } }, new Data[] @@ -174,7 +168,6 @@ public static void Main() db = 999.999999999999, bo = true, en = TestEnum.A, - name = "asdfhudjh" }, new Data() { @@ -186,7 +179,6 @@ public static void Main() db = 999.999999999999, bo = true, en = TestEnum.A, - name = "asdfhudjh" } }, }; @@ -209,7 +201,6 @@ public static void Main() db = 999.999999999999, bo = true, en = TestEnum.A, - name = "asdfhudjh" } }, new List() @@ -224,7 +215,6 @@ public static void Main() db = 999.999999999999, bo = true, en = TestEnum.A, - name = "asdfhudjh" } } }; diff --git a/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test2.cs b/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test2.cs index a5c341a..05d812e 100644 --- a/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test2.cs +++ b/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test2.cs @@ -1,3 +1,4 @@ +using System; using System.IO; using System.Text; using Nino.Shared.Util; @@ -68,7 +69,6 @@ private static void DoTest(int max) db = 999.999999999999, bo = true, en = TestEnum.A, - name = GetString(20) }; } @@ -83,22 +83,33 @@ private static void DoTest(int max) #region Test Logger.D("Serialization Test", $"testing {max} objs"); - var sizeOfNestedData = Encoding.Default.GetByteCount(points.name) + - (sizeof(int) + sizeof(short) + sizeof(long) + sizeof(float) + sizeof(double) + - sizeof(decimal) + sizeof(bool) + sizeof(byte) + - Encoding.Default.GetByteCount(points.ps[0].name)) * points.ps.Length; - Logger.D("Serialization Test", $"marshal.sizeof struct: {sizeOfNestedData} bytes"); Logger.D("Serialization Test", "======================================"); //Nino var sw = new Stopwatch(); BeginSample("Nino"); sw.Restart(); - var bs = Nino.Serialization.Serializer.Serialize(points); - sw.Stop(); - EndSample(); - Logger.D("Serialization Test", $"Nino: {bs.Length} bytes in {sw.ElapsedMilliseconds}ms"); - long len = bs.Length; + int size = Nino.Serialization.Serializer.GetSize(points); + long len; + byte[] bs; + if (size <= 1024) + { + Span ret = stackalloc byte[size]; + Nino.Serialization.Serializer.Serialize(ret, points); + sw.Stop(); + EndSample(); + Logger.D("Serialization Test", $"Nino: {ret.Length} bytes in {sw.ElapsedMilliseconds}ms"); + len = ret.Length; + } + else + { + byte[] ret = new byte[size]; + Nino.Serialization.Serializer.Serialize(ret, points); + sw.Stop(); + EndSample(); + Logger.D("Serialization Test", $"Nino: {ret.Length} bytes in {sw.ElapsedMilliseconds}ms"); + len = ret.Length; + } var tm = sw.ElapsedMilliseconds; //Logger.D("Serialization Test",string.Join(",", bs)); diff --git a/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test3.cs b/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test3.cs index 815342c..a46fdd1 100644 --- a/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test3.cs +++ b/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test3.cs @@ -68,15 +68,13 @@ private static void DoTest(int max) db = 999.999999999999, bo = true, en = TestEnum.A, - name = GetString(20) }; } - NestedData2 points = new NestedData2() + NestedData points = new NestedData() { name = "测试", - ps = ps, - vs = new List(){1,65535,65536,1234567,int.MaxValue} + ps = ps }; #endregion @@ -84,14 +82,6 @@ private static void DoTest(int max) #region Test Logger.D("Deserialization Test", $"testing {max} objs"); - var sizeOfNestedData = Encoding.Default.GetByteCount(points.name) + - (sizeof(int) + sizeof(short) + sizeof(long) + sizeof(float) + sizeof(double) + - sizeof(decimal) + sizeof(bool) + sizeof(byte) + - Encoding.Default.GetByteCount(points.ps[0].name)) * points.ps.Length+ - 5 * sizeof(int); - Logger.D("Deserialization Test", $"marshal.sizeof struct: {sizeOfNestedData} bytes"); - Logger.D("Deserialization Test", "======================================"); - NestedData2 d; //Nino diff --git a/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test4.cs b/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test4.cs index 5946fee..5b17464 100644 --- a/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test4.cs +++ b/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test4.cs @@ -69,7 +69,6 @@ private static void DoTest(int max) db = 999.999999999999, bo = true, en = TestEnum.A, - name = GetString(20) }; } @@ -85,12 +84,6 @@ private static void DoTest(int max) #region Test Logger.D("Deserialization Test", $"testing {max} objs"); - var sizeOfNestedData = Encoding.Default.GetByteCount(points.name) + - (sizeof(int) + sizeof(short) + sizeof(long) + sizeof(float) + sizeof(double) + - sizeof(decimal) + sizeof(bool) + sizeof(byte) + - Encoding.Default.GetByteCount(points.ps[0].name)) * points.ps.Length+ - 5 * sizeof(int); - Logger.D("Deserialization Test", $"marshal.sizeof struct: {sizeOfNestedData} bytes"); Logger.D("Deserialization Test", "======================================"); NestedData2 d; diff --git a/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test5.cs b/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test5.cs index f403f23..1736345 100644 --- a/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test5.cs +++ b/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test5.cs @@ -1,3 +1,4 @@ +using System; using System.IO; using System.Text; using Nino.Shared.Util; @@ -11,7 +12,8 @@ namespace Nino.Test.Editor.Serialization { public class Test5 { - private const string SerializationTest5 = "Nino/Test/Serialization/Test5 - Serialize and Deserialize (Nino vs MongoDB.Bson)"; + private const string SerializationTest5 = + "Nino/Test/Serialization/Test5 - Serialize and Deserialize (Nino vs MongoDB.Bson)"; private static string GetString(int len) { @@ -21,7 +23,7 @@ private static string GetString(int len) } #if UNITY_2017_1_OR_NEWER - [UnityEditor.MenuItem(SerializationTest5,priority=5)] + [UnityEditor.MenuItem(SerializationTest5, priority = 5)] #endif public static void Main() { @@ -56,7 +58,7 @@ private static void EndSample() #endif return; } - + private static void DoTest(int max) { #region Test data @@ -74,7 +76,6 @@ private static void DoTest(int max) db = 999.999999999999, bo = true, en = TestEnum.A, - name = GetString(20) }; } @@ -89,84 +90,159 @@ private static void DoTest(int max) #region Test Logger.D("Serialization Test", $"testing {max} objs"); - var sizeOfNestedData = Encoding.Default.GetByteCount(points.name) + - (sizeof(int) + sizeof(short) + sizeof(long) + sizeof(float) + sizeof(double) + - sizeof(decimal) + sizeof(bool) + sizeof(byte) + - Encoding.Default.GetByteCount(points.ps[0].name)) * points.ps.Length; - Logger.D("Serialization Test", $"marshal.sizeof struct: {sizeOfNestedData} bytes"); Logger.D("Serialization Test", "======================================"); //Nino var sw = new Stopwatch(); BeginSample("Nino - Serialize"); sw.Restart(); - var bs = Nino.Serialization.Serializer.Serialize(points); - sw.Stop(); - EndSample(); - Logger.D("Serialization Test", $"Nino: {bs.Length} bytes in {sw.ElapsedMilliseconds}ms"); - long len = bs.Length; - var tm = sw.ElapsedMilliseconds; - //Logger.D("Serialization Test",string.Join(",", bs)); - - //MongoDB.Bson - BeginSample("MongoDB.Bson - Serialize"); - byte[] bs2; - sw.Restart(); - //we want byte[], MongoDB.Bson returns stream - //to be able to make it fair, we need to convert stream to byte[] - using (MemoryStream ms = new MemoryStream()) + int size = Nino.Serialization.Serializer.GetSize(points); + long len; + byte[] bs; + if (size <= 1024) { - using (BsonBinaryWriter bsonWriter = new BsonBinaryWriter(ms, BsonBinaryWriterSettings.Defaults)) + Span ret = stackalloc byte[size]; + Nino.Serialization.Serializer.Serialize(ret, points); + sw.Stop(); + EndSample(); + Logger.D("Serialization Test", $"Nino: {ret.Length} bytes in {sw.ElapsedMilliseconds}ms"); + len = ret.Length; + var tm = sw.ElapsedMilliseconds; + //Logger.D("Serialization Test",string.Join(",", bs)); + + //MongoDB.Bson + BeginSample("MongoDB.Bson - Serialize"); + byte[] bs2; + sw.Restart(); + //we want byte[], MongoDB.Bson returns stream + //to be able to make it fair, we need to convert stream to byte[] + using (MemoryStream ms = new MemoryStream()) { - BsonSerializationContext context = BsonSerializationContext.CreateRoot(bsonWriter); - BsonSerializationArgs args = default; - args.NominalType = typeof (object); - IBsonSerializer serializer = BsonSerializer.LookupSerializer(args.NominalType); - serializer.Serialize(context, args, points); - bs2 = ms.ToArray(); + using (BsonBinaryWriter bsonWriter = new BsonBinaryWriter(ms, BsonBinaryWriterSettings.Defaults)) + { + BsonSerializationContext context = BsonSerializationContext.CreateRoot(bsonWriter); + BsonSerializationArgs args = default; + args.NominalType = typeof(object); + IBsonSerializer serializer = BsonSerializer.LookupSerializer(args.NominalType); + serializer.Serialize(context, args, points); + bs2 = ms.ToArray(); + } } - } - sw.Stop(); - EndSample(); - - Logger.D("Serialization Test", $"MongoDB.Bson: {bs2.Length} bytes in {sw.ElapsedMilliseconds}ms"); - //Logger.D("Serialization Test",string.Join(",", bs)); - Logger.D("Serialization Test", "======================================"); - Logger.D("Serialization Test", $"size diff (nino - MongoDB.Bson): {len - bs2.Length} bytes"); - Logger.D("Serialization Test", - $"size diff pct => diff/MongoDB.Bson : {((len - bs2.Length) * 100f / bs2.Length):F2}%"); + sw.Stop(); + EndSample(); + + Logger.D("Serialization Test", $"MongoDB.Bson: {bs2.Length} bytes in {sw.ElapsedMilliseconds}ms"); + //Logger.D("Serialization Test",string.Join(",", bs)); + + Logger.D("Serialization Test", "======================================"); + Logger.D("Serialization Test", $"size diff (nino - MongoDB.Bson): {len - bs2.Length} bytes"); + Logger.D("Serialization Test", + $"size diff pct => diff/MongoDB.Bson : {((len - bs2.Length) * 100f / bs2.Length):F2}%"); + + Logger.D("Serialization Test", "======================================"); + Logger.D("Serialization Test", $"time diff (nino - MongoDB.Bson): {tm - sw.ElapsedMilliseconds} ms"); + Logger.D("Serialization Test", + $"time diff pct => time/MongoDB.Bson : {((tm - sw.ElapsedMilliseconds) * 100f / sw.ElapsedMilliseconds):F2}%"); + + BeginSample("Nino - Deserialize"); + sw.Restart(); + var d = Nino.Serialization.Deserializer.Deserialize(ret); + sw.Stop(); + EndSample(); + Logger.D("Deserialization Test", d); + Logger.D("Deserialization Test", + $"Nino: extracted {len} bytes and deserialized {points.ps.Length} entries in {sw.ElapsedMilliseconds}ms"); + tm = sw.ElapsedMilliseconds; + + //MongoDB.Bson + BeginSample("MongoDB.Bson - Deserialize"); + sw.Restart(); + d = (NestedData)BsonSerializer.Deserialize(bs2, typeof(NestedData)); + sw.Stop(); + EndSample(); + Logger.D("Deserialization Test", d); + Logger.D("Deserialization Test", + $"MongoDB.Bson: extracted {bs2.Length} bytes and deserialized {points.ps.Length} entries in {sw.ElapsedMilliseconds}ms"); + + Logger.D("Deserialization Test", "======================================"); + Logger.D("Deserialization Test", $"time diff (nino - MongoDB.Bson): {tm - sw.ElapsedMilliseconds} ms"); + Logger.D("Deserialization Test", + $"time diff pct => time/MongoDB.Bson : {((tm - sw.ElapsedMilliseconds) * 100f / sw.ElapsedMilliseconds):F2}%"); + } + else + { + byte[] ret = new byte[size]; + Nino.Serialization.Serializer.Serialize(ret, points); + sw.Stop(); + EndSample(); + Logger.D("Serialization Test", $"Nino: {ret.Length} bytes in {sw.ElapsedMilliseconds}ms"); + len = ret.Length; + var tm = sw.ElapsedMilliseconds; + //Logger.D("Serialization Test",string.Join(",", bs)); + + //MongoDB.Bson + BeginSample("MongoDB.Bson - Serialize"); + byte[] bs2; + sw.Restart(); + //we want byte[], MongoDB.Bson returns stream + //to be able to make it fair, we need to convert stream to byte[] + using (MemoryStream ms = new MemoryStream()) + { + using (BsonBinaryWriter bsonWriter = new BsonBinaryWriter(ms, BsonBinaryWriterSettings.Defaults)) + { + BsonSerializationContext context = BsonSerializationContext.CreateRoot(bsonWriter); + BsonSerializationArgs args = default; + args.NominalType = typeof(object); + IBsonSerializer serializer = BsonSerializer.LookupSerializer(args.NominalType); + serializer.Serialize(context, args, points); + bs2 = ms.ToArray(); + } + } - Logger.D("Serialization Test", "======================================"); - Logger.D("Serialization Test", $"time diff (nino - MongoDB.Bson): {tm - sw.ElapsedMilliseconds} ms"); - Logger.D("Serialization Test", - $"time diff pct => time/MongoDB.Bson : {((tm - sw.ElapsedMilliseconds) * 100f / sw.ElapsedMilliseconds):F2}%"); + sw.Stop(); + EndSample(); + + Logger.D("Serialization Test", $"MongoDB.Bson: {bs2.Length} bytes in {sw.ElapsedMilliseconds}ms"); + //Logger.D("Serialization Test",string.Join(",", bs)); + + Logger.D("Serialization Test", "======================================"); + Logger.D("Serialization Test", $"size diff (nino - MongoDB.Bson): {len - bs2.Length} bytes"); + Logger.D("Serialization Test", + $"size diff pct => diff/MongoDB.Bson : {((len - bs2.Length) * 100f / bs2.Length):F2}%"); + + Logger.D("Serialization Test", "======================================"); + Logger.D("Serialization Test", $"time diff (nino - MongoDB.Bson): {tm - sw.ElapsedMilliseconds} ms"); + Logger.D("Serialization Test", + $"time diff pct => time/MongoDB.Bson : {((tm - sw.ElapsedMilliseconds) * 100f / sw.ElapsedMilliseconds):F2}%"); + + BeginSample("Nino - Deserialize"); + sw.Restart(); + var d = Nino.Serialization.Deserializer.Deserialize(ret); + sw.Stop(); + EndSample(); + Logger.D("Deserialization Test", d); + Logger.D("Deserialization Test", + $"Nino: extracted {ret.Length} bytes and deserialized {points.ps.Length} entries in {sw.ElapsedMilliseconds}ms"); + tm = sw.ElapsedMilliseconds; + + //MongoDB.Bson + BeginSample("MongoDB.Bson - Deserialize"); + sw.Restart(); + d = (NestedData)BsonSerializer.Deserialize(bs2, typeof(NestedData)); + sw.Stop(); + EndSample(); + Logger.D("Deserialization Test", d); + Logger.D("Deserialization Test", + $"MongoDB.Bson: extracted {bs2.Length} bytes and deserialized {points.ps.Length} entries in {sw.ElapsedMilliseconds}ms"); + + Logger.D("Deserialization Test", "======================================"); + Logger.D("Deserialization Test", $"time diff (nino - MongoDB.Bson): {tm - sw.ElapsedMilliseconds} ms"); + Logger.D("Deserialization Test", + $"time diff pct => time/MongoDB.Bson : {((tm - sw.ElapsedMilliseconds) * 100f / sw.ElapsedMilliseconds):F2}%"); + } - BeginSample("Nino - Deserialize"); - sw.Restart(); - var d = Nino.Serialization.Deserializer.Deserialize(bs); - sw.Stop(); - EndSample(); - Logger.D("Deserialization Test", d); - Logger.D("Deserialization Test", - $"Nino: extracted {bs.Length} bytes and deserialized {points.ps.Length} entries in {sw.ElapsedMilliseconds}ms"); - tm = sw.ElapsedMilliseconds; - - //MongoDB.Bson - BeginSample("MongoDB.Bson - Deserialize"); - sw.Restart(); - d = (NestedData)BsonSerializer.Deserialize(bs2, typeof(NestedData)); - sw.Stop(); - EndSample(); - Logger.D("Deserialization Test", d); - Logger.D("Deserialization Test", - $"MongoDB.Bson: extracted {bs2.Length} bytes and deserialized {points.ps.Length} entries in {sw.ElapsedMilliseconds}ms"); - - Logger.D("Deserialization Test", "======================================"); - Logger.D("Deserialization Test", $"time diff (nino - MongoDB.Bson): {tm - sw.ElapsedMilliseconds} ms"); - Logger.D("Deserialization Test", - $"time diff pct => time/MongoDB.Bson : {((tm - sw.ElapsedMilliseconds) * 100f / sw.ElapsedMilliseconds):F2}%"); #endregion } } -} +} \ No newline at end of file diff --git a/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test6.cs b/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test6.cs index e708966..ee5da79 100644 --- a/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test6.cs +++ b/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test6.cs @@ -1,3 +1,4 @@ +using System; using MessagePack; using System.Text; using Nino.Shared.Util; @@ -10,7 +11,8 @@ namespace Nino.Test.Editor.Serialization { public class Test6 { - private const string SerializationTest6 = "Nino/Test/Serialization/Test6 - Serialize and Deserialize (Nino vs MsgPack)"; + private const string SerializationTest6 = + "Nino/Test/Serialization/Test6 - Serialize and Deserialize (Nino vs MsgPack)"; private static string GetString(int len) { @@ -20,7 +22,7 @@ private static string GetString(int len) } #if UNITY_2017_1_OR_NEWER - [UnityEditor.MenuItem(SerializationTest6,priority=6)] + [UnityEditor.MenuItem(SerializationTest6, priority = 6)] #endif public static void Main() { @@ -42,7 +44,7 @@ public static void Main() { //ignore } - + Logger.W("1/5"); BeginSample("Array len of 10"); DoTest(10); @@ -80,7 +82,7 @@ private static void EndSample() #endif return; } - + private static void DoTest(int max) { #region Test data @@ -98,7 +100,6 @@ private static void DoTest(int max) db = 999.999999999999, bo = true, en = TestEnum.A, - name = GetString(20) }; } @@ -113,72 +114,133 @@ private static void DoTest(int max) #region Test Logger.D("Serialization Test", $"testing {max} objs"); - var sizeOfNestedData = Encoding.Default.GetByteCount(points.name) + - (sizeof(int) + sizeof(short) + sizeof(long) + sizeof(float) + sizeof(double) + - sizeof(decimal) + sizeof(bool) + sizeof(byte) + - Encoding.Default.GetByteCount(points.ps[0].name)) * points.ps.Length; - Logger.D("Serialization Test", $"marshal.sizeof struct: {sizeOfNestedData} bytes"); Logger.D("Serialization Test", "======================================"); //Nino var sw = new Stopwatch(); BeginSample("Nino - Serialize"); sw.Restart(); - var bs = Nino.Serialization.Serializer.Serialize(points); - sw.Stop(); - EndSample(); - Logger.D("Serialization Test", $"Nino: {bs.Length} bytes in {sw.ElapsedMilliseconds}ms"); - long len = bs.Length; - var tm = sw.ElapsedMilliseconds; - //Logger.D("Serialization Test",string.Join(",", bs)); - - //MsgPack - BeginSample("MsgPack - Serialize"); - byte[] bs2; - sw.Restart(); - var lz4Options = MessagePackSerializerOptions.Standard.WithCompression(MessagePackCompression.Lz4BlockArray); - bs2 = MessagePackSerializer.Serialize(points,lz4Options); - sw.Stop(); - EndSample(); + int size = Nino.Serialization.Serializer.GetSize(points); + long len; + byte[] bs; + if (size <= 1024) + { + Span ret = stackalloc byte[size]; + Nino.Serialization.Serializer.Serialize(ret, points); + sw.Stop(); + EndSample(); + Logger.D("Serialization Test", $"Nino: {ret.Length} bytes in {sw.ElapsedMilliseconds}ms"); + len = ret.Length; + var tm = sw.ElapsedMilliseconds; + + //MsgPack + BeginSample("MsgPack - Serialize"); + byte[] bs2; + sw.Restart(); + var lz4Options = MessagePackSerializerOptions.Standard.WithCompression(MessagePackCompression.None); + bs2 = MessagePackSerializer.Serialize(points, lz4Options); + sw.Stop(); + EndSample(); + + Logger.D("Serialization Test", $"MsgPack: {bs2.Length} bytes in {sw.ElapsedMilliseconds}ms"); + //Logger.D("Serialization Test",string.Join(",", bs)); + + Logger.D("Serialization Test", "======================================"); + Logger.D("Serialization Test", $"size diff (nino - MsgPack): {len - bs2.Length} bytes"); + Logger.D("Serialization Test", + $"size diff pct => diff/MsgPack : {((len - bs2.Length) * 100f / bs2.Length):F2}%"); + + Logger.D("Serialization Test", "======================================"); + Logger.D("Serialization Test", $"time diff (nino - MsgPack): {tm - sw.ElapsedMilliseconds} ms"); + Logger.D("Serialization Test", + $"time diff pct => time/MsgPack : {((tm - sw.ElapsedMilliseconds) * 100f / sw.ElapsedMilliseconds):F2}%"); + + BeginSample("Nino - Deserialize"); + sw.Restart(); + var d = Nino.Serialization.Deserializer.Deserialize(ret); + sw.Stop(); + EndSample(); + Logger.D("Deserialization Test", d); + Logger.D("Deserialization Test", + $"Nino: extracted {len} bytes and deserialized {points.ps.Length} entries in {sw.ElapsedMilliseconds}ms"); + tm = sw.ElapsedMilliseconds; + + //MsgPack + BeginSample("MsgPack - Deserialize"); + sw.Restart(); + d = MessagePackSerializer.Deserialize(bs2); + sw.Stop(); + EndSample(); + Logger.D("Deserialization Test", d); + Logger.D("Deserialization Test", + $"MsgPack: extracted {bs2.Length} bytes and deserialized {points.ps.Length} entries in {sw.ElapsedMilliseconds}ms"); + + Logger.D("Deserialization Test", "======================================"); + Logger.D("Deserialization Test", $"time diff (nino - MsgPack): {tm - sw.ElapsedMilliseconds} ms"); + Logger.D("Deserialization Test", + $"time diff pct => time/MsgPack : {((tm - sw.ElapsedMilliseconds) * 100f / sw.ElapsedMilliseconds):F2}%"); + } + else + { + byte[] ret = new byte[size]; + Nino.Serialization.Serializer.Serialize(ret, points); + sw.Stop(); + EndSample(); + Logger.D("Serialization Test", $"Nino: {ret.Length} bytes in {sw.ElapsedMilliseconds}ms"); + len = ret.Length; + var tm = sw.ElapsedMilliseconds; + + //MsgPack + BeginSample("MsgPack - Serialize"); + byte[] bs2; + sw.Restart(); + var lz4Options = MessagePackSerializerOptions.Standard.WithCompression(MessagePackCompression.None); + bs2 = MessagePackSerializer.Serialize(points, lz4Options); + sw.Stop(); + EndSample(); + + Logger.D("Serialization Test", $"MsgPack: {bs2.Length} bytes in {sw.ElapsedMilliseconds}ms"); + //Logger.D("Serialization Test",string.Join(",", bs)); + + Logger.D("Serialization Test", "======================================"); + Logger.D("Serialization Test", $"size diff (nino - MsgPack): {len - bs2.Length} bytes"); + Logger.D("Serialization Test", + $"size diff pct => diff/MsgPack : {((len - bs2.Length) * 100f / bs2.Length):F2}%"); + + Logger.D("Serialization Test", "======================================"); + Logger.D("Serialization Test", $"time diff (nino - MsgPack): {tm - sw.ElapsedMilliseconds} ms"); + Logger.D("Serialization Test", + $"time diff pct => time/MsgPack : {((tm - sw.ElapsedMilliseconds) * 100f / sw.ElapsedMilliseconds):F2}%"); + + BeginSample("Nino - Deserialize"); + sw.Restart(); + var d = Nino.Serialization.Deserializer.Deserialize(ret); + sw.Stop(); + EndSample(); + Logger.D("Deserialization Test", d); + Logger.D("Deserialization Test", + $"Nino: extracted {len} bytes and deserialized {points.ps.Length} entries in {sw.ElapsedMilliseconds}ms"); + tm = sw.ElapsedMilliseconds; + + //MsgPack + BeginSample("MsgPack - Deserialize"); + sw.Restart(); + d = MessagePackSerializer.Deserialize(bs2); + sw.Stop(); + EndSample(); + Logger.D("Deserialization Test", d); + Logger.D("Deserialization Test", + $"MsgPack: extracted {bs2.Length} bytes and deserialized {points.ps.Length} entries in {sw.ElapsedMilliseconds}ms"); + + Logger.D("Deserialization Test", "======================================"); + Logger.D("Deserialization Test", $"time diff (nino - MsgPack): {tm - sw.ElapsedMilliseconds} ms"); + Logger.D("Deserialization Test", + $"time diff pct => time/MsgPack : {((tm - sw.ElapsedMilliseconds) * 100f / sw.ElapsedMilliseconds):F2}%"); + } - Logger.D("Serialization Test", $"MsgPack: {bs2.Length} bytes in {sw.ElapsedMilliseconds}ms"); //Logger.D("Serialization Test",string.Join(",", bs)); - Logger.D("Serialization Test", "======================================"); - Logger.D("Serialization Test", $"size diff (nino - MsgPack): {len - bs2.Length} bytes"); - Logger.D("Serialization Test", - $"size diff pct => diff/MsgPack : {((len - bs2.Length) * 100f / bs2.Length):F2}%"); - - Logger.D("Serialization Test", "======================================"); - Logger.D("Serialization Test", $"time diff (nino - MsgPack): {tm - sw.ElapsedMilliseconds} ms"); - Logger.D("Serialization Test", - $"time diff pct => time/MsgPack : {((tm - sw.ElapsedMilliseconds) * 100f / sw.ElapsedMilliseconds):F2}%"); - - BeginSample("Nino - Deserialize"); - sw.Restart(); - var d = Nino.Serialization.Deserializer.Deserialize(bs); - sw.Stop(); - EndSample(); - Logger.D("Deserialization Test", d); - Logger.D("Deserialization Test", - $"Nino: extracted {bs.Length} bytes and deserialized {points.ps.Length} entries in {sw.ElapsedMilliseconds}ms"); - tm = sw.ElapsedMilliseconds; - - //MsgPack - BeginSample("MsgPack - Deserialize"); - sw.Restart(); - d = MessagePackSerializer.Deserialize(bs2); - sw.Stop(); - EndSample(); - Logger.D("Deserialization Test", d); - Logger.D("Deserialization Test", - $"MsgPack: extracted {bs2.Length} bytes and deserialized {points.ps.Length} entries in {sw.ElapsedMilliseconds}ms"); - - Logger.D("Deserialization Test", "======================================"); - Logger.D("Deserialization Test", $"time diff (nino - MsgPack): {tm - sw.ElapsedMilliseconds} ms"); - Logger.D("Deserialization Test", - $"time diff pct => time/MsgPack : {((tm - sw.ElapsedMilliseconds) * 100f / sw.ElapsedMilliseconds):F2}%"); #endregion } } -} +} \ No newline at end of file diff --git a/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test7.cs b/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test7.cs index 53ea3bf..be84ed5 100644 --- a/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test7.cs +++ b/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test7.cs @@ -1,20 +1,104 @@ -using System; -using Nino.Shared.Util; using Nino.Serialization; using System.Collections.Generic; +using UnityEngine; +using Logger = Nino.Shared.Util.Logger; // ReSharper disable RedundantTypeArgumentsOfMethod namespace Nino.Test.Editor.Serialization { + public class Vector3Wrapper : NinoWrapperBase + { + public override void Serialize(Vector3 val, ref Writer writer) + { + writer.Write(val.x); + writer.Write(val.y); + writer.Write(val.z); + } + + public override Vector3 Deserialize(Reader reader) + { + return new Vector3(reader.Read(4), reader.Read(4), reader.Read(4)); + } + + public override int GetSize(Vector3 val) + { + return 12; + } + } + + public class QuaternionWrapper : NinoWrapperBase + { + public override void Serialize(Quaternion val, ref Writer writer) + { + writer.Write(val.x); + writer.Write(val.y); + writer.Write(val.z); + writer.Write(val.w); + } + + public override Quaternion Deserialize(Reader reader) + { + return new Quaternion(reader.Read(4), reader.Read(4), reader.Read(4), + reader.Read(4)); + } + + public override int GetSize(Quaternion val) + { + return 16; + } + } + + public class Matrix4x4Wrapper : NinoWrapperBase + { + public override void Serialize(Matrix4x4 val, ref Writer writer) + { + writer.Write(val.m00); + writer.Write(val.m01); + writer.Write(val.m02); + writer.Write(val.m03); + writer.Write(val.m10); + writer.Write(val.m11); + writer.Write(val.m12); + writer.Write(val.m13); + writer.Write(val.m20); + writer.Write(val.m21); + writer.Write(val.m22); + writer.Write(val.m23); + writer.Write(val.m30); + writer.Write(val.m31); + writer.Write(val.m32); + writer.Write(val.m33); + } + + public override Matrix4x4 Deserialize(Reader reader) + { + return new Matrix4x4( + new Vector4(reader.Read(4), reader.Read(4), reader.Read(4), reader.Read(4)), + new Vector4(reader.Read(4), reader.Read(4), reader.Read(4), reader.Read(4)), + new Vector4(reader.Read(4), reader.Read(4), reader.Read(4), reader.Read(4)), + new Vector4(reader.Read(4), reader.Read(4), reader.Read(4), + reader.Read(4))); + } + + public override int GetSize(Matrix4x4 val) + { + return 64; + } + } + public class Test7 { private const string SerializationTest7 = "Nino/Test/Serialization/Test7 - Custom Type Importer Exporter"; #if UNITY_2017_1_OR_NEWER - [UnityEditor.MenuItem(SerializationTest7,priority=7)] + [UnityEditor.MenuItem(SerializationTest7, priority = 7)] #endif public static void Main() { + //register wrappers + WrapperManifest.AddWrapper(typeof(Vector3), new Vector3Wrapper()); + WrapperManifest.AddWrapper(typeof(Quaternion), new QuaternionWrapper()); + WrapperManifest.AddWrapper(typeof(Matrix4x4), new Matrix4x4Wrapper()); //custom type CustomTypeTest c = new CustomTypeTest() { @@ -42,75 +126,9 @@ public static void Main() } }; - Serializer.AddCustomImporter((val, writer) => - { - //write int - writer.Write(val.GetValueOrDefault()); - }); - Serializer.AddCustomImporter((val, writer) => - { - //write 3 float - writer.Write(val.x); - writer.Write(val.y); - writer.Write(val.z); - }); - Serializer.AddCustomImporter((val, writer) => - { - //write 4 float - writer.Write(val.x); - writer.Write(val.y); - writer.Write(val.z); - writer.Write(val.w); - }); - Serializer.AddCustomImporter((val, writer) => - { - void WriteV4(UnityEngine.Vector4 v) - { - writer.Write(v.x); - writer.Write(v.y); - writer.Write(v.z); - writer.Write(v.w); - } - - //write 4 rows - WriteV4(val.GetRow(0)); - WriteV4(val.GetRow(1)); - WriteV4(val.GetRow(2)); - WriteV4(val.GetRow(3)); - }); Logger.D($"will serialize c: {c}"); var bs = Serializer.Serialize(c); Logger.D($"serialized to {bs.Length} bytes: {string.Join(",", bs)}"); - - //register exporter (custom way to export bytes to object) - //as when writing nullable, we wrote int, here we read int - Deserializer.AddCustomExporter(reader => reader.ReadInt32()); - //as we wrote 3 floats with vector3, now we read 3 floats and parse to vector - Deserializer.AddCustomExporter(reader => - new UnityEngine.Vector3(reader.ReadFloat(), reader.ReadFloat(), reader.ReadFloat())); - //read 4 floats and parse to Quaternion - Deserializer.AddCustomExporter(reader => - new UnityEngine.Quaternion(reader.ReadFloat(), reader.ReadFloat(), reader.ReadFloat(), - reader.ReadFloat())); - //read 4 rows and parse to matrix 4x4 - Deserializer.AddCustomExporter(reader => - { - UnityEngine.Vector4 ReadV4() - { - return new UnityEngine.Vector4(reader.ReadFloat(), reader.ReadFloat(), reader.ReadFloat(), - reader.ReadFloat()); - } - - //result - var ret = new UnityEngine.Matrix4x4(); - //read 4 rows - ret.SetRow(0, ReadV4()); - ret.SetRow(1, ReadV4()); - ret.SetRow(2, ReadV4()); - ret.SetRow(3, ReadV4()); - return ret; - }); - Logger.D("will deserialize"); var cc = Deserializer.Deserialize(bs); Logger.D($"deserialized as cc: {cc}"); diff --git a/Nino_Unity/Assets/Nino/Test/MessagePackGenerated.cs b/Nino_Unity/Assets/Nino/Test/MessagePackGenerated.cs index a9ea462..89ec334 100644 --- a/Nino_Unity/Assets/Nino/Test/MessagePackGenerated.cs +++ b/Nino_Unity/Assets/Nino/Test/MessagePackGenerated.cs @@ -441,14 +441,8 @@ public sealed class DataFormatter : global::MessagePack.Formatters.IMessagePackF public void Serialize(ref global::MessagePack.MessagePackWriter writer, global::Nino.Test.Data value, global::MessagePack.MessagePackSerializerOptions options) { - if (value == null) - { - writer.WriteNil(); - return; - } - global::MessagePack.IFormatterResolver formatterResolver = options.Resolver; - writer.WriteArrayHeader(10); + writer.WriteArrayHeader(9); writer.WriteNil(); writer.Write(value.x); writer.Write(value.y); @@ -458,14 +452,13 @@ public void Serialize(ref global::MessagePack.MessagePackWriter writer, global:: writer.Write(value.db); writer.Write(value.bo); formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.en, options); - formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.name, options); } public global::Nino.Test.Data Deserialize(ref global::MessagePack.MessagePackReader reader, global::MessagePack.MessagePackSerializerOptions options) { if (reader.TryReadNil()) { - return null; + throw new global::System.InvalidOperationException("typecode is null, struct not supported"); } options.Security.DepthStep(ref reader); @@ -501,9 +494,6 @@ public void Serialize(ref global::MessagePack.MessagePackWriter writer, global:: case 8: ____result.en = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, options); break; - case 9: - ____result.name = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; default: reader.Skip(); break; diff --git a/Nino_Unity/Assets/ThirdParty/Mongo/MongoDB.Shared/GlobalAssemblyInfo.cs b/Nino_Unity/Assets/ThirdParty/Mongo/MongoDB.Shared/GlobalAssemblyInfo.cs deleted file mode 100644 index 32df04d..0000000 --- a/Nino_Unity/Assets/ThirdParty/Mongo/MongoDB.Shared/GlobalAssemblyInfo.cs +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright 2015-present MongoDB Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -using System.Reflection; - -[assembly: AssemblyCompany("MongoDB Inc.")] -[assembly: AssemblyVersion("0.0.0.*")] -[assembly: AssemblyFileVersion("0.0.0.0")] -[assembly: AssemblyInformationalVersion("0.0.0-unofficial")] -[assembly: AssemblyCopyright("Copyright © 2010-present MongoDB Inc.")] -[assembly: AssemblyConfiguration("Debug")] diff --git a/Nino_Unity/ProjectSettings/AutoStreamingSettings.asset b/Nino_Unity/ProjectSettings/AutoStreamingSettings.asset new file mode 100644 index 0000000..d3e071e --- /dev/null +++ b/Nino_Unity/ProjectSettings/AutoStreamingSettings.asset @@ -0,0 +1,21 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1200 &1 +AutoStreamingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + mSearchMode: 15 + mCustomSearchFile: + mTextureSearchString: + mMeshSearchString: + mTextures: [] + mAudios: [] + mMeshes: [] + mScenes: [] + mConfigCCD: + useCCD: 0 + cosKey: + projectGuid: + bucketUuid: + bucketName: + badgeName: diff --git a/Nino_Unity/ProjectSettings/ProjectVersion.txt b/Nino_Unity/ProjectSettings/ProjectVersion.txt index 5549a7f..d58dcc0 100644 --- a/Nino_Unity/ProjectSettings/ProjectVersion.txt +++ b/Nino_Unity/ProjectSettings/ProjectVersion.txt @@ -1,2 +1,2 @@ -m_EditorVersion: 2019.4.31f1 -m_EditorVersionWithRevision: 2019.4.31f1 (bd5abf232a62) +m_EditorVersion: 2020.3.47f1 +m_EditorVersionWithRevision: 2020.3.47f1 (5ef4f5b5e2d4) diff --git a/Nino_Unity/ProjectSettings/UnityConnectSettings.asset b/Nino_Unity/ProjectSettings/UnityConnectSettings.asset index fa0b146..a88bee0 100644 --- a/Nino_Unity/ProjectSettings/UnityConnectSettings.asset +++ b/Nino_Unity/ProjectSettings/UnityConnectSettings.asset @@ -9,6 +9,7 @@ UnityConnectSettings: m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events m_EventUrl: https://cdp.cloud.unity3d.com/v1/events m_ConfigUrl: https://config.uca.cloud.unity3d.com + m_DashboardUrl: https://dashboard.unity3d.com m_TestInitMode: 0 CrashReportingSettings: m_EventUrl: https://perf-events.cloud.unity3d.com @@ -22,6 +23,7 @@ UnityConnectSettings: m_Enabled: 0 m_TestMode: 0 m_InitializeOnStartup: 1 + m_PackageRequiringCoreStatsPresent: 0 UnityAdsSettings: m_Enabled: 0 m_InitializeOnStartup: 1 diff --git a/Nino_Unity/ProjectSettings/VersionControlSettings.asset b/Nino_Unity/ProjectSettings/VersionControlSettings.asset new file mode 100644 index 0000000..dca2881 --- /dev/null +++ b/Nino_Unity/ProjectSettings/VersionControlSettings.asset @@ -0,0 +1,8 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!890905787 &1 +VersionControlSettings: + m_ObjectHideFlags: 0 + m_Mode: Visible Meta Files + m_CollabEditorSettings: + inProgressEnabled: 1 diff --git a/Performance/Serialization.md b/Performance/Serialization.md index 9dd3f74..7582671 100644 --- a/Performance/Serialization.md +++ b/Performance/Serialization.md @@ -2,95 +2,18 @@ #### [**测试数据**](/Nino_Unity/Assets/Nino/Test/Data.cs) -*第一次序列化的时候,Nino会对类型进行缓存,达到预热效果,使得同一类型的第二次开始的序列化速度大幅度提升,其他库亦是如此* - ## Unity平台性能测试 -### 结论 - -> 数据越大,Nino的性能对比其他库就越强大,如果测试的数据很小,则与其他库差距不大,甚至会略微差于其他库 - -体积方面,Nino最小,MsgPack其次,其他库不尽人意 - -序列化速度方面,Nino Code Gen最快,MsgPack略慢一筹,Nino Reflection基本与Protobuf-net一致,其他库不尽人意(序列化小体积的数据,可能会比MsgPack略慢) - -**反序列化速度方面,Nino Code Gen最快**,MsgPack略慢一筹,Nino Reflection略快于Protobuf-net,略微逊色于MongoDB.Bson,BinaryFormatter最糟糕 - -**GC方面,Nino Code Gen碾压全部其他库**,一览众山小,序列化的GC比其他库低几百到上千倍,反序列化的GC与MsgPack持平,是其他库的几十到几百分之一! - -> 序列化下,Nino Code Gen的GC基本只有扩容和转二进制返回值时的GC,其他GC全无 -> -> 反序列化下,Nino Code Gen和MsgPack基本持平,GC基本只有new对象的GC,转字符串的GC,以及解压的GC,无任何额外GC - -### 易用性 - -Nino、BinaryFormatter、可以轻松用于Unity或其他C#平台(Mono以及IL2CPP平台),无需针对不同平台进行任何额外操作 - -MsgPack需要在IL2CPP平台(Unity和Xamarin)进行额外处理(防止AOT问题,需要预生成代码,不然会导致无法使用),该操作十分繁琐 - -Protobuf-net以及MongoDB.Bson在IL2CPP平台下,字典无法使用,这个是AOT问题,暂时没找到解决方案 - -### 备注 - -- 测试的时候[MsgPack有生成代码](/Nino_Unity/Assets/Nino/Test/MessagePackGenerated.cs),所以不要说Nino生成代码后和其他库对比不公平 -- 这里测试用的是MsgPack LZ4压缩,如果不开压缩的话,MsgPack的速度会快10%,但是体积则会变大很多(大概是Protobuf-net的体积的60%,即Nino的数倍) -- MsgPack之所以比较快是因为它用到了Emit以及生成了动态类型进行序列化(高效且低GC),但是在IL2CPP平台下,会遇到限制,所以上面才会提到MsgPack在IL2CPP平台使用起来很繁琐,Nino Code Gen这边是静态生成进行序列化(高效且低GC),即便不生成代码也不影响IL2CPP下使用,并且Nino生成的代码可以搭配ILRuntime或Huatuo技术实时热更 -- Odin序列化性能不如MsgPack,故而Odin序列化性能不如Nino Code Gen -- MsgPack在某些情况下的体积会比Nino小,这是因为Nino针对Collection类型(Array、List等)做了多态支持,会占用额外的体积 - -### 为什么Nino又小又快、还能易用且低GC - -- GC优化 - - Nino实现了高性能动态扩容数组,通过这个功能可以**极大幅度**降低GC(可以从20MB降到100KB) - - Nino底层用了对象池,实现了包括但不限于数据流、缓冲区等内容的复用,杜绝重复创建造成的开销 - - Nino在生成代码后,通过生成的代码,避免了装箱拆箱、反射字段造成的大额GC - - Nino在序列化和反序列化的时候,会调用不造成高额GC的方法写入数据(例如不用Decimal.GetBits去取Decimall的二进制,这个每次请求会产生一个int数组的GC) - - Nino改造了很多原生代码,实现了低GC(如Unity平台下DeflateStream的底层被彻底改造了,只剩下调用C++方法/Write时扩容/ToArray所造成的GC了,读和写的时候不需要申请io_buffer去读写导致gc,还可以直接无gc转Nino的动态扩容Buffer) -- 速度优化 - - Nino缓存了类型模型 - - Nino生成代码后直接调用了底层API,**大幅度**优化性能(速度快一倍以上) - - Nino底层写入数据直接在操作了指针,以实现用最高的效率去序列化和反序列化 -- 体积优化 - - Nino写Int64和Int32的时候会考虑压缩,最高将8字节压缩到2字节 - - Nino采用了C#自带的DeflateStream去压缩数据,该库是目前C#众多压缩库里最高性能,较高压缩率的压缩方式,但是只能用DeflateStream去解压,所以在其他领域用处不大,在Nino这里起到了巨大的作用 - - - -### 体积(bytes) - -![i1](https://s1.ax1x.com/2022/06/15/XowpM4.png) - -> 使用的是Zlib压缩模式 -> -> Nino < MsgPack (LZ4 Compress) < Protobuf-net < BinaryFormatter < MongoDB.Bson -> -> 体积方面可以忽略是否预热 - -### 序列化速度(ms) - -![i2](https://s1.ax1x.com/2022/06/15/XodP4f.png) - -> Nino Code Gen < MsgPack (LZ4 Compress) < MongoDB.Bson < Nino Reflection < Protobuf-net < BinaryFormatter - -### 反序列化速度(ms) - -![i3](https://s1.ax1x.com/2022/06/29/jnsrWt.png) - -> Nino Code Gen < MsgPack (LZ4 Compress) < MongoDB.Bson < Nino Reflection < Protobuf-net < BinaryFormatter -> - - +新版数据待补充 ## 非Unity平台性能测试 -> 注,此测试开启了原生压缩解压 - ``` ini BenchmarkDotNet=v0.13.1, OS=macOS 13.0.1 (22A400) [Darwin 22.1.0] Intel Core i9-8950HK CPU 2.90GHz (Coffee Lake), 1 CPU, 12 logical and 6 physical cores -.NET SDK=7.0.100 +.NET SDK=8.0.100-preview.5.23303.2 [Host] : .NET 6.0.12 (6.0.1222.56807), X64 RyuJIT ShortRun : .NET 6.0.12 (6.0.1222.56807), X64 RyuJIT @@ -99,565 +22,515 @@ IterationCount=1 LaunchCount=1 WarmupCount=1 ``` -| Method | Serializer | Mean | Error | DataSize | Gen 0 | Gen 1 | Gen 2 | Allocated | -| --------------------------------- | ------------------- | ------------------: | -----: | ---------: | -----------: | -----------: | -----------: | --------------: | -| **_PrimitiveBoolDeserialize** | **MessagePack_Lz4** | **222.29 ns** | **NA** | **-** | **0.0100** | **-** | **-** | **64 B** | -| _PrimitiveBoolDeserialize | MessagePack_NoComp | 95.40 ns | NA | - | - | - | - | - | -| _PrimitiveBoolDeserialize | ProtobufNet | 440.50 ns | NA | - | 0.0138 | - | - | 88 B | -| _PrimitiveBoolDeserialize | JsonNet | 1,110.07 ns | NA | - | 0.9041 | 0.0095 | - | 5,672 B | -| _PrimitiveBoolDeserialize | BinaryFormatter | 3,034.54 ns | NA | - | 0.6561 | 0.0038 | - | 4,128 B | -| _PrimitiveBoolDeserialize | DataContract | 2,237.42 ns | NA | - | 0.6638 | 0.0076 | - | 4,168 B | -| _PrimitiveBoolDeserialize | Hyperion | 99.29 ns | NA | - | 0.0305 | - | - | 192 B | -| _PrimitiveBoolDeserialize | Jil | 106.66 ns | NA | - | 0.0204 | - | - | 128 B | -| _PrimitiveBoolDeserialize | SpanJson | 25.23 ns | NA | - | - | - | - | - | -| _PrimitiveBoolDeserialize | UTF8Json | 36.92 ns | NA | - | - | - | - | - | -| _PrimitiveBoolDeserialize | FsPickler | 612.75 ns | NA | - | 0.1631 | - | - | 1,024 B | -| _PrimitiveBoolDeserialize | Ceras | 123.39 ns | NA | - | - | - | - | - | -| _PrimitiveBoolDeserialize | OdinSerializer_ | 456.07 ns | NA | - | - | - | - | - | -| _PrimitiveBoolDeserialize | Nino_Zlib | 143.87 ns | NA | - | - | - | - | - | -| _PrimitiveBoolDeserialize | Nino_NoComp | 138.92 ns | NA | - | - | - | - | - | -| **_PrimitiveBoolSerialize** | **MessagePack_Lz4** | **139.63 ns** | **NA** | **1 B** | **0.0153** | **-** | **-** | **96 B** | -| _PrimitiveBoolSerialize | MessagePack_NoComp | 113.97 ns | NA | 1 B | 0.0050 | - | - | 32 B | -| _PrimitiveBoolSerialize | ProtobufNet | 286.37 ns | NA | 2 B | 0.0596 | - | - | 376 B | -| _PrimitiveBoolSerialize | JsonNet | 677.44 ns | NA | 8 B | 0.4616 | 0.0029 | - | 2,896 B | -| _PrimitiveBoolSerialize | BinaryFormatter | 2,117.54 ns | NA | 53 B | 0.4883 | 0.0038 | - | 3,072 B | -| _PrimitiveBoolSerialize | DataContract | 939.35 ns | NA | 84 B | 0.2737 | - | - | 1,720 B | -| _PrimitiveBoolSerialize | Hyperion | 220.78 ns | NA | 2 B | 0.0789 | - | - | 496 B | -| _PrimitiveBoolSerialize | Jil | 139.97 ns | NA | 5 B | 0.0267 | - | - | 168 B | -| _PrimitiveBoolSerialize | SpanJson | 78.98 ns | NA | 5 B | 0.0050 | - | - | 32 B | -| _PrimitiveBoolSerialize | UTF8Json | 58.01 ns | NA | 5 B | 0.0050 | - | - | 32 B | -| _PrimitiveBoolSerialize | FsPickler | 669.80 ns | NA | 27 B | 0.1755 | - | - | 1,104 B | -| _PrimitiveBoolSerialize | Ceras | 502.23 ns | NA | 1 B | 0.6609 | - | - | 4,152 B | -| _PrimitiveBoolSerialize | OdinSerializer_ | 491.47 ns | NA | 2 B | 0.0048 | - | - | 32 B | -| _PrimitiveBoolSerialize | Nino_Zlib | 174.55 ns | NA | 1 B | 0.0050 | - | - | 32 B | -| _PrimitiveBoolSerialize | Nino_NoComp | 186.17 ns | NA | 1 B | 0.0050 | - | - | 32 B | -| **_PrimitiveByteDeserialize** | **MessagePack_Lz4** | **213.45 ns** | **NA** | **-** | **0.0100** | **-** | **-** | **64 B** | -| _PrimitiveByteDeserialize | MessagePack_NoComp | 96.05 ns | NA | - | - | - | - | - | -| _PrimitiveByteDeserialize | ProtobufNet | 423.92 ns | NA | - | 0.0138 | - | - | 88 B | -| _PrimitiveByteDeserialize | JsonNet | 1,132.96 ns | NA | - | 0.9098 | 0.0057 | - | 5,720 B | -| _PrimitiveByteDeserialize | BinaryFormatter | 2,924.55 ns | NA | - | 0.6561 | 0.0038 | - | 4,120 B | -| _PrimitiveByteDeserialize | DataContract | 2,188.99 ns | NA | - | 0.6561 | 0.0038 | - | 4,136 B | -| _PrimitiveByteDeserialize | Hyperion | 100.53 ns | NA | - | 0.0305 | - | - | 192 B | -| _PrimitiveByteDeserialize | Jil | 111.50 ns | NA | - | 0.0204 | - | - | 128 B | -| _PrimitiveByteDeserialize | SpanJson | 32.35 ns | NA | - | - | - | - | - | -| _PrimitiveByteDeserialize | UTF8Json | 42.23 ns | NA | - | - | - | - | - | -| _PrimitiveByteDeserialize | FsPickler | 648.26 ns | NA | - | 0.1612 | - | - | 1,016 B | -| _PrimitiveByteDeserialize | Ceras | 110.68 ns | NA | - | - | - | - | - | -| _PrimitiveByteDeserialize | OdinSerializer_ | 473.18 ns | NA | - | - | - | - | - | -| _PrimitiveByteDeserialize | Nino_Zlib | 156.51 ns | NA | - | - | - | - | - | -| _PrimitiveByteDeserialize | Nino_NoComp | 154.53 ns | NA | - | - | - | - | - | -| **_PrimitiveByteSerialize** | **MessagePack_Lz4** | **91.96 ns** | **NA** | **2 B** | **0.0153** | **-** | **-** | **96 B** | -| _PrimitiveByteSerialize | MessagePack_NoComp | 79.42 ns | NA | 2 B | 0.0050 | - | - | 32 B | -| _PrimitiveByteSerialize | ProtobufNet | 234.74 ns | NA | 3 B | 0.0598 | - | - | 376 B | -| _PrimitiveByteSerialize | JsonNet | 526.89 ns | NA | 6 B | 0.4768 | 0.0010 | - | 2,992 B | -| _PrimitiveByteSerialize | BinaryFormatter | 1,552.07 ns | NA | 50 B | 0.4883 | 0.0038 | - | 3,072 B | -| _PrimitiveByteSerialize | DataContract | 714.62 ns | NA | 92 B | 0.2747 | - | - | 1,728 B | -| _PrimitiveByteSerialize | Hyperion | 166.53 ns | NA | 2 B | 0.0789 | - | - | 496 B | -| _PrimitiveByteSerialize | Jil | 122.58 ns | NA | 3 B | 0.0420 | - | - | 264 B | -| _PrimitiveByteSerialize | SpanJson | 70.91 ns | NA | 3 B | 0.0050 | - | - | 32 B | -| _PrimitiveByteSerialize | UTF8Json | 48.94 ns | NA | 3 B | 0.0051 | - | - | 32 B | -| _PrimitiveByteSerialize | FsPickler | 527.07 ns | NA | 24 B | 0.1745 | - | - | 1,096 B | -| _PrimitiveByteSerialize | Ceras | 383.86 ns | NA | 1 B | 0.6614 | - | - | 4,152 B | -| _PrimitiveByteSerialize | OdinSerializer_ | 336.23 ns | NA | 2 B | 0.0048 | - | - | 32 B | -| _PrimitiveByteSerialize | Nino_Zlib | 138.62 ns | NA | 1 B | 0.0050 | - | - | 32 B | -| _PrimitiveByteSerialize | Nino_NoComp | 134.93 ns | NA | 1 B | 0.0050 | - | - | 32 B | -| **_PrimitiveCharDeserialize** | **MessagePack_Lz4** | **221.55 ns** | **NA** | **-** | **0.0100** | **-** | **-** | **64 B** | -| _PrimitiveCharDeserialize | MessagePack_NoComp | 98.39 ns | NA | - | - | - | - | - | -| _PrimitiveCharDeserialize | ProtobufNet | 433.28 ns | NA | - | 0.0138 | - | - | 88 B | -| _PrimitiveCharDeserialize | JsonNet | 1,124.85 ns | NA | - | 0.9117 | 0.0095 | - | 5,720 B | -| _PrimitiveCharDeserialize | BinaryFormatter | 3,230.59 ns | NA | - | 0.6561 | 0.0038 | - | 4,120 B | -| _PrimitiveCharDeserialize | DataContract | 2,100.41 ns | NA | - | 0.6561 | 0.0038 | - | 4,136 B | -| _PrimitiveCharDeserialize | Hyperion | 117.88 ns | NA | - | 0.0305 | - | - | 192 B | -| _PrimitiveCharDeserialize | Jil | 84.29 ns | NA | - | 0.0050 | - | - | 32 B | -| _PrimitiveCharDeserialize | SpanJson | 42.41 ns | NA | - | - | - | - | - | -| _PrimitiveCharDeserialize | UTF8Json | 96.41 ns | NA | - | 0.0038 | - | - | 24 B | -| _PrimitiveCharDeserialize | FsPickler | 680.08 ns | NA | - | 0.1612 | - | - | 1,016 B | -| _PrimitiveCharDeserialize | Ceras | 137.17 ns | NA | - | - | - | - | - | -| _PrimitiveCharDeserialize | OdinSerializer_ | 483.21 ns | NA | - | - | - | - | - | -| _PrimitiveCharDeserialize | Nino_Zlib | 145.60 ns | NA | - | - | - | - | - | -| _PrimitiveCharDeserialize | Nino_NoComp | 148.27 ns | NA | - | - | - | - | - | -| **_PrimitiveCharSerialize** | **MessagePack_Lz4** | **161.38 ns** | **NA** | **1 B** | **0.0153** | **-** | **-** | **96 B** | -| _PrimitiveCharSerialize | MessagePack_NoComp | 132.48 ns | NA | 1 B | 0.0050 | - | - | 32 B | -| _PrimitiveCharSerialize | ProtobufNet | 326.83 ns | NA | 2 B | 0.0596 | - | - | 376 B | -| _PrimitiveCharSerialize | JsonNet | 1,062.09 ns | NA | 6 B | 0.5169 | 0.0019 | - | 3,248 B | -| _PrimitiveCharSerialize | BinaryFormatter | 2,388.57 ns | NA | 50 B | 0.4883 | 0.0038 | - | 3,072 B | -| _PrimitiveCharSerialize | DataContract | 1,110.20 ns | NA | 75 B | 0.2728 | - | - | 1,712 B | -| _PrimitiveCharSerialize | Hyperion | 261.80 ns | NA | 3 B | 0.0787 | - | - | 496 B | -| _PrimitiveCharSerialize | Jil | 190.10 ns | NA | 3 B | 0.0267 | - | - | 168 B | -| _PrimitiveCharSerialize | SpanJson | 99.50 ns | NA | 3 B | 0.0050 | - | - | 32 B | -| _PrimitiveCharSerialize | UTF8Json | 124.84 ns | NA | 3 B | 0.0088 | - | - | 56 B | -| _PrimitiveCharSerialize | FsPickler | 793.73 ns | NA | 24 B | 0.1745 | - | - | 1,096 B | -| _PrimitiveCharSerialize | Ceras | 628.00 ns | NA | 2 B | 0.6609 | - | - | 4,152 B | -| _PrimitiveCharSerialize | OdinSerializer_ | 529.36 ns | NA | 3 B | 0.0048 | - | - | 32 B | -| _PrimitiveCharSerialize | Nino_Zlib | 206.11 ns | NA | 2 B | 0.0050 | - | - | 32 B | -| _PrimitiveCharSerialize | Nino_NoComp | 198.86 ns | NA | 2 B | 0.0050 | - | - | 32 B | -| **_PrimitiveDateTimeDeserialize** | **MessagePack_Lz4** | **269.62 ns** | **NA** | **-** | **0.0100** | **-** | **-** | **64 B** | -| _PrimitiveDateTimeDeserialize | MessagePack_NoComp | 117.38 ns | NA | - | - | - | - | - | -| _PrimitiveDateTimeDeserialize | ProtobufNet | 490.25 ns | NA | - | 0.0134 | - | - | 88 B | -| _PrimitiveDateTimeDeserialize | JsonNet | 1,586.28 ns | NA | - | 0.9098 | 0.0057 | - | 5,720 B | -| _PrimitiveDateTimeDeserialize | BinaryFormatter | 5,416.26 ns | NA | - | 0.9232 | 0.0076 | - | 5,801 B | -| _PrimitiveDateTimeDeserialize | DataContract | 2,561.31 ns | NA | - | 0.6828 | 0.0076 | - | 4,288 B | -| _PrimitiveDateTimeDeserialize | Hyperion | 129.34 ns | NA | - | 0.0305 | - | - | 192 B | -| _PrimitiveDateTimeDeserialize | Jil | 282.59 ns | NA | - | 0.0267 | - | - | 168 B | -| _PrimitiveDateTimeDeserialize | SpanJson | 403.83 ns | NA | - | - | - | - | - | -| _PrimitiveDateTimeDeserialize | UTF8Json | 403.90 ns | NA | - | - | - | - | - | -| _PrimitiveDateTimeDeserialize | FsPickler | 887.31 ns | NA | - | 0.1631 | - | - | 1,024 B | -| _PrimitiveDateTimeDeserialize | Ceras | 318.30 ns | NA | - | - | - | - | - | -| _PrimitiveDateTimeDeserialize | OdinSerializer_ | 1,145.84 ns | NA | - | 0.0153 | - | - | 104 B | -| _PrimitiveDateTimeDeserialize | Nino_Zlib | 145.17 ns | NA | - | - | - | - | - | -| _PrimitiveDateTimeDeserialize | Nino_NoComp | 157.65 ns | NA | - | - | - | - | - | -| **_PrimitiveDateTimeSerialize** | **MessagePack_Lz4** | **988.30 ns** | **NA** | **6 B** | **0.0153** | **-** | **-** | **96 B** | -| _PrimitiveDateTimeSerialize | MessagePack_NoComp | 532.88 ns | NA | 6 B | 0.0048 | - | - | 32 B | -| _PrimitiveDateTimeSerialize | ProtobufNet | 496.04 ns | NA | 6 B | 0.0591 | - | - | 376 B | -| _PrimitiveDateTimeSerialize | JsonNet | 1,486.33 ns | NA | 30 B | 0.4807 | - | - | 3,016 B | -| _PrimitiveDateTimeSerialize | BinaryFormatter | 3,234.85 ns | NA | 78 B | 0.5798 | 0.0038 | - | 3,656 B | -| _PrimitiveDateTimeSerialize | DataContract | 1,972.02 ns | NA | 106 B | 0.3395 | - | - | 2,144 B | -| _PrimitiveDateTimeSerialize | Hyperion | 303.81 ns | NA | 10 B | 0.0801 | - | - | 504 B | -| _PrimitiveDateTimeSerialize | Jil | 790.26 ns | NA | 22 B | 0.0668 | - | - | 424 B | -| _PrimitiveDateTimeSerialize | SpanJson | 557.45 ns | NA | 27 B | 0.0086 | - | - | 56 B | -| _PrimitiveDateTimeSerialize | UTF8Json | 652.97 ns | NA | 27 B | 0.0086 | - | - | 56 B | -| _PrimitiveDateTimeSerialize | FsPickler | 1,218.76 ns | NA | 44 B | 0.1774 | - | - | 1,120 B | -| _PrimitiveDateTimeSerialize | Ceras | 1,003.29 ns | NA | 8 B | 0.6599 | - | - | 4,152 B | -| _PrimitiveDateTimeSerialize | OdinSerializer_ | 1,190.45 ns | NA | 99 B | 0.0191 | - | - | 128 B | -| _PrimitiveDateTimeSerialize | Nino_Zlib | 213.88 ns | NA | 8 B | 0.0050 | - | - | 32 B | -| _PrimitiveDateTimeSerialize | Nino_NoComp | 228.76 ns | NA | 8 B | 0.0050 | - | - | 32 B | -| **_PrimitiveIntDeserialize** | **MessagePack_Lz4** | **235.56 ns** | **NA** | **-** | **0.0100** | **-** | **-** | **64 B** | -| _PrimitiveIntDeserialize | MessagePack_NoComp | 109.81 ns | NA | - | - | - | - | - | -| _PrimitiveIntDeserialize | ProtobufNet | 447.41 ns | NA | - | 0.0138 | - | - | 88 B | -| _PrimitiveIntDeserialize | JsonNet | 1,261.46 ns | NA | - | 0.9079 | 0.0057 | - | 5,696 B | -| _PrimitiveIntDeserialize | BinaryFormatter | 3,108.94 ns | NA | - | 0.6561 | 0.0038 | - | 4,120 B | -| _PrimitiveIntDeserialize | DataContract | 2,131.66 ns | NA | - | 0.6561 | 0.0038 | - | 4,136 B | -| _PrimitiveIntDeserialize | Hyperion | 118.17 ns | NA | - | 0.0305 | - | - | 192 B | -| _PrimitiveIntDeserialize | Jil | 138.12 ns | NA | - | 0.0229 | - | - | 144 B | -| _PrimitiveIntDeserialize | SpanJson | 66.53 ns | NA | - | - | - | - | - | -| _PrimitiveIntDeserialize | UTF8Json | 65.58 ns | NA | - | - | - | - | - | -| _PrimitiveIntDeserialize | FsPickler | 621.94 ns | NA | - | 0.1612 | - | - | 1,016 B | -| _PrimitiveIntDeserialize | Ceras | 127.77 ns | NA | - | - | - | - | - | -| _PrimitiveIntDeserialize | OdinSerializer_ | 476.63 ns | NA | - | - | - | - | - | -| _PrimitiveIntDeserialize | Nino_Zlib | 153.59 ns | NA | - | - | - | - | - | -| _PrimitiveIntDeserialize | Nino_NoComp | 152.27 ns | NA | - | - | - | - | - | -| **_PrimitiveIntSerialize** | **MessagePack_Lz4** | **102.46 ns** | **NA** | **5 B** | **0.0153** | **-** | **-** | **96 B** | -| _PrimitiveIntSerialize | MessagePack_NoComp | 80.68 ns | NA | 5 B | 0.0050 | - | - | 32 B | -| _PrimitiveIntSerialize | ProtobufNet | 211.90 ns | NA | 11 B | 0.0610 | - | - | 384 B | -| _PrimitiveIntSerialize | JsonNet | 522.47 ns | NA | 14 B | 0.4778 | 0.0019 | - | 3,000 B | -| _PrimitiveIntSerialize | BinaryFormatter | 1,390.02 ns | NA | 54 B | 0.4883 | 0.0038 | - | 3,072 B | -| _PrimitiveIntSerialize | DataContract | 696.81 ns | NA | 82 B | 0.2737 | - | - | 1,720 B | -| _PrimitiveIntSerialize | Hyperion | 161.08 ns | NA | 5 B | 0.0789 | - | - | 496 B | -| _PrimitiveIntSerialize | Jil | 107.79 ns | NA | 11 B | 0.0458 | - | - | 288 B | -| _PrimitiveIntSerialize | SpanJson | 83.51 ns | NA | 11 B | 0.0063 | - | - | 40 B | -| _PrimitiveIntSerialize | UTF8Json | 60.55 ns | NA | 11 B | 0.0063 | - | - | 40 B | -| _PrimitiveIntSerialize | FsPickler | 453.62 ns | NA | 28 B | 0.1760 | - | - | 1,104 B | -| _PrimitiveIntSerialize | Ceras | 323.80 ns | NA | 5 B | 0.6614 | - | - | 4,152 B | -| _PrimitiveIntSerialize | OdinSerializer_ | 295.59 ns | NA | 5 B | 0.0048 | - | - | 32 B | -| _PrimitiveIntSerialize | Nino_Zlib | 134.57 ns | NA | 5 B | 0.0050 | - | - | 32 B | -| _PrimitiveIntSerialize | Nino_NoComp | 119.82 ns | NA | 5 B | 0.0050 | - | - | 32 B | -| **_PrimitiveLongDeserialize** | **MessagePack_Lz4** | **222.07 ns** | **NA** | **-** | **0.0100** | **-** | **-** | **64 B** | -| _PrimitiveLongDeserialize | MessagePack_NoComp | 103.32 ns | NA | - | - | - | - | - | -| _PrimitiveLongDeserialize | ProtobufNet | 428.93 ns | NA | - | 0.0138 | - | - | 88 B | -| _PrimitiveLongDeserialize | JsonNet | 1,260.51 ns | NA | - | 0.9079 | 0.0057 | - | 5,696 B | -| _PrimitiveLongDeserialize | BinaryFormatter | 2,981.59 ns | NA | - | 0.6561 | 0.0038 | - | 4,120 B | -| _PrimitiveLongDeserialize | DataContract | 2,079.31 ns | NA | - | 0.6561 | 0.0038 | - | 4,136 B | -| _PrimitiveLongDeserialize | Hyperion | 120.07 ns | NA | - | 0.0305 | - | - | 192 B | -| _PrimitiveLongDeserialize | Jil | 172.65 ns | NA | - | 0.0253 | - | - | 160 B | -| _PrimitiveLongDeserialize | SpanJson | 88.73 ns | NA | - | - | - | - | - | -| _PrimitiveLongDeserialize | UTF8Json | 74.94 ns | NA | - | - | - | - | - | -| _PrimitiveLongDeserialize | FsPickler | 652.31 ns | NA | - | 0.1612 | - | - | 1,016 B | -| _PrimitiveLongDeserialize | Ceras | 125.82 ns | NA | - | - | - | - | - | -| _PrimitiveLongDeserialize | OdinSerializer_ | 462.90 ns | NA | - | - | - | - | - | -| _PrimitiveLongDeserialize | Nino_Zlib | 156.28 ns | NA | - | - | - | - | - | -| _PrimitiveLongDeserialize | Nino_NoComp | 149.51 ns | NA | - | - | - | - | - | -| **_PrimitiveLongSerialize** | **MessagePack_Lz4** | **104.46 ns** | **NA** | **9 B** | **0.0166** | **-** | **-** | **104 B** | -| _PrimitiveLongSerialize | MessagePack_NoComp | 88.07 ns | NA | 9 B | 0.0063 | - | - | 40 B | -| _PrimitiveLongSerialize | ProtobufNet | 222.75 ns | NA | 10 B | 0.0610 | - | - | 384 B | -| _PrimitiveLongSerialize | JsonNet | 595.36 ns | NA | 22 B | 0.4787 | 0.0038 | - | 3,008 B | -| _PrimitiveLongSerialize | BinaryFormatter | 1,561.98 ns | NA | 58 B | 0.4902 | 0.0038 | - | 3,080 B | -| _PrimitiveLongSerialize | DataContract | 763.44 ns | NA | 92 B | 0.2747 | - | - | 1,728 B | -| _PrimitiveLongSerialize | Hyperion | 168.71 ns | NA | 9 B | 0.0801 | - | - | 504 B | -| _PrimitiveLongSerialize | Jil | 178.44 ns | NA | 19 B | 0.0663 | - | - | 416 B | -| _PrimitiveLongSerialize | SpanJson | 84.74 ns | NA | 19 B | 0.0076 | - | - | 48 B | -| _PrimitiveLongSerialize | UTF8Json | 82.10 ns | NA | 19 B | 0.0076 | - | - | 48 B | -| _PrimitiveLongSerialize | FsPickler | 464.22 ns | NA | 32 B | 0.1760 | - | - | 1,104 B | -| _PrimitiveLongSerialize | Ceras | 316.20 ns | NA | 8 B | 0.6614 | - | - | 4,152 B | -| _PrimitiveLongSerialize | OdinSerializer_ | 301.59 ns | NA | 9 B | 0.0062 | - | - | 40 B | -| _PrimitiveLongSerialize | Nino_Zlib | 121.94 ns | NA | 9 B | 0.0062 | - | - | 40 B | -| _PrimitiveLongSerialize | Nino_NoComp | 120.22 ns | NA | 9 B | 0.0062 | - | - | 40 B | -| **_PrimitiveSByteDeserialize** | **MessagePack_Lz4** | **226.21 ns** | **NA** | **-** | **0.0100** | **-** | **-** | **64 B** | -| _PrimitiveSByteDeserialize | MessagePack_NoComp | 107.57 ns | NA | - | - | - | - | - | -| _PrimitiveSByteDeserialize | ProtobufNet | 420.53 ns | NA | - | 0.0138 | - | - | 88 B | -| _PrimitiveSByteDeserialize | JsonNet | 1,173.78 ns | NA | - | 0.9098 | 0.0057 | - | 5,720 B | -| _PrimitiveSByteDeserialize | BinaryFormatter | 2,973.26 ns | NA | - | 0.6561 | 0.0038 | - | 4,120 B | -| _PrimitiveSByteDeserialize | DataContract | 2,034.18 ns | NA | - | 0.6561 | 0.0038 | - | 4,136 B | -| _PrimitiveSByteDeserialize | Hyperion | 92.84 ns | NA | - | 0.0305 | - | - | 192 B | -| _PrimitiveSByteDeserialize | Jil | 107.63 ns | NA | - | 0.0204 | - | - | 128 B | -| _PrimitiveSByteDeserialize | SpanJson | 39.98 ns | NA | - | - | - | - | - | -| _PrimitiveSByteDeserialize | UTF8Json | 45.22 ns | NA | - | - | - | - | - | -| _PrimitiveSByteDeserialize | FsPickler | 587.44 ns | NA | - | 0.1612 | - | - | 1,016 B | -| _PrimitiveSByteDeserialize | Ceras | 115.64 ns | NA | - | - | - | - | - | -| _PrimitiveSByteDeserialize | OdinSerializer_ | 433.59 ns | NA | - | - | - | - | - | -| _PrimitiveSByteDeserialize | Nino_Zlib | 135.45 ns | NA | - | - | - | - | - | -| _PrimitiveSByteDeserialize | Nino_NoComp | 133.51 ns | NA | - | - | - | - | - | -| **_PrimitiveSByteSerialize** | **MessagePack_Lz4** | **84.05 ns** | **NA** | **2 B** | **0.0153** | **-** | **-** | **96 B** | -| _PrimitiveSByteSerialize | MessagePack_NoComp | 72.41 ns | NA | 2 B | 0.0050 | - | - | 32 B | -| _PrimitiveSByteSerialize | ProtobufNet | 209.75 ns | NA | 11 B | 0.0610 | - | - | 384 B | -| _PrimitiveSByteSerialize | JsonNet | 467.49 ns | NA | 7 B | 0.4768 | 0.0010 | - | 2,992 B | -| _PrimitiveSByteSerialize | BinaryFormatter | 1,467.11 ns | NA | 51 B | 0.4883 | 0.0038 | - | 3,072 B | -| _PrimitiveSByteSerialize | DataContract | 649.26 ns | NA | 77 B | 0.2728 | - | - | 1,712 B | -| _PrimitiveSByteSerialize | Hyperion | 153.24 ns | NA | 2 B | 0.0789 | - | - | 496 B | -| _PrimitiveSByteSerialize | Jil | 112.42 ns | NA | 4 B | 0.0420 | - | - | 264 B | -| _PrimitiveSByteSerialize | SpanJson | 66.85 ns | NA | 4 B | 0.0050 | - | - | 32 B | -| _PrimitiveSByteSerialize | UTF8Json | 47.29 ns | NA | 4 B | 0.0051 | - | - | 32 B | -| _PrimitiveSByteSerialize | FsPickler | 469.70 ns | NA | 25 B | 0.1760 | - | - | 1,104 B | -| _PrimitiveSByteSerialize | Ceras | 298.89 ns | NA | 1 B | 0.6614 | - | - | 4,152 B | -| _PrimitiveSByteSerialize | OdinSerializer_ | 282.31 ns | NA | 2 B | 0.0048 | - | - | 32 B | -| _PrimitiveSByteSerialize | Nino_Zlib | 111.29 ns | NA | 1 B | 0.0050 | - | - | 32 B | -| _PrimitiveSByteSerialize | Nino_NoComp | 119.20 ns | NA | 1 B | 0.0050 | - | - | 32 B | -| **_PrimitiveShortDeserialize** | **MessagePack_Lz4** | **223.23 ns** | **NA** | **-** | **0.0100** | **-** | **-** | **64 B** | -| _PrimitiveShortDeserialize | MessagePack_NoComp | 104.21 ns | NA | - | - | - | - | - | -| _PrimitiveShortDeserialize | ProtobufNet | 421.04 ns | NA | - | 0.0138 | - | - | 88 B | -| _PrimitiveShortDeserialize | JsonNet | 1,159.24 ns | NA | - | 0.9098 | 0.0057 | - | 5,720 B | -| _PrimitiveShortDeserialize | BinaryFormatter | 2,926.90 ns | NA | - | 0.6561 | 0.0038 | - | 4,120 B | -| _PrimitiveShortDeserialize | DataContract | 1,947.54 ns | NA | - | 0.6561 | 0.0038 | - | 4,136 B | -| _PrimitiveShortDeserialize | Hyperion | 108.60 ns | NA | - | 0.0305 | - | - | 192 B | -| _PrimitiveShortDeserialize | Jil | 105.69 ns | NA | - | 0.0204 | - | - | 128 B | -| _PrimitiveShortDeserialize | SpanJson | 47.09 ns | NA | - | - | - | - | - | -| _PrimitiveShortDeserialize | UTF8Json | 46.90 ns | NA | - | - | - | - | - | -| _PrimitiveShortDeserialize | FsPickler | 632.71 ns | NA | - | 0.1612 | - | - | 1,016 B | -| _PrimitiveShortDeserialize | Ceras | 111.61 ns | NA | - | - | - | - | - | -| _PrimitiveShortDeserialize | OdinSerializer_ | 462.96 ns | NA | - | - | - | - | - | -| _PrimitiveShortDeserialize | Nino_Zlib | 138.76 ns | NA | - | - | - | - | - | -| _PrimitiveShortDeserialize | Nino_NoComp | 148.85 ns | NA | - | - | - | - | - | -| **_PrimitiveShortSerialize** | **MessagePack_Lz4** | **116.22 ns** | **NA** | **3 B** | **0.0153** | **-** | **-** | **96 B** | -| _PrimitiveShortSerialize | MessagePack_NoComp | 88.65 ns | NA | 3 B | 0.0050 | - | - | 32 B | -| _PrimitiveShortSerialize | ProtobufNet | 207.51 ns | NA | 4 B | 0.0598 | - | - | 376 B | -| _PrimitiveShortSerialize | JsonNet | 528.23 ns | NA | 8 B | 0.4768 | 0.0010 | - | 2,992 B | -| _PrimitiveShortSerialize | BinaryFormatter | 1,404.88 ns | NA | 52 B | 0.4883 | 0.0038 | - | 3,072 B | -| _PrimitiveShortSerialize | DataContract | 722.85 ns | NA | 80 B | 0.2728 | - | - | 1,712 B | -| _PrimitiveShortSerialize | Hyperion | 156.32 ns | NA | 3 B | 0.0789 | - | - | 496 B | -| _PrimitiveShortSerialize | Jil | 108.55 ns | NA | 5 B | 0.0421 | - | - | 264 B | -| _PrimitiveShortSerialize | SpanJson | 72.73 ns | NA | 5 B | 0.0050 | - | - | 32 B | -| _PrimitiveShortSerialize | UTF8Json | 45.00 ns | NA | 5 B | 0.0051 | - | - | 32 B | -| _PrimitiveShortSerialize | FsPickler | 590.47 ns | NA | 26 B | 0.1760 | - | - | 1,104 B | -| _PrimitiveShortSerialize | Ceras | 361.85 ns | NA | 2 B | 0.6614 | - | - | 4,152 B | -| _PrimitiveShortSerialize | OdinSerializer_ | 310.20 ns | NA | 3 B | 0.0048 | - | - | 32 B | -| _PrimitiveShortSerialize | Nino_Zlib | 117.04 ns | NA | 2 B | 0.0050 | - | - | 32 B | -| _PrimitiveShortSerialize | Nino_NoComp | 119.09 ns | NA | 2 B | 0.0050 | - | - | 32 B | -| **_PrimitiveStringDeserialize** | **MessagePack_Lz4** | **941.14 ns** | **NA** | **-** | **0.0458** | **-** | **-** | **288 B** | -| _PrimitiveStringDeserialize | MessagePack_NoComp | 219.75 ns | NA | - | 0.0353 | - | - | 224 B | -| _PrimitiveStringDeserialize | ProtobufNet | 553.94 ns | NA | - | 0.0496 | - | - | 312 B | -| _PrimitiveStringDeserialize | JsonNet | 1,501.53 ns | NA | - | 0.9384 | 0.0114 | - | 5,896 B | -| _PrimitiveStringDeserialize | BinaryFormatter | 1,113.69 ns | NA | - | 0.4063 | 0.0019 | - | 2,560 B | -| _PrimitiveStringDeserialize | DataContract | 2,620.38 ns | NA | - | 0.7401 | 0.0076 | - | 4,664 B | -| _PrimitiveStringDeserialize | Hyperion | 237.31 ns | NA | - | 0.0825 | - | - | 520 B | -| _PrimitiveStringDeserialize | Jil | 603.66 ns | NA | - | 0.1326 | - | - | 832 B | -| _PrimitiveStringDeserialize | SpanJson | 283.40 ns | NA | - | 0.0353 | - | - | 224 B | -| _PrimitiveStringDeserialize | UTF8Json | 475.72 ns | NA | - | 0.0353 | - | - | 224 B | -| _PrimitiveStringDeserialize | FsPickler | 761.37 ns | NA | - | 0.1974 | - | - | 1,240 B | -| _PrimitiveStringDeserialize | Ceras | 238.95 ns | NA | - | 0.0353 | - | - | 224 B | -| _PrimitiveStringDeserialize | OdinSerializer_ | 542.05 ns | NA | - | 0.0353 | - | - | 224 B | -| _PrimitiveStringDeserialize | Nino_Zlib | 21,192.86 ns | NA | - | 0.0305 | - | - | 296 B | -| _PrimitiveStringDeserialize | Nino_NoComp | 265.80 ns | NA | - | 0.0353 | - | - | 224 B | -| **_PrimitiveStringSerialize** | **MessagePack_Lz4** | **855.98 ns** | **NA** | **21 B** | **0.0172** | **-** | **-** | **112 B** | -| _PrimitiveStringSerialize | MessagePack_NoComp | 202.66 ns | NA | 102 B | 0.0203 | - | - | 128 B | -| _PrimitiveStringSerialize | ProtobufNet | 476.26 ns | NA | 102 B | 0.0744 | - | - | 472 B | -| _PrimitiveStringSerialize | JsonNet | 1,044.86 ns | NA | 105 B | 0.4883 | 0.0019 | - | 3,072 B | -| _PrimitiveStringSerialize | BinaryFormatter | 1,496.46 ns | NA | 124 B | 0.3910 | 0.0019 | - | 2,464 B | -| _PrimitiveStringSerialize | DataContract | 1,400.38 ns | NA | 177 B | 0.2842 | - | - | 1,792 B | -| _PrimitiveStringSerialize | Hyperion | 365.16 ns | NA | 102 B | 0.1106 | - | - | 696 B | -| _PrimitiveStringSerialize | Jil | 1,176.22 ns | NA | 102 B | 0.1431 | - | - | 904 B | -| _PrimitiveStringSerialize | SpanJson | 470.14 ns | NA | 102 B | 0.0200 | - | - | 128 B | -| _PrimitiveStringSerialize | UTF8Json | 302.70 ns | NA | 102 B | 0.0200 | - | - | 128 B | -| _PrimitiveStringSerialize | FsPickler | 921.01 ns | NA | 127 B | 0.1907 | - | - | 1,200 B | -| _PrimitiveStringSerialize | Ceras | 674.61 ns | NA | 101 B | 0.6762 | - | - | 4,248 B | -| _PrimitiveStringSerialize | OdinSerializer_ | 602.30 ns | NA | 206 B | 0.0362 | - | - | 232 B | -| _PrimitiveStringSerialize | Nino_Zlib | 8,281.73 ns | NA | 9 B | - | - | - | 72 B | -| _PrimitiveStringSerialize | Nino_NoComp | 348.39 ns | NA | 203 B | 0.0367 | - | - | 232 B | -| **_PrimitiveUIntDeserialize** | **MessagePack_Lz4** | **222.22 ns** | **NA** | **-** | **0.0100** | **-** | **-** | **64 B** | -| _PrimitiveUIntDeserialize | MessagePack_NoComp | 96.65 ns | NA | - | - | - | - | - | -| _PrimitiveUIntDeserialize | ProtobufNet | 419.57 ns | NA | - | 0.0138 | - | - | 88 B | -| _PrimitiveUIntDeserialize | JsonNet | 1,114.16 ns | NA | - | 0.9079 | 0.0057 | - | 5,696 B | -| _PrimitiveUIntDeserialize | BinaryFormatter | 2,956.81 ns | NA | - | 0.6561 | 0.0038 | - | 4,120 B | -| _PrimitiveUIntDeserialize | DataContract | 2,104.80 ns | NA | - | 0.6561 | 0.0038 | - | 4,136 B | -| _PrimitiveUIntDeserialize | Hyperion | 112.56 ns | NA | - | 0.0305 | - | - | 192 B | -| _PrimitiveUIntDeserialize | Jil | 99.79 ns | NA | - | 0.0191 | - | - | 120 B | -| _PrimitiveUIntDeserialize | SpanJson | 26.91 ns | NA | - | - | - | - | - | -| _PrimitiveUIntDeserialize | UTF8Json | 37.32 ns | NA | - | - | - | - | - | -| _PrimitiveUIntDeserialize | FsPickler | 669.42 ns | NA | - | 0.1612 | - | - | 1,016 B | -| _PrimitiveUIntDeserialize | Ceras | 118.94 ns | NA | - | - | - | - | - | -| _PrimitiveUIntDeserialize | OdinSerializer_ | 474.02 ns | NA | - | - | - | - | - | -| _PrimitiveUIntDeserialize | Nino_Zlib | 149.60 ns | NA | - | - | - | - | - | -| _PrimitiveUIntDeserialize | Nino_NoComp | 146.86 ns | NA | - | - | - | - | - | -| **_PrimitiveUIntSerialize** | **MessagePack_Lz4** | **108.71 ns** | **NA** | **1 B** | **0.0153** | **-** | **-** | **96 B** | -| _PrimitiveUIntSerialize | MessagePack_NoComp | 100.50 ns | NA | 1 B | 0.0050 | - | - | 32 B | -| _PrimitiveUIntSerialize | ProtobufNet | 242.37 ns | NA | 2 B | 0.0596 | - | - | 376 B | -| _PrimitiveUIntSerialize | JsonNet | 560.40 ns | NA | 4 B | 0.4616 | 0.0029 | - | 2,896 B | -| _PrimitiveUIntSerialize | BinaryFormatter | 1,756.38 ns | NA | 55 B | 0.4883 | 0.0038 | - | 3,072 B | -| _PrimitiveUIntSerialize | DataContract | 792.58 ns | NA | 88 B | 0.2737 | - | - | 1,720 B | -| _PrimitiveUIntSerialize | Hyperion | 200.97 ns | NA | 5 B | 0.0789 | - | - | 496 B | -| _PrimitiveUIntSerialize | Jil | 134.25 ns | NA | 1 B | 0.0408 | - | - | 256 B | -| _PrimitiveUIntSerialize | SpanJson | 69.38 ns | NA | 1 B | 0.0050 | - | - | 32 B | -| _PrimitiveUIntSerialize | UTF8Json | 48.79 ns | NA | 1 B | 0.0051 | - | - | 32 B | -| _PrimitiveUIntSerialize | FsPickler | 558.85 ns | NA | 29 B | 0.1755 | - | - | 1,104 B | -| _PrimitiveUIntSerialize | Ceras | 401.06 ns | NA | 1 B | 0.6614 | - | - | 4,152 B | -| _PrimitiveUIntSerialize | OdinSerializer_ | 379.91 ns | NA | 5 B | 0.0048 | - | - | 32 B | -| _PrimitiveUIntSerialize | Nino_Zlib | 152.39 ns | NA | 2 B | 0.0050 | - | - | 32 B | -| _PrimitiveUIntSerialize | Nino_NoComp | 150.21 ns | NA | 2 B | 0.0050 | - | - | 32 B | -| **_PrimitiveULongDeserialize** | **MessagePack_Lz4** | **217.94 ns** | **NA** | **-** | **0.0100** | **-** | **-** | **64 B** | -| _PrimitiveULongDeserialize | MessagePack_NoComp | 104.13 ns | NA | - | - | - | - | - | -| _PrimitiveULongDeserialize | ProtobufNet | 422.62 ns | NA | - | 0.0138 | - | - | 88 B | -| _PrimitiveULongDeserialize | JsonNet | 1,826.04 ns | NA | - | 0.9613 | 0.0114 | - | 6,032 B | -| _PrimitiveULongDeserialize | BinaryFormatter | 2,893.15 ns | NA | - | 0.6561 | 0.0038 | - | 4,120 B | -| _PrimitiveULongDeserialize | DataContract | 2,594.89 ns | NA | - | 0.6790 | 0.0076 | - | 4,264 B | -| _PrimitiveULongDeserialize | Hyperion | 126.66 ns | NA | - | 0.0305 | - | - | 192 B | -| _PrimitiveULongDeserialize | Jil | 176.79 ns | NA | - | 0.0253 | - | - | 160 B | -| _PrimitiveULongDeserialize | SpanJson | 94.04 ns | NA | - | - | - | - | - | -| _PrimitiveULongDeserialize | UTF8Json | 95.72 ns | NA | - | - | - | - | - | -| _PrimitiveULongDeserialize | FsPickler | 633.73 ns | NA | - | 0.1612 | - | - | 1,016 B | -| _PrimitiveULongDeserialize | Ceras | 114.95 ns | NA | - | - | - | - | - | -| _PrimitiveULongDeserialize | OdinSerializer_ | 490.62 ns | NA | - | - | - | - | - | -| _PrimitiveULongDeserialize | Nino_Zlib | 161.00 ns | NA | - | - | - | - | - | -| _PrimitiveULongDeserialize | Nino_NoComp | 148.49 ns | NA | - | - | - | - | - | -| **_PrimitiveULongSerialize** | **MessagePack_Lz4** | **129.70 ns** | **NA** | **9 B** | **0.0165** | **-** | **-** | **104 B** | -| _PrimitiveULongSerialize | MessagePack_NoComp | 113.44 ns | NA | 9 B | 0.0063 | - | - | 40 B | -| _PrimitiveULongSerialize | ProtobufNet | 284.05 ns | NA | 11 B | 0.0610 | - | - | 384 B | -| _PrimitiveULongSerialize | JsonNet | 776.96 ns | NA | 23 B | 0.4787 | 0.0038 | - | 3,008 B | -| _PrimitiveULongSerialize | BinaryFormatter | 2,086.13 ns | NA | 59 B | 0.4883 | 0.0038 | - | 3,080 B | -| _PrimitiveULongSerialize | DataContract | 1,001.41 ns | NA | 109 B | 0.2880 | - | - | 1,808 B | -| _PrimitiveULongSerialize | Hyperion | 234.26 ns | NA | 9 B | 0.0801 | - | - | 504 B | -| _PrimitiveULongSerialize | Jil | 249.99 ns | NA | 20 B | 0.0663 | - | - | 416 B | -| _PrimitiveULongSerialize | SpanJson | 135.41 ns | NA | 20 B | 0.0076 | - | - | 48 B | -| _PrimitiveULongSerialize | UTF8Json | 122.67 ns | NA | 20 B | 0.0076 | - | - | 48 B | -| _PrimitiveULongSerialize | FsPickler | 639.48 ns | NA | 33 B | 0.1764 | - | - | 1,112 B | -| _PrimitiveULongSerialize | Ceras | 458.00 ns | NA | 8 B | 0.6614 | - | - | 4,152 B | -| _PrimitiveULongSerialize | OdinSerializer_ | 429.83 ns | NA | 9 B | 0.0062 | - | - | 40 B | -| _PrimitiveULongSerialize | Nino_Zlib | 175.49 ns | NA | 9 B | 0.0062 | - | - | 40 B | -| _PrimitiveULongSerialize | Nino_NoComp | 169.52 ns | NA | 9 B | 0.0062 | - | - | 40 B | -| **_PrimitiveUShortDeserialize** | **MessagePack_Lz4** | **242.71 ns** | **NA** | **-** | **0.0100** | **-** | **-** | **64 B** | -| _PrimitiveUShortDeserialize | MessagePack_NoComp | 111.88 ns | NA | - | - | - | - | - | -| _PrimitiveUShortDeserialize | ProtobufNet | 427.94 ns | NA | - | 0.0138 | - | - | 88 B | -| _PrimitiveUShortDeserialize | JsonNet | 1,291.07 ns | NA | - | 0.9098 | 0.0057 | - | 5,720 B | -| _PrimitiveUShortDeserialize | BinaryFormatter | 3,044.84 ns | NA | - | 0.6561 | 0.0038 | - | 4,120 B | -| _PrimitiveUShortDeserialize | DataContract | 2,183.97 ns | NA | - | 0.6561 | 0.0038 | - | 4,136 B | -| _PrimitiveUShortDeserialize | Hyperion | 119.12 ns | NA | - | 0.0305 | - | - | 192 B | -| _PrimitiveUShortDeserialize | Jil | 114.56 ns | NA | - | 0.0204 | - | - | 128 B | -| _PrimitiveUShortDeserialize | SpanJson | 49.52 ns | NA | - | - | - | - | - | -| _PrimitiveUShortDeserialize | UTF8Json | 48.66 ns | NA | - | - | - | - | - | -| _PrimitiveUShortDeserialize | FsPickler | 639.76 ns | NA | - | 0.1612 | - | - | 1,016 B | -| _PrimitiveUShortDeserialize | Ceras | 109.37 ns | NA | - | - | - | - | - | -| _PrimitiveUShortDeserialize | OdinSerializer_ | 484.77 ns | NA | - | - | - | - | - | -| _PrimitiveUShortDeserialize | Nino_Zlib | 150.96 ns | NA | - | - | - | - | - | -| _PrimitiveUShortDeserialize | Nino_NoComp | 155.35 ns | NA | - | - | - | - | - | -| **_PrimitiveUShortSerialize** | **MessagePack_Lz4** | **107.21 ns** | **NA** | **3 B** | **0.0153** | **-** | **-** | **96 B** | -| _PrimitiveUShortSerialize | MessagePack_NoComp | 86.41 ns | NA | 3 B | 0.0050 | - | - | 32 B | -| _PrimitiveUShortSerialize | ProtobufNet | 220.36 ns | NA | 4 B | 0.0598 | - | - | 376 B | -| _PrimitiveUShortSerialize | JsonNet | 541.51 ns | NA | 8 B | 0.4768 | 0.0010 | - | 2,992 B | -| _PrimitiveUShortSerialize | BinaryFormatter | 1,578.58 ns | NA | 53 B | 0.4883 | 0.0038 | - | 3,072 B | -| _PrimitiveUShortSerialize | DataContract | 755.19 ns | NA | 96 B | 0.2747 | - | - | 1,728 B | -| _PrimitiveUShortSerialize | Hyperion | 184.83 ns | NA | 3 B | 0.0789 | - | - | 496 B | -| _PrimitiveUShortSerialize | Jil | 124.34 ns | NA | 5 B | 0.0420 | - | - | 264 B | -| _PrimitiveUShortSerialize | SpanJson | 75.39 ns | NA | 5 B | 0.0050 | - | - | 32 B | -| _PrimitiveUShortSerialize | UTF8Json | 55.81 ns | NA | 5 B | 0.0050 | - | - | 32 B | -| _PrimitiveUShortSerialize | FsPickler | 523.38 ns | NA | 27 B | 0.1755 | - | - | 1,104 B | -| _PrimitiveUShortSerialize | Ceras | 399.69 ns | NA | 2 B | 0.6614 | - | - | 4,152 B | -| _PrimitiveUShortSerialize | OdinSerializer_ | 351.97 ns | NA | 3 B | 0.0048 | - | - | 32 B | -| _PrimitiveUShortSerialize | Nino_Zlib | 143.31 ns | NA | 2 B | 0.0050 | - | - | 32 B | -| _PrimitiveUShortSerialize | Nino_NoComp | 144.99 ns | NA | 2 B | 0.0050 | - | - | 32 B | -| **AccessTokenDeserialize** | **MessagePack_Lz4** | **421.48 ns** | **NA** | **-** | **0.0176** | **-** | **-** | **112 B** | -| AccessTokenDeserialize | MessagePack_NoComp | 274.66 ns | NA | - | 0.0076 | - | - | 48 B | -| AccessTokenDeserialize | ProtobufNet | 626.16 ns | NA | - | 0.0210 | - | - | 136 B | -| AccessTokenDeserialize | JsonNet | 3,042.56 ns | NA | - | 0.9193 | 0.0076 | - | 5,768 B | -| AccessTokenDeserialize | BinaryFormatter | 4,737.86 ns | NA | - | 0.8316 | 0.0076 | - | 5,240 B | -| AccessTokenDeserialize | DataContract | 6,715.16 ns | NA | - | 1.3733 | 0.0153 | - | 8,632 B | -| AccessTokenDeserialize | Hyperion | 570.14 ns | NA | - | 0.0706 | - | - | 448 B | -| AccessTokenDeserialize | Jil | 589.09 ns | NA | - | 0.0515 | - | - | 328 B | -| AccessTokenDeserialize | SpanJson | 232.51 ns | NA | - | 0.0076 | - | - | 48 B | -| AccessTokenDeserialize | UTF8Json | 490.31 ns | NA | - | 0.0076 | - | - | 48 B | -| AccessTokenDeserialize | FsPickler | 867.72 ns | NA | - | 0.1974 | - | - | 1,240 B | -| AccessTokenDeserialize | Ceras | 383.26 ns | NA | - | 0.0076 | - | - | 48 B | -| AccessTokenDeserialize | OdinSerializer_ | 3,563.58 ns | NA | - | 0.0992 | - | - | 632 B | -| AccessTokenDeserialize | Nino_Zlib | 28,160.61 ns | NA | - | - | - | - | 112 B | -| AccessTokenDeserialize | Nino_NoComp | 242.91 ns | NA | - | 0.0076 | - | - | 48 B | -| **AccessTokenSerialize** | **MessagePack_Lz4** | **779.79 ns** | **NA** | **19 B** | **0.0172** | **-** | **-** | **112 B** | -| AccessTokenSerialize | MessagePack_NoComp | 279.68 ns | NA | 19 B | 0.0076 | - | - | 48 B | -| AccessTokenSerialize | ProtobufNet | 713.87 ns | NA | 6 B | 0.0591 | - | - | 376 B | -| AccessTokenSerialize | JsonNet | 2,280.40 ns | NA | 82 B | 0.4997 | - | - | 3,152 B | -| AccessTokenSerialize | BinaryFormatter | 6,540.13 ns | NA | 392 B | 0.7782 | 0.0076 | - | 4,888 B | -| AccessTokenSerialize | DataContract | 3,534.70 ns | NA | 333 B | 0.4272 | - | - | 2,680 B | -| AccessTokenSerialize | Hyperion | 515.55 ns | NA | 69 B | 0.1040 | - | - | 656 B | -| AccessTokenSerialize | Jil | 1,168.70 ns | NA | 80 B | 0.1469 | - | - | 928 B | -| AccessTokenSerialize | SpanJson | 264.01 ns | NA | 53 B | 0.0124 | - | - | 80 B | -| AccessTokenSerialize | UTF8Json | 433.28 ns | NA | 79 B | 0.0162 | - | - | 104 B | -| AccessTokenSerialize | FsPickler | 1,154.64 ns | NA | 67 B | 0.1907 | - | - | 1,200 B | -| AccessTokenSerialize | Ceras | 3,505.90 ns | NA | 12 B | 0.6599 | - | - | 4,160 B | -| AccessTokenSerialize | OdinSerializer_ | 4,889.66 ns | NA | 440 B | 0.0763 | - | - | 512 B | -| AccessTokenSerialize | Nino_Zlib | 7,560.32 ns | NA | 8 B | 0.0076 | - | - | 64 B | -| AccessTokenSerialize | Nino_NoComp | 318.75 ns | NA | 13 B | 0.0062 | - | - | 40 B | -| **AccountMergeDeserialize** | **MessagePack_Lz4** | **425.76 ns** | **NA** | **-** | **0.0153** | **-** | **-** | **96 B** | -| AccountMergeDeserialize | MessagePack_NoComp | 238.42 ns | NA | - | 0.0048 | - | - | 32 B | -| AccountMergeDeserialize | ProtobufNet | 666.40 ns | NA | - | 0.0191 | - | - | 120 B | -| AccountMergeDeserialize | JsonNet | 2,995.41 ns | NA | - | 0.9155 | 0.0076 | - | 5,752 B | -| AccountMergeDeserialize | BinaryFormatter | 4,906.26 ns | NA | - | 0.7706 | 0.0076 | - | 4,848 B | -| AccountMergeDeserialize | DataContract | 6,233.62 ns | NA | - | 1.9913 | 0.0534 | - | 12,536 B | -| AccountMergeDeserialize | Hyperion | 620.24 ns | NA | - | 0.0687 | - | - | 432 B | -| AccountMergeDeserialize | Jil | 558.99 ns | NA | - | 0.0467 | - | - | 296 B | -| AccountMergeDeserialize | SpanJson | 321.99 ns | NA | - | 0.0048 | - | - | 32 B | -| AccountMergeDeserialize | UTF8Json | 446.79 ns | NA | - | 0.0048 | - | - | 32 B | -| AccountMergeDeserialize | FsPickler | 847.69 ns | NA | - | 0.1955 | - | - | 1,232 B | -| AccountMergeDeserialize | Ceras | 349.59 ns | NA | - | 0.0048 | - | - | 32 B | -| AccountMergeDeserialize | OdinSerializer_ | 2,996.86 ns | NA | - | 0.0916 | - | - | 576 B | -| AccountMergeDeserialize | Nino_Zlib | 27,947.87 ns | NA | - | - | - | - | 96 B | -| AccountMergeDeserialize | Nino_NoComp | 214.83 ns | NA | - | 0.0050 | - | - | 32 B | -| **AccountMergeSerialize** | **MessagePack_Lz4** | **627.76 ns** | **NA** | **18 B** | **0.0172** | **-** | **-** | **112 B** | -| AccountMergeSerialize | MessagePack_NoComp | 207.28 ns | NA | 18 B | 0.0076 | - | - | 48 B | -| AccountMergeSerialize | ProtobufNet | 575.43 ns | NA | 6 B | 0.0591 | - | - | 376 B | -| AccountMergeSerialize | JsonNet | 1,736.21 ns | NA | 72 B | 0.5035 | 0.0019 | - | 3,160 B | -| AccountMergeSerialize | BinaryFormatter | 4,198.66 ns | NA | 250 B | 0.6104 | - | - | 3,872 B | -| AccountMergeSerialize | DataContract | 2,338.14 ns | NA | 253 B | 0.3929 | - | - | 2,472 B | -| AccountMergeSerialize | Hyperion | 411.39 ns | NA | 72 B | 0.0992 | - | - | 624 B | -| AccountMergeSerialize | Jil | 886.63 ns | NA | 70 B | 0.1144 | - | - | 720 B | -| AccountMergeSerialize | SpanJson | 228.71 ns | NA | 69 B | 0.0153 | - | - | 96 B | -| AccountMergeSerialize | UTF8Json | 315.70 ns | NA | 69 B | 0.0153 | - | - | 96 B | -| AccountMergeSerialize | FsPickler | 1,078.00 ns | NA | 67 B | 0.1907 | - | - | 1,200 B | -| AccountMergeSerialize | Ceras | 3,006.87 ns | NA | 11 B | 0.6599 | - | - | 4,160 B | -| AccountMergeSerialize | OdinSerializer_ | 3,885.62 ns | NA | 408 B | 0.0763 | - | - | 504 B | -| AccountMergeSerialize | Nino_Zlib | 7,221.10 ns | NA | 8 B | 0.0076 | - | - | 64 B | -| AccountMergeSerialize | Nino_NoComp | 277.90 ns | NA | 13 B | 0.0062 | - | - | 40 B | -| **AnswerDeserialize** | **MessagePack_Lz4** | **1,614.54 ns** | **NA** | **-** | **0.0324** | **-** | **-** | **208 B** | -| AnswerDeserialize | MessagePack_NoComp | 846.45 ns | NA | - | 0.0229 | - | - | 144 B | -| AnswerDeserialize | ProtobufNet | 1,172.98 ns | NA | - | 0.0362 | - | - | 232 B | -| AnswerDeserialize | JsonNet | 11,275.07 ns | NA | - | 0.9613 | - | - | 6,056 B | -| AnswerDeserialize | BinaryFormatter | 13,850.84 ns | NA | - | 1.3885 | 0.0153 | - | 8,784 B | -| AnswerDeserialize | DataContract | 17,463.89 ns | NA | - | 2.1057 | 0.0305 | - | 13,392 B | -| AnswerDeserialize | Hyperion | 853.29 ns | NA | - | 0.0849 | - | - | 536 B | -| AnswerDeserialize | Jil | 3,426.28 ns | NA | - | 0.1869 | - | - | 1,184 B | -| AnswerDeserialize | SpanJson | 1,262.68 ns | NA | - | 0.0229 | - | - | 144 B | -| AnswerDeserialize | UTF8Json | 2,312.79 ns | NA | - | 0.0229 | - | - | 144 B | -| AnswerDeserialize | FsPickler | 1,180.32 ns | NA | - | 0.2098 | - | - | 1,328 B | -| AnswerDeserialize | Ceras | 525.16 ns | NA | - | 0.0229 | - | - | 144 B | -| AnswerDeserialize | OdinSerializer_ | 10,864.35 ns | NA | - | 0.3815 | - | - | 2,416 B | -| AnswerDeserialize | Nino_Zlib | 25,319.28 ns | NA | - | 0.0305 | - | - | 216 B | -| AnswerDeserialize | Nino_NoComp | 332.02 ns | NA | - | 0.0229 | - | - | 144 B | -| **AnswerSerialize** | **MessagePack_Lz4** | **1,427.47 ns** | **NA** | **53 B** | **0.0229** | **-** | **-** | **144 B** | -| AnswerSerialize | MessagePack_NoComp | 597.94 ns | NA | 97 B | 0.0200 | - | - | 128 B | -| AnswerSerialize | ProtobufNet | 985.32 ns | NA | 30 B | 0.0629 | - | - | 400 B | -| AnswerSerialize | JsonNet | 6,272.99 ns | NA | 458 B | 1.1902 | 0.0153 | - | 7,480 B | -| AnswerSerialize | BinaryFormatter | 14,136.83 ns | NA | 1117 B | 1.6785 | 0.0458 | - | 10,552 B | -| AnswerSerialize | DataContract | 7,149.27 ns | NA | 883 B | 0.9155 | 0.0076 | - | 5,768 B | -| AnswerSerialize | Hyperion | 798.43 ns | NA | 129 B | 0.1345 | - | - | 848 B | -| AnswerSerialize | Jil | 3,293.21 ns | NA | 460 B | 0.4730 | - | - | 2,984 B | -| AnswerSerialize | SpanJson | 809.78 ns | NA | 353 B | 0.0610 | - | - | 384 B | -| AnswerSerialize | UTF8Json | 1,446.97 ns | NA | 455 B | 0.0763 | - | - | 480 B | -| AnswerSerialize | FsPickler | 1,454.39 ns | NA | 130 B | 0.2003 | - | - | 1,264 B | -| AnswerSerialize | Ceras | 2,945.60 ns | NA | 58 B | 0.6676 | - | - | 4,208 B | -| AnswerSerialize | OdinSerializer_ | 9,229.05 ns | NA | 1584 B | 0.3052 | - | - | 1,968 B | -| AnswerSerialize | Nino_Zlib | 7,715.57 ns | NA | 14 B | - | - | - | 72 B | -| AnswerSerialize | Nino_NoComp | 482.84 ns | NA | 64 B | 0.0134 | - | - | 88 B | -| **BadgeDeserialize** | **MessagePack_Lz4** | **455.06 ns** | **NA** | **-** | **0.0176** | **-** | **-** | **112 B** | -| BadgeDeserialize | MessagePack_NoComp | 312.77 ns | NA | - | 0.0076 | - | - | 48 B | -| BadgeDeserialize | ProtobufNet | 462.74 ns | NA | - | 0.0215 | - | - | 136 B | -| BadgeDeserialize | JsonNet | 3,398.97 ns | NA | - | 0.9079 | 0.0038 | - | 5,720 B | -| BadgeDeserialize | BinaryFormatter | 5,041.51 ns | NA | - | 0.8011 | 0.0076 | - | 5,072 B | -| BadgeDeserialize | DataContract | 6,171.20 ns | NA | - | 1.3351 | 0.0229 | - | 8,400 B | -| BadgeDeserialize | Hyperion | 538.43 ns | NA | - | 0.0696 | - | - | 440 B | -| BadgeDeserialize | Jil | 387.61 ns | NA | - | 0.0496 | - | - | 312 B | -| BadgeDeserialize | SpanJson | 165.97 ns | NA | - | 0.0076 | - | - | 48 B | -| BadgeDeserialize | UTF8Json | 384.26 ns | NA | - | 0.0076 | - | - | 48 B | -| BadgeDeserialize | FsPickler | 831.36 ns | NA | - | 0.1955 | - | - | 1,232 B | -| BadgeDeserialize | Ceras | 371.16 ns | NA | - | 0.0076 | - | - | 48 B | -| BadgeDeserialize | OdinSerializer_ | 3,030.07 ns | NA | - | 0.0877 | - | - | 568 B | -| BadgeDeserialize | Nino_Zlib | 27,013.11 ns | NA | - | - | - | - | 112 B | -| BadgeDeserialize | Nino_NoComp | 227.73 ns | NA | - | 0.0076 | - | - | 48 B | -| **BadgeSerialize** | **MessagePack_Lz4** | **657.35 ns** | **NA** | **9 B** | **0.0162** | **-** | **-** | **104 B** | -| BadgeSerialize | MessagePack_NoComp | 248.79 ns | NA | 9 B | 0.0062 | - | - | 40 B | -| BadgeSerialize | ProtobufNet | 332.90 ns | NA | 0 B | 0.0100 | - | - | 64 B | -| BadgeSerialize | JsonNet | 1,698.29 ns | NA | 74 B | 0.4845 | 0.0019 | - | 3,048 B | -| BadgeSerialize | BinaryFormatter | 4,346.21 ns | NA | 278 B | 0.7172 | 0.0076 | - | 4,504 B | -| BadgeSerialize | DataContract | 2,264.94 ns | NA | 250 B | 0.3357 | - | - | 2,120 B | -| BadgeSerialize | Hyperion | 421.76 ns | NA | 59 B | 0.1135 | - | - | 712 B | -| BadgeSerialize | Jil | 644.73 ns | NA | 71 B | 0.1440 | - | - | 904 B | -| BadgeSerialize | SpanJson | 142.45 ns | NA | 28 B | 0.0088 | - | - | 56 B | -| BadgeSerialize | UTF8Json | 176.76 ns | NA | 71 B | 0.0153 | - | - | 96 B | -| BadgeSerialize | FsPickler | 931.15 ns | NA | 54 B | 0.1879 | - | - | 1,184 B | -| BadgeSerialize | Ceras | 2,851.39 ns | NA | 6 B | 0.6599 | - | - | 4,152 B | -| BadgeSerialize | OdinSerializer_ | 4,006.35 ns | NA | 382 B | 0.0687 | - | - | 456 B | -| BadgeSerialize | Nino_Zlib | 6,540.39 ns | NA | 8 B | 0.0076 | - | - | 64 B | -| BadgeSerialize | Nino_NoComp | 282.47 ns | NA | 8 B | 0.0048 | - | - | 32 B | -| **CommentDeserialize** | **MessagePack_Lz4** | **581.24 ns** | **NA** | **-** | **0.0200** | **-** | **-** | **128 B** | -| CommentDeserialize | MessagePack_NoComp | 431.68 ns | NA | - | 0.0100 | - | - | 64 B | -| CommentDeserialize | ProtobufNet | 620.94 ns | NA | - | 0.0238 | - | - | 152 B | -| CommentDeserialize | JsonNet | 5,062.82 ns | NA | - | 0.9155 | - | - | 5,784 B | -| CommentDeserialize | BinaryFormatter | 7,918.69 ns | NA | - | 0.9155 | - | - | 5,832 B | -| CommentDeserialize | DataContract | 9,067.15 ns | NA | - | 2.0142 | 0.0458 | - | 12,728 B | -| CommentDeserialize | Hyperion | 600.20 ns | NA | - | 0.0725 | - | - | 456 B | -| CommentDeserialize | Jil | 881.82 ns | NA | - | 0.0763 | - | - | 480 B | -| CommentDeserialize | SpanJson | 419.11 ns | NA | - | 0.0100 | - | - | 64 B | -| CommentDeserialize | UTF8Json | 775.36 ns | NA | - | 0.0095 | - | - | 64 B | -| CommentDeserialize | FsPickler | 899.46 ns | NA | - | 0.1984 | - | - | 1,248 B | -| CommentDeserialize | Ceras | 392.30 ns | NA | - | 0.0100 | - | - | 64 B | -| CommentDeserialize | OdinSerializer_ | 4,992.43 ns | NA | - | 0.1678 | - | - | 1,080 B | -| CommentDeserialize | Nino_Zlib | 27,036.60 ns | NA | - | - | - | - | 136 B | -| CommentDeserialize | Nino_NoComp | 245.21 ns | NA | - | 0.0100 | - | - | 64 B | -| **CommentSerialize** | **MessagePack_Lz4** | **738.03 ns** | **NA** | **27 B** | **0.0191** | **-** | **-** | **120 B** | -| CommentSerialize | MessagePack_NoComp | 314.42 ns | NA | 27 B | 0.0086 | - | - | 56 B | -| CommentSerialize | ProtobufNet | 552.27 ns | NA | 6 B | 0.0591 | - | - | 376 B | -| CommentSerialize | JsonNet | 2,723.65 ns | NA | 151 B | 0.5264 | 0.0038 | - | 3,312 B | -| CommentSerialize | BinaryFormatter | 6,683.07 ns | NA | 403 B | 0.7935 | 0.0076 | - | 5,016 B | -| CommentSerialize | DataContract | 3,265.22 ns | NA | 361 B | 0.4272 | - | - | 2,696 B | -| CommentSerialize | Hyperion | 495.14 ns | NA | 76 B | 0.1154 | - | - | 728 B | -| CommentSerialize | Jil | 1,130.93 ns | NA | 149 B | 0.1888 | - | - | 1,192 B | -| CommentSerialize | SpanJson | 267.51 ns | NA | 104 B | 0.0200 | - | - | 128 B | -| CommentSerialize | UTF8Json | 437.83 ns | NA | 148 B | 0.0277 | - | - | 176 B | -| CommentSerialize | FsPickler | 1,072.74 ns | NA | 71 B | 0.1907 | - | - | 1,200 B | -| CommentSerialize | Ceras | 2,850.17 ns | NA | 17 B | 0.6638 | - | - | 4,168 B | -| CommentSerialize | OdinSerializer_ | 5,334.21 ns | NA | 708 B | 0.1373 | - | - | 880 B | -| CommentSerialize | Nino_Zlib | 7,009.99 ns | NA | 10 B | 0.0076 | - | - | 72 B | -| CommentSerialize | Nino_NoComp | 316.11 ns | NA | 20 B | 0.0076 | - | - | 48 B | -| **NestedDataDeserialize** | **MessagePack_Lz4** | **5,955,406.29 ns** | **NA** | **-** | **367.1875** | **281.2500** | **140.6250** | **2,030,432 B** | -| NestedDataDeserialize | MessagePack_NoComp | 5,701,349.30 ns | NA | - | 226.5625 | 109.3750 | - | 1,440,094 B | -| NestedDataDeserialize | ProtobufNet | 5,934,018.99 ns | NA | - | 226.5625 | 109.3750 | - | 1,442,234 B | -| NestedDataDeserialize | JsonNet | 47,828,036.45 ns | NA | - | 636.3636 | 181.8182 | - | 4,668,442 B | -| NestedDataDeserialize | BinaryFormatter | 80,521,508.29 ns | NA | - | 2428.5714 | 1142.8571 | 428.5714 | 13,916,781 B | -| NestedDataDeserialize | DataContract | 49,279,548.91 ns | NA | - | 454.5455 | 181.8182 | - | 3,075,429 B | -| NestedDataDeserialize | Hyperion | 7,032,226.12 ns | NA | - | 375.0000 | 187.5000 | - | 2,401,190 B | -| NestedDataDeserialize | Jil | 18,638,147.09 ns | NA | - | 593.7500 | 468.7500 | 250.0000 | 5,283,266 B | -| NestedDataDeserialize | SpanJson | 9,692,929.92 ns | NA | - | 218.7500 | 109.3750 | - | 1,444,204 B | -| NestedDataDeserialize | UTF8Json | 18,934,927.81 ns | NA | - | 343.7500 | 125.0000 | 31.2500 | 2,121,539 B | -| NestedDataDeserialize | FsPickler | 5,792,169.12 ns | NA | - | 437.5000 | 351.5625 | 179.6875 | 2,383,467 B | -| NestedDataDeserialize | Ceras | 3,525,483.38 ns | NA | - | 226.5625 | 113.2813 | - | 1,440,091 B | -| NestedDataDeserialize | OdinSerializer_ | 49,474,874.45 ns | NA | - | 1090.9091 | 454.5455 | 181.8182 | 8,104,806 B | -| NestedDataDeserialize | Nino_Zlib | 2,998,791.60 ns | NA | - | 226.5625 | 113.2813 | - | 1,443,155 B | -| NestedDataDeserialize | Nino_NoComp | 2,342,892.74 ns | NA | - | 226.5625 | 113.2813 | - | 1,440,091 B | -| **NestedDataSerialize** | **MessagePack_Lz4** | **3,026,814.81 ns** | **NA** | **2383 B** | **-** | **-** | **-** | **6,609 B** | -| NestedDataSerialize | MessagePack_NoComp | 3,005,729.12 ns | NA | 590010 B | 136.7188 | 136.7188 | 136.7188 | 590,132 B | -| NestedDataSerialize | ProtobufNet | 5,107,883.46 ns | NA | 630006 B | 515.6250 | 500.0000 | 500.0000 | 2,708,899 B | -| NestedDataSerialize | JsonNet | 31,175,129.78 ns | NA | 1220025 B | 1281.2500 | 750.0000 | 750.0000 | 8,633,922 B | -| NestedDataSerialize | BinaryFormatter | 52,344,957.10 ns | NA | 890394 B | 1800.0000 | 900.0000 | 900.0000 | 10,688,969 B | -| NestedDataSerialize | DataContract | 25,796,990.48 ns | NA | 1520173 B | 843.7500 | 593.7500 | 593.7500 | 6,978,066 B | -| NestedDataSerialize | Hyperion | 6,917,247.12 ns | NA | 710203 B | 742.1875 | 570.3125 | 570.3125 | 3,769,472 B | -| NestedDataSerialize | Jil | 15,173,997.57 ns | NA | 1310022 B | 1187.5000 | 921.8750 | 546.8750 | 8,007,938 B | -| NestedDataSerialize | SpanJson | 10,628,000.64 ns | NA | 1310022 B | 187.5000 | 187.5000 | 187.5000 | 1,342,951 B | -| NestedDataSerialize | UTF8Json | 14,443,581.85 ns | NA | 1310022 B | 843.7500 | 703.1250 | 703.1250 | 6,255,081 B | -| NestedDataSerialize | FsPickler | 6,138,351.23 ns | NA | 690066 B | 742.1875 | 703.1250 | 687.5000 | 3,819,804 B | -| NestedDataSerialize | Ceras | 2,811,484.57 ns | NA | 650009 B | 480.4688 | 460.9375 | 460.9375 | 2,736,927 B | -| NestedDataSerialize | OdinSerializer_ | 30,184,617.06 ns | NA | 1910351 B | 937.5000 | 562.5000 | 562.5000 | 10,876,392 B | -| NestedDataSerialize | Nino_Zlib | 5,436,515.48 ns | NA | 3006 B | - | - | - | 3,076 B | -| NestedDataSerialize | Nino_NoComp | 2,197,140.24 ns | NA | 860016 B | 183.5938 | 183.5938 | 183.5938 | 860,165 B | +| Method | Serializer | Mean | Error | DataSize | Gen 0 | Gen 1 | Gen 2 | Allocated | +| --------------------------------- | ------------------- | ------------------: | -----: | ---------: | -----------: | -----------: | -----------: | ------------: | +| **_PrimitiveBoolDeserialize** | **MessagePack_Lz4** | **262.17 ns** | **NA** | **-** | **0.0100** | **-** | **-** | **64 B** | +| _PrimitiveBoolDeserialize | MessagePack_NoComp | 108.33 ns | NA | - | - | - | - | - | +| _PrimitiveBoolDeserialize | ProtobufNet | 437.98 ns | NA | - | 0.0138 | - | - | 88 B | +| _PrimitiveBoolDeserialize | JsonNet | 1,216.66 ns | NA | - | 0.9041 | 0.0057 | - | 5,672 B | +| _PrimitiveBoolDeserialize | BinaryFormatter | 3,140.05 ns | NA | - | 0.6561 | 0.0038 | - | 4,128 B | +| _PrimitiveBoolDeserialize | DataContract | 2,193.95 ns | NA | - | 0.6638 | 0.0076 | - | 4,168 B | +| _PrimitiveBoolDeserialize | Hyperion | 95.48 ns | NA | - | 0.0305 | - | - | 192 B | +| _PrimitiveBoolDeserialize | Jil | 92.74 ns | NA | - | 0.0204 | - | - | 128 B | +| _PrimitiveBoolDeserialize | SpanJson | 20.85 ns | NA | - | - | - | - | - | +| _PrimitiveBoolDeserialize | UTF8Json | 34.63 ns | NA | - | - | - | - | - | +| _PrimitiveBoolDeserialize | FsPickler | 503.17 ns | NA | - | 0.1631 | - | - | 1,024 B | +| _PrimitiveBoolDeserialize | Ceras | 87.45 ns | NA | - | - | - | - | - | +| _PrimitiveBoolDeserialize | OdinSerializer_ | 353.01 ns | NA | - | - | - | - | - | +| _PrimitiveBoolDeserialize | Nino | 86.40 ns | NA | - | - | - | - | - | +| **_PrimitiveBoolSerialize** | **MessagePack_Lz4** | **126.90 ns** | **NA** | **1 B** | **0.0153** | **-** | **-** | **96 B** | +| _PrimitiveBoolSerialize | MessagePack_NoComp | 112.23 ns | NA | 1 B | 0.0050 | - | - | 32 B | +| _PrimitiveBoolSerialize | ProtobufNet | 270.50 ns | NA | 2 B | 0.0596 | - | - | 376 B | +| _PrimitiveBoolSerialize | JsonNet | 661.18 ns | NA | 8 B | 0.4616 | 0.0019 | - | 2,896 B | +| _PrimitiveBoolSerialize | BinaryFormatter | 1,901.34 ns | NA | 53 B | 0.4883 | 0.0038 | - | 3,072 B | +| _PrimitiveBoolSerialize | DataContract | 827.86 ns | NA | 84 B | 0.2737 | - | - | 1,720 B | +| _PrimitiveBoolSerialize | Hyperion | 180.55 ns | NA | 2 B | 0.0789 | - | - | 496 B | +| _PrimitiveBoolSerialize | Jil | 110.33 ns | NA | 5 B | 0.0267 | - | - | 168 B | +| _PrimitiveBoolSerialize | SpanJson | 64.60 ns | NA | 5 B | 0.0050 | - | - | 32 B | +| _PrimitiveBoolSerialize | UTF8Json | 44.52 ns | NA | 5 B | 0.0051 | - | - | 32 B | +| _PrimitiveBoolSerialize | FsPickler | 472.89 ns | NA | 27 B | 0.1760 | - | - | 1,104 B | +| _PrimitiveBoolSerialize | Ceras | 349.18 ns | NA | 1 B | 0.6614 | - | - | 4,152 B | +| _PrimitiveBoolSerialize | OdinSerializer_ | 316.79 ns | NA | 2 B | 0.0048 | - | - | 32 B | +| _PrimitiveBoolSerialize | Nino | 146.27 ns | NA | 1 B | 0.0050 | - | - | 32 B | +| **_PrimitiveByteDeserialize** | **MessagePack_Lz4** | **173.70 ns** | **NA** | **-** | **0.0100** | **-** | **-** | **64 B** | +| _PrimitiveByteDeserialize | MessagePack_NoComp | 76.77 ns | NA | - | - | - | - | - | +| _PrimitiveByteDeserialize | ProtobufNet | 324.39 ns | NA | - | 0.0138 | - | - | 88 B | +| _PrimitiveByteDeserialize | JsonNet | 901.83 ns | NA | - | 0.9108 | 0.0057 | - | 5,720 B | +| _PrimitiveByteDeserialize | BinaryFormatter | 2,311.94 ns | NA | - | 0.6561 | 0.0038 | - | 4,120 B | +| _PrimitiveByteDeserialize | DataContract | 1,811.74 ns | NA | - | 0.6580 | 0.0057 | - | 4,136 B | +| _PrimitiveByteDeserialize | Hyperion | 82.76 ns | NA | - | 0.0305 | - | - | 192 B | +| _PrimitiveByteDeserialize | Jil | 87.40 ns | NA | - | 0.0204 | - | - | 128 B | +| _PrimitiveByteDeserialize | SpanJson | 29.69 ns | NA | - | - | - | - | - | +| _PrimitiveByteDeserialize | UTF8Json | 42.17 ns | NA | - | - | - | - | - | +| _PrimitiveByteDeserialize | FsPickler | 510.09 ns | NA | - | 0.1612 | - | - | 1,016 B | +| _PrimitiveByteDeserialize | Ceras | 95.83 ns | NA | - | - | - | - | - | +| _PrimitiveByteDeserialize | OdinSerializer_ | 408.88 ns | NA | - | - | - | - | - | +| _PrimitiveByteDeserialize | Nino | 98.67 ns | NA | - | - | - | - | - | +| **_PrimitiveByteSerialize** | **MessagePack_Lz4** | **127.84 ns** | **NA** | **2 B** | **0.0153** | **-** | **-** | **96 B** | +| _PrimitiveByteSerialize | MessagePack_NoComp | 91.36 ns | NA | 2 B | 0.0050 | - | - | 32 B | +| _PrimitiveByteSerialize | ProtobufNet | 268.41 ns | NA | 3 B | 0.0596 | - | - | 376 B | +| _PrimitiveByteSerialize | JsonNet | 577.13 ns | NA | 6 B | 0.4768 | 0.0010 | - | 2,992 B | +| _PrimitiveByteSerialize | BinaryFormatter | 1,623.59 ns | NA | 50 B | 0.4883 | 0.0038 | - | 3,072 B | +| _PrimitiveByteSerialize | DataContract | 752.26 ns | NA | 92 B | 0.2747 | - | - | 1,728 B | +| _PrimitiveByteSerialize | Hyperion | 160.05 ns | NA | 2 B | 0.0789 | - | - | 496 B | +| _PrimitiveByteSerialize | Jil | 137.56 ns | NA | 3 B | 0.0420 | - | - | 264 B | +| _PrimitiveByteSerialize | SpanJson | 84.48 ns | NA | 3 B | 0.0050 | - | - | 32 B | +| _PrimitiveByteSerialize | UTF8Json | 45.01 ns | NA | 3 B | 0.0051 | - | - | 32 B | +| _PrimitiveByteSerialize | FsPickler | 493.11 ns | NA | 24 B | 0.1745 | - | - | 1,096 B | +| _PrimitiveByteSerialize | Ceras | 367.07 ns | NA | 1 B | 0.6614 | - | - | 4,152 B | +| _PrimitiveByteSerialize | OdinSerializer_ | 324.68 ns | NA | 2 B | 0.0048 | - | - | 32 B | +| _PrimitiveByteSerialize | Nino | 135.00 ns | NA | 1 B | 0.0050 | - | - | 32 B | +| **_PrimitiveCharDeserialize** | **MessagePack_Lz4** | **150.04 ns** | **NA** | **-** | **0.0100** | **-** | **-** | **64 B** | +| _PrimitiveCharDeserialize | MessagePack_NoComp | 69.56 ns | NA | - | - | - | - | - | +| _PrimitiveCharDeserialize | ProtobufNet | 312.59 ns | NA | - | 0.0138 | - | - | 88 B | +| _PrimitiveCharDeserialize | JsonNet | 762.04 ns | NA | - | 0.9117 | 0.0095 | - | 5,720 B | +| _PrimitiveCharDeserialize | BinaryFormatter | 2,261.20 ns | NA | - | 0.6561 | 0.0038 | - | 4,120 B | +| _PrimitiveCharDeserialize | DataContract | 1,441.26 ns | NA | - | 0.6580 | 0.0057 | - | 4,136 B | +| _PrimitiveCharDeserialize | Hyperion | 82.89 ns | NA | - | 0.0305 | - | - | 192 B | +| _PrimitiveCharDeserialize | Jil | 61.32 ns | NA | - | 0.0050 | - | - | 32 B | +| _PrimitiveCharDeserialize | SpanJson | 34.24 ns | NA | - | - | - | - | - | +| _PrimitiveCharDeserialize | UTF8Json | 72.87 ns | NA | - | 0.0038 | - | - | 24 B | +| _PrimitiveCharDeserialize | FsPickler | 495.26 ns | NA | - | 0.1612 | - | - | 1,016 B | +| _PrimitiveCharDeserialize | Ceras | 80.93 ns | NA | - | - | - | - | - | +| _PrimitiveCharDeserialize | OdinSerializer_ | 334.60 ns | NA | - | - | - | - | - | +| _PrimitiveCharDeserialize | Nino | 87.82 ns | NA | - | - | - | - | - | +| **_PrimitiveCharSerialize** | **MessagePack_Lz4** | **108.94 ns** | **NA** | **1 B** | **0.0153** | **-** | **-** | **96 B** | +| _PrimitiveCharSerialize | MessagePack_NoComp | 83.64 ns | NA | 1 B | 0.0050 | - | - | 32 B | +| _PrimitiveCharSerialize | ProtobufNet | 215.61 ns | NA | 2 B | 0.0598 | - | - | 376 B | +| _PrimitiveCharSerialize | JsonNet | 650.56 ns | NA | 6 B | 0.5169 | 0.0019 | - | 3,248 B | +| _PrimitiveCharSerialize | BinaryFormatter | 1,533.47 ns | NA | 50 B | 0.4883 | 0.0038 | - | 3,072 B | +| _PrimitiveCharSerialize | DataContract | 706.93 ns | NA | 75 B | 0.2728 | - | - | 1,712 B | +| _PrimitiveCharSerialize | Hyperion | 162.62 ns | NA | 3 B | 0.0789 | - | - | 496 B | +| _PrimitiveCharSerialize | Jil | 113.40 ns | NA | 3 B | 0.0267 | - | - | 168 B | +| _PrimitiveCharSerialize | SpanJson | 64.72 ns | NA | 3 B | 0.0050 | - | - | 32 B | +| _PrimitiveCharSerialize | UTF8Json | 87.20 ns | NA | 3 B | 0.0088 | - | - | 56 B | +| _PrimitiveCharSerialize | FsPickler | 477.69 ns | NA | 24 B | 0.1745 | - | - | 1,096 B | +| _PrimitiveCharSerialize | Ceras | 336.91 ns | NA | 2 B | 0.6614 | - | - | 4,152 B | +| _PrimitiveCharSerialize | OdinSerializer_ | 321.80 ns | NA | 3 B | 0.0048 | - | - | 32 B | +| _PrimitiveCharSerialize | Nino | 136.12 ns | NA | 2 B | 0.0050 | - | - | 32 B | +| **_PrimitiveDateTimeDeserialize** | **MessagePack_Lz4** | **197.56 ns** | **NA** | **-** | **0.0100** | **-** | **-** | **64 B** | +| _PrimitiveDateTimeDeserialize | MessagePack_NoComp | 84.56 ns | NA | - | - | - | - | - | +| _PrimitiveDateTimeDeserialize | ProtobufNet | 352.64 ns | NA | - | 0.0138 | - | - | 88 B | +| _PrimitiveDateTimeDeserialize | JsonNet | 1,044.40 ns | NA | - | 0.9098 | 0.0057 | - | 5,720 B | +| _PrimitiveDateTimeDeserialize | BinaryFormatter | 3,880.64 ns | NA | - | 0.9232 | 0.0076 | - | 5,801 B | +| _PrimitiveDateTimeDeserialize | DataContract | 1,819.97 ns | NA | - | 0.6828 | 0.0095 | - | 4,288 B | +| _PrimitiveDateTimeDeserialize | Hyperion | 93.05 ns | NA | - | 0.0305 | - | - | 192 B | +| _PrimitiveDateTimeDeserialize | Jil | 217.84 ns | NA | - | 0.0267 | - | - | 168 B | +| _PrimitiveDateTimeDeserialize | SpanJson | 295.83 ns | NA | - | - | - | - | - | +| _PrimitiveDateTimeDeserialize | UTF8Json | 235.23 ns | NA | - | - | - | - | - | +| _PrimitiveDateTimeDeserialize | FsPickler | 589.08 ns | NA | - | 0.1631 | - | - | 1,024 B | +| _PrimitiveDateTimeDeserialize | Ceras | 175.09 ns | NA | - | - | - | - | - | +| _PrimitiveDateTimeDeserialize | OdinSerializer_ | 706.02 ns | NA | - | 0.0162 | - | - | 104 B | +| _PrimitiveDateTimeDeserialize | Nino | 82.33 ns | NA | - | - | - | - | - | +| **_PrimitiveDateTimeSerialize** | **MessagePack_Lz4** | **558.48 ns** | **NA** | **6 B** | **0.0153** | **-** | **-** | **96 B** | +| _PrimitiveDateTimeSerialize | MessagePack_NoComp | 306.01 ns | NA | 6 B | 0.0048 | - | - | 32 B | +| _PrimitiveDateTimeSerialize | ProtobufNet | 302.47 ns | NA | 6 B | 0.0596 | - | - | 376 B | +| _PrimitiveDateTimeSerialize | JsonNet | 803.17 ns | NA | 30 B | 0.4807 | - | - | 3,016 B | +| _PrimitiveDateTimeSerialize | BinaryFormatter | 2,012.68 ns | NA | 78 B | 0.5798 | 0.0038 | - | 3,656 B | +| _PrimitiveDateTimeSerialize | DataContract | 1,145.24 ns | NA | 106 B | 0.3414 | - | - | 2,144 B | +| _PrimitiveDateTimeSerialize | Hyperion | 171.93 ns | NA | 10 B | 0.0801 | - | - | 504 B | +| _PrimitiveDateTimeSerialize | Jil | 447.85 ns | NA | 22 B | 0.0672 | - | - | 424 B | +| _PrimitiveDateTimeSerialize | SpanJson | 316.81 ns | NA | 27 B | 0.0086 | - | - | 56 B | +| _PrimitiveDateTimeSerialize | UTF8Json | 374.99 ns | NA | 27 B | 0.0086 | - | - | 56 B | +| _PrimitiveDateTimeSerialize | FsPickler | 712.63 ns | NA | 44 B | 0.1783 | - | - | 1,120 B | +| _PrimitiveDateTimeSerialize | Ceras | 581.55 ns | NA | 8 B | 0.6609 | - | - | 4,152 B | +| _PrimitiveDateTimeSerialize | OdinSerializer_ | 694.13 ns | NA | 99 B | 0.0200 | - | - | 128 B | +| _PrimitiveDateTimeSerialize | Nino | 137.24 ns | NA | 8 B | 0.0050 | - | - | 32 B | +| **_PrimitiveIntDeserialize** | **MessagePack_Lz4** | **148.41 ns** | **NA** | **-** | **0.0100** | **-** | **-** | **64 B** | +| _PrimitiveIntDeserialize | MessagePack_NoComp | 76.11 ns | NA | - | - | - | - | - | +| _PrimitiveIntDeserialize | ProtobufNet | 324.10 ns | NA | - | 0.0138 | - | - | 88 B | +| _PrimitiveIntDeserialize | JsonNet | 842.86 ns | NA | - | 0.9079 | 0.0067 | - | 5,696 B | +| _PrimitiveIntDeserialize | BinaryFormatter | 2,035.29 ns | NA | - | 0.6561 | 0.0038 | - | 4,120 B | +| _PrimitiveIntDeserialize | DataContract | 1,449.67 ns | NA | - | 0.6580 | 0.0057 | - | 4,136 B | +| _PrimitiveIntDeserialize | Hyperion | 83.81 ns | NA | - | 0.0305 | - | - | 192 B | +| _PrimitiveIntDeserialize | Jil | 95.71 ns | NA | - | 0.0229 | - | - | 144 B | +| _PrimitiveIntDeserialize | SpanJson | 50.59 ns | NA | - | - | - | - | - | +| _PrimitiveIntDeserialize | UTF8Json | 46.04 ns | NA | - | - | - | - | - | +| _PrimitiveIntDeserialize | FsPickler | 472.08 ns | NA | - | 0.1612 | - | - | 1,016 B | +| _PrimitiveIntDeserialize | Ceras | 96.58 ns | NA | - | - | - | - | - | +| _PrimitiveIntDeserialize | OdinSerializer_ | 410.72 ns | NA | - | - | - | - | - | +| _PrimitiveIntDeserialize | Nino | 107.12 ns | NA | - | - | - | - | - | +| **_PrimitiveIntSerialize** | **MessagePack_Lz4** | **408.25 ns** | **NA** | **5 B** | **0.0153** | **-** | **-** | **96 B** | +| _PrimitiveIntSerialize | MessagePack_NoComp | 333.21 ns | NA | 5 B | 0.0048 | - | - | 32 B | +| _PrimitiveIntSerialize | ProtobufNet | 778.21 ns | NA | 11 B | 0.0610 | - | - | 384 B | +| _PrimitiveIntSerialize | JsonNet | 2,366.20 ns | NA | 14 B | 0.4768 | - | - | 3,000 B | +| _PrimitiveIntSerialize | BinaryFormatter | 5,830.16 ns | NA | 54 B | 0.4883 | - | - | 3,072 B | +| _PrimitiveIntSerialize | DataContract | 2,536.22 ns | NA | 82 B | 0.2708 | - | - | 1,720 B | +| _PrimitiveIntSerialize | Hyperion | 549.32 ns | NA | 5 B | 0.0782 | - | - | 496 B | +| _PrimitiveIntSerialize | Jil | 501.79 ns | NA | 11 B | 0.0458 | - | - | 288 B | +| _PrimitiveIntSerialize | SpanJson | 633.02 ns | NA | 11 B | 0.0062 | - | - | 40 B | +| _PrimitiveIntSerialize | UTF8Json | 323.87 ns | NA | 11 B | 0.0062 | - | - | 40 B | +| _PrimitiveIntSerialize | FsPickler | 1,831.85 ns | NA | 28 B | 0.1755 | - | - | 1,104 B | +| _PrimitiveIntSerialize | Ceras | 1,389.47 ns | NA | 5 B | 0.6599 | - | - | 4,152 B | +| _PrimitiveIntSerialize | OdinSerializer_ | 1,497.75 ns | NA | 5 B | 0.0038 | - | - | 32 B | +| _PrimitiveIntSerialize | Nino | 507.27 ns | NA | 4 B | 0.0048 | - | - | 32 B | +| **_PrimitiveLongDeserialize** | **MessagePack_Lz4** | **191.03 ns** | **NA** | **-** | **0.0100** | **-** | **-** | **64 B** | +| _PrimitiveLongDeserialize | MessagePack_NoComp | 94.85 ns | NA | - | - | - | - | - | +| _PrimitiveLongDeserialize | ProtobufNet | 366.65 ns | NA | - | 0.0138 | - | - | 88 B | +| _PrimitiveLongDeserialize | JsonNet | 1,111.65 ns | NA | - | 0.9079 | 0.0057 | - | 5,696 B | +| _PrimitiveLongDeserialize | BinaryFormatter | 2,593.48 ns | NA | - | 0.6561 | 0.0038 | - | 4,120 B | +| _PrimitiveLongDeserialize | DataContract | 1,869.81 ns | NA | - | 0.6580 | 0.0057 | - | 4,136 B | +| _PrimitiveLongDeserialize | Hyperion | 106.53 ns | NA | - | 0.0305 | - | - | 192 B | +| _PrimitiveLongDeserialize | Jil | 136.81 ns | NA | - | 0.0253 | - | - | 160 B | +| _PrimitiveLongDeserialize | SpanJson | 71.58 ns | NA | - | - | - | - | - | +| _PrimitiveLongDeserialize | UTF8Json | 61.51 ns | NA | - | - | - | - | - | +| _PrimitiveLongDeserialize | FsPickler | 513.67 ns | NA | - | 0.1612 | - | - | 1,016 B | +| _PrimitiveLongDeserialize | Ceras | 91.18 ns | NA | - | - | - | - | - | +| _PrimitiveLongDeserialize | OdinSerializer_ | 382.98 ns | NA | - | - | - | - | - | +| _PrimitiveLongDeserialize | Nino | 99.65 ns | NA | - | - | - | - | - | +| **_PrimitiveLongSerialize** | **MessagePack_Lz4** | **458.17 ns** | **NA** | **9 B** | **0.0162** | **-** | **-** | **104 B** | +| _PrimitiveLongSerialize | MessagePack_NoComp | 218.31 ns | NA | 9 B | 0.0062 | - | - | 40 B | +| _PrimitiveLongSerialize | ProtobufNet | 256.52 ns | NA | 10 B | 0.0610 | - | - | 384 B | +| _PrimitiveLongSerialize | JsonNet | 838.98 ns | NA | 22 B | 0.4787 | 0.0038 | - | 3,008 B | +| _PrimitiveLongSerialize | BinaryFormatter | 1,825.85 ns | NA | 58 B | 0.4883 | 0.0038 | - | 3,080 B | +| _PrimitiveLongSerialize | DataContract | 900.76 ns | NA | 92 B | 0.2747 | - | - | 1,728 B | +| _PrimitiveLongSerialize | Hyperion | 244.66 ns | NA | 9 B | 0.0801 | - | - | 504 B | +| _PrimitiveLongSerialize | Jil | 272.82 ns | NA | 19 B | 0.0663 | - | - | 416 B | +| _PrimitiveLongSerialize | SpanJson | 214.51 ns | NA | 19 B | 0.0076 | - | - | 48 B | +| _PrimitiveLongSerialize | UTF8Json | 117.40 ns | NA | 19 B | 0.0076 | - | - | 48 B | +| _PrimitiveLongSerialize | FsPickler | 584.20 ns | NA | 32 B | 0.1755 | - | - | 1,104 B | +| _PrimitiveLongSerialize | Ceras | 434.96 ns | NA | 8 B | 0.6614 | - | - | 4,152 B | +| _PrimitiveLongSerialize | OdinSerializer_ | 405.56 ns | NA | 9 B | 0.0062 | - | - | 40 B | +| _PrimitiveLongSerialize | Nino | 150.53 ns | NA | 8 B | 0.0050 | - | - | 32 B | +| **_PrimitiveSByteDeserialize** | **MessagePack_Lz4** | **163.35 ns** | **NA** | **-** | **0.0100** | **-** | **-** | **64 B** | +| _PrimitiveSByteDeserialize | MessagePack_NoComp | 79.37 ns | NA | - | - | - | - | - | +| _PrimitiveSByteDeserialize | ProtobufNet | 292.83 ns | NA | - | 0.0138 | - | - | 88 B | +| _PrimitiveSByteDeserialize | JsonNet | 886.23 ns | NA | - | 0.9108 | 0.0057 | - | 5,720 B | +| _PrimitiveSByteDeserialize | BinaryFormatter | 2,111.91 ns | NA | - | 0.6561 | 0.0038 | - | 4,120 B | +| _PrimitiveSByteDeserialize | DataContract | 1,470.46 ns | NA | - | 0.6580 | 0.0057 | - | 4,136 B | +| _PrimitiveSByteDeserialize | Hyperion | 72.53 ns | NA | - | 0.0305 | - | - | 192 B | +| _PrimitiveSByteDeserialize | Jil | 77.67 ns | NA | - | 0.0204 | - | - | 128 B | +| _PrimitiveSByteDeserialize | SpanJson | 30.20 ns | NA | - | - | - | - | - | +| _PrimitiveSByteDeserialize | UTF8Json | 32.34 ns | NA | - | - | - | - | - | +| _PrimitiveSByteDeserialize | FsPickler | 454.18 ns | NA | - | 0.1616 | 0.0005 | - | 1,016 B | +| _PrimitiveSByteDeserialize | Ceras | 82.68 ns | NA | - | - | - | - | - | +| _PrimitiveSByteDeserialize | OdinSerializer_ | 334.05 ns | NA | - | - | - | - | - | +| _PrimitiveSByteDeserialize | Nino | 88.79 ns | NA | - | - | - | - | - | +| **_PrimitiveSByteSerialize** | **MessagePack_Lz4** | **90.83 ns** | **NA** | **2 B** | **0.0153** | **-** | **-** | **96 B** | +| _PrimitiveSByteSerialize | MessagePack_NoComp | 90.67 ns | NA | 2 B | 0.0050 | - | - | 32 B | +| _PrimitiveSByteSerialize | ProtobufNet | 223.00 ns | NA | 11 B | 0.0610 | - | - | 384 B | +| _PrimitiveSByteSerialize | JsonNet | 599.03 ns | NA | 7 B | 0.4768 | 0.0010 | - | 2,992 B | +| _PrimitiveSByteSerialize | BinaryFormatter | 1,410.25 ns | NA | 51 B | 0.4883 | 0.0038 | - | 3,072 B | +| _PrimitiveSByteSerialize | DataContract | 664.72 ns | NA | 77 B | 0.2728 | - | - | 1,712 B | +| _PrimitiveSByteSerialize | Hyperion | 152.05 ns | NA | 2 B | 0.0789 | - | - | 496 B | +| _PrimitiveSByteSerialize | Jil | 120.99 ns | NA | 4 B | 0.0420 | - | - | 264 B | +| _PrimitiveSByteSerialize | SpanJson | 70.48 ns | NA | 4 B | 0.0050 | - | - | 32 B | +| _PrimitiveSByteSerialize | UTF8Json | 47.41 ns | NA | 4 B | 0.0051 | - | - | 32 B | +| _PrimitiveSByteSerialize | FsPickler | 465.54 ns | NA | 25 B | 0.1760 | - | - | 1,104 B | +| _PrimitiveSByteSerialize | Ceras | 1,126.48 ns | NA | 1 B | 0.6614 | - | - | 4,152 B | +| _PrimitiveSByteSerialize | OdinSerializer_ | 331.74 ns | NA | 2 B | 0.0048 | - | - | 32 B | +| _PrimitiveSByteSerialize | Nino | 158.76 ns | NA | 1 B | 0.0050 | - | - | 32 B | +| **_PrimitiveShortDeserialize** | **MessagePack_Lz4** | **175.02 ns** | **NA** | **-** | **0.0100** | **-** | **-** | **64 B** | +| _PrimitiveShortDeserialize | MessagePack_NoComp | 79.92 ns | NA | - | - | - | - | - | +| _PrimitiveShortDeserialize | ProtobufNet | 334.96 ns | NA | - | 0.0138 | - | - | 88 B | +| _PrimitiveShortDeserialize | JsonNet | 912.80 ns | NA | - | 0.9108 | 0.0057 | - | 5,720 B | +| _PrimitiveShortDeserialize | BinaryFormatter | 2,267.03 ns | NA | - | 0.6561 | 0.0038 | - | 4,120 B | +| _PrimitiveShortDeserialize | DataContract | 1,482.83 ns | NA | - | 0.6580 | 0.0057 | - | 4,136 B | +| _PrimitiveShortDeserialize | Hyperion | 84.74 ns | NA | - | 0.0305 | - | - | 192 B | +| _PrimitiveShortDeserialize | Jil | 76.02 ns | NA | - | 0.0204 | - | - | 128 B | +| _PrimitiveShortDeserialize | SpanJson | 34.33 ns | NA | - | - | - | - | - | +| _PrimitiveShortDeserialize | UTF8Json | 32.36 ns | NA | - | - | - | - | - | +| _PrimitiveShortDeserialize | FsPickler | 430.14 ns | NA | - | 0.1616 | 0.0005 | - | 1,016 B | +| _PrimitiveShortDeserialize | Ceras | 75.62 ns | NA | - | - | - | - | - | +| _PrimitiveShortDeserialize | OdinSerializer_ | 310.98 ns | NA | - | - | - | - | - | +| _PrimitiveShortDeserialize | Nino | 81.78 ns | NA | - | - | - | - | - | +| **_PrimitiveShortSerialize** | **MessagePack_Lz4** | **117.52 ns** | **NA** | **3 B** | **0.0153** | **-** | **-** | **96 B** | +| _PrimitiveShortSerialize | MessagePack_NoComp | 112.40 ns | NA | 3 B | 0.0050 | - | - | 32 B | +| _PrimitiveShortSerialize | ProtobufNet | 1,199.30 ns | NA | 4 B | 0.0591 | - | - | 376 B | +| _PrimitiveShortSerialize | JsonNet | 2,141.40 ns | NA | 8 B | 0.4768 | - | - | 2,992 B | +| _PrimitiveShortSerialize | BinaryFormatter | 2,133.40 ns | NA | 52 B | 0.4883 | 0.0038 | - | 3,072 B | +| _PrimitiveShortSerialize | DataContract | 2,307.27 ns | NA | 80 B | 0.2708 | - | - | 1,712 B | +| _PrimitiveShortSerialize | Hyperion | 528.66 ns | NA | 3 B | 0.0782 | - | - | 496 B | +| _PrimitiveShortSerialize | Jil | 530.41 ns | NA | 5 B | 0.0420 | - | - | 264 B | +| _PrimitiveShortSerialize | SpanJson | 356.18 ns | NA | 5 B | 0.0048 | - | - | 32 B | +| _PrimitiveShortSerialize | UTF8Json | 216.68 ns | NA | 5 B | 0.0050 | - | - | 32 B | +| _PrimitiveShortSerialize | FsPickler | 1,829.01 ns | NA | 26 B | 0.1755 | - | - | 1,104 B | +| _PrimitiveShortSerialize | Ceras | 1,756.26 ns | NA | 2 B | 0.6599 | - | - | 4,152 B | +| _PrimitiveShortSerialize | OdinSerializer_ | 1,209.57 ns | NA | 3 B | 0.0038 | - | - | 32 B | +| _PrimitiveShortSerialize | Nino | 573.01 ns | NA | 2 B | 0.0048 | - | - | 32 B | +| **_PrimitiveStringDeserialize** | **MessagePack_Lz4** | **702.68 ns** | **NA** | **-** | **0.0458** | **-** | **-** | **288 B** | +| _PrimitiveStringDeserialize | MessagePack_NoComp | 173.30 ns | NA | - | 0.0355 | - | - | 224 B | +| _PrimitiveStringDeserialize | ProtobufNet | 411.17 ns | NA | - | 0.0496 | - | - | 312 B | +| _PrimitiveStringDeserialize | JsonNet | 1,060.70 ns | NA | - | 0.9384 | 0.0114 | - | 5,896 B | +| _PrimitiveStringDeserialize | BinaryFormatter | 807.73 ns | NA | - | 0.4072 | 0.0029 | - | 2,560 B | +| _PrimitiveStringDeserialize | DataContract | 1,922.67 ns | NA | - | 0.7401 | 0.0076 | - | 4,664 B | +| _PrimitiveStringDeserialize | Hyperion | 166.16 ns | NA | - | 0.0827 | - | - | 520 B | +| _PrimitiveStringDeserialize | Jil | 420.00 ns | NA | - | 0.1326 | - | - | 832 B | +| _PrimitiveStringDeserialize | SpanJson | 184.15 ns | NA | - | 0.0355 | - | - | 224 B | +| _PrimitiveStringDeserialize | UTF8Json | 336.03 ns | NA | - | 0.0353 | - | - | 224 B | +| _PrimitiveStringDeserialize | FsPickler | 556.87 ns | NA | - | 0.1974 | - | - | 1,240 B | +| _PrimitiveStringDeserialize | Ceras | 168.98 ns | NA | - | 0.0355 | - | - | 224 B | +| _PrimitiveStringDeserialize | OdinSerializer_ | 398.28 ns | NA | - | 0.0353 | - | - | 224 B | +| _PrimitiveStringDeserialize | Nino | 128.60 ns | NA | - | 0.0355 | - | - | 224 B | +| **_PrimitiveStringSerialize** | **MessagePack_Lz4** | **820.00 ns** | **NA** | **21 B** | **0.0172** | **-** | **-** | **112 B** | +| _PrimitiveStringSerialize | MessagePack_NoComp | 189.62 ns | NA | 102 B | 0.0203 | - | - | 128 B | +| _PrimitiveStringSerialize | ProtobufNet | 383.55 ns | NA | 102 B | 0.0749 | - | - | 472 B | +| _PrimitiveStringSerialize | JsonNet | 813.87 ns | NA | 105 B | 0.4892 | - | - | 3,072 B | +| _PrimitiveStringSerialize | BinaryFormatter | 1,115.42 ns | NA | 124 B | 0.3910 | 0.0019 | - | 2,464 B | +| _PrimitiveStringSerialize | DataContract | 1,060.32 ns | NA | 177 B | 0.2842 | - | - | 1,792 B | +| _PrimitiveStringSerialize | Hyperion | 289.40 ns | NA | 102 B | 0.1106 | - | - | 696 B | +| _PrimitiveStringSerialize | Jil | 799.98 ns | NA | 102 B | 0.1440 | - | - | 904 B | +| _PrimitiveStringSerialize | SpanJson | 325.26 ns | NA | 102 B | 0.0200 | - | - | 128 B | +| _PrimitiveStringSerialize | UTF8Json | 201.56 ns | NA | 102 B | 0.0203 | - | - | 128 B | +| _PrimitiveStringSerialize | FsPickler | 685.57 ns | NA | 127 B | 0.1907 | - | - | 1,200 B | +| _PrimitiveStringSerialize | Ceras | 429.81 ns | NA | 101 B | 0.6766 | - | - | 4,248 B | +| _PrimitiveStringSerialize | OdinSerializer_ | 412.05 ns | NA | 206 B | 0.0367 | - | - | 232 B | +| _PrimitiveStringSerialize | Nino | 211.95 ns | NA | 205 B | 0.0370 | - | - | 232 B | +| **_PrimitiveUIntDeserialize** | **MessagePack_Lz4** | **157.59 ns** | **NA** | **-** | **0.0100** | **-** | **-** | **64 B** | +| _PrimitiveUIntDeserialize | MessagePack_NoComp | 73.96 ns | NA | - | - | - | - | - | +| _PrimitiveUIntDeserialize | ProtobufNet | 328.39 ns | NA | - | 0.0138 | - | - | 88 B | +| _PrimitiveUIntDeserialize | JsonNet | 930.75 ns | NA | - | 0.9079 | 0.0067 | - | 5,696 B | +| _PrimitiveUIntDeserialize | BinaryFormatter | 2,540.67 ns | NA | - | 0.6561 | 0.0038 | - | 4,120 B | +| _PrimitiveUIntDeserialize | DataContract | 1,867.91 ns | NA | - | 0.6580 | 0.0057 | - | 4,136 B | +| _PrimitiveUIntDeserialize | Hyperion | 111.25 ns | NA | - | 0.0305 | - | - | 192 B | +| _PrimitiveUIntDeserialize | Jil | 85.69 ns | NA | - | 0.0191 | - | - | 120 B | +| _PrimitiveUIntDeserialize | SpanJson | 23.02 ns | NA | - | - | - | - | - | +| _PrimitiveUIntDeserialize | UTF8Json | 30.73 ns | NA | - | - | - | - | - | +| _PrimitiveUIntDeserialize | FsPickler | 535.68 ns | NA | - | 0.1612 | - | - | 1,016 B | +| _PrimitiveUIntDeserialize | Ceras | 93.66 ns | NA | - | - | - | - | - | +| _PrimitiveUIntDeserialize | OdinSerializer_ | 401.44 ns | NA | - | - | - | - | - | +| _PrimitiveUIntDeserialize | Nino | 100.82 ns | NA | - | - | - | - | - | +| **_PrimitiveUIntSerialize** | **MessagePack_Lz4** | **111.23 ns** | **NA** | **1 B** | **0.0153** | **-** | **-** | **96 B** | +| _PrimitiveUIntSerialize | MessagePack_NoComp | 89.36 ns | NA | 1 B | 0.0050 | - | - | 32 B | +| _PrimitiveUIntSerialize | ProtobufNet | 257.15 ns | NA | 2 B | 0.0596 | - | - | 376 B | +| _PrimitiveUIntSerialize | JsonNet | 564.64 ns | NA | 4 B | 0.4616 | 0.0019 | - | 2,896 B | +| _PrimitiveUIntSerialize | BinaryFormatter | 1,993.48 ns | NA | 55 B | 0.4883 | 0.0019 | - | 3,072 B | +| _PrimitiveUIntSerialize | DataContract | 854.89 ns | NA | 88 B | 0.2737 | - | - | 1,720 B | +| _PrimitiveUIntSerialize | Hyperion | 216.72 ns | NA | 5 B | 0.0789 | - | - | 496 B | +| _PrimitiveUIntSerialize | Jil | 117.08 ns | NA | 1 B | 0.0408 | - | - | 256 B | +| _PrimitiveUIntSerialize | SpanJson | 58.77 ns | NA | 1 B | 0.0050 | - | - | 32 B | +| _PrimitiveUIntSerialize | UTF8Json | 42.10 ns | NA | 1 B | 0.0051 | - | - | 32 B | +| _PrimitiveUIntSerialize | FsPickler | 522.95 ns | NA | 29 B | 0.1755 | - | - | 1,104 B | +| _PrimitiveUIntSerialize | Ceras | 361.05 ns | NA | 1 B | 0.6614 | - | - | 4,152 B | +| _PrimitiveUIntSerialize | OdinSerializer_ | 366.13 ns | NA | 5 B | 0.0048 | - | - | 32 B | +| _PrimitiveUIntSerialize | Nino | 156.86 ns | NA | 4 B | 0.0050 | - | - | 32 B | +| **_PrimitiveULongDeserialize** | **MessagePack_Lz4** | **176.60 ns** | **NA** | **-** | **0.0100** | **-** | **-** | **64 B** | +| _PrimitiveULongDeserialize | MessagePack_NoComp | 85.79 ns | NA | - | - | - | - | - | +| _PrimitiveULongDeserialize | ProtobufNet | 368.50 ns | NA | - | 0.0138 | - | - | 88 B | +| _PrimitiveULongDeserialize | JsonNet | 1,520.99 ns | NA | - | 0.9613 | 0.0114 | - | 6,032 B | +| _PrimitiveULongDeserialize | BinaryFormatter | 2,263.35 ns | NA | - | 0.6561 | 0.0038 | - | 4,120 B | +| _PrimitiveULongDeserialize | DataContract | 1,886.31 ns | NA | - | 0.6790 | 0.0076 | - | 4,264 B | +| _PrimitiveULongDeserialize | Hyperion | 96.14 ns | NA | - | 0.0305 | - | - | 192 B | +| _PrimitiveULongDeserialize | Jil | 130.89 ns | NA | - | 0.0253 | - | - | 160 B | +| _PrimitiveULongDeserialize | SpanJson | 67.90 ns | NA | - | - | - | - | - | +| _PrimitiveULongDeserialize | UTF8Json | 68.53 ns | NA | - | - | - | - | - | +| _PrimitiveULongDeserialize | FsPickler | 675.51 ns | NA | - | 0.1612 | - | - | 1,016 B | +| _PrimitiveULongDeserialize | Ceras | 135.51 ns | NA | - | - | - | - | - | +| _PrimitiveULongDeserialize | OdinSerializer_ | 607.82 ns | NA | - | - | - | - | - | +| _PrimitiveULongDeserialize | Nino | 176.12 ns | NA | - | - | - | - | - | +| **_PrimitiveULongSerialize** | **MessagePack_Lz4** | **118.16 ns** | **NA** | **9 B** | **0.0166** | **-** | **-** | **104 B** | +| _PrimitiveULongSerialize | MessagePack_NoComp | 86.94 ns | NA | 9 B | 0.0063 | - | - | 40 B | +| _PrimitiveULongSerialize | ProtobufNet | 252.73 ns | NA | 11 B | 0.0610 | - | - | 384 B | +| _PrimitiveULongSerialize | JsonNet | 614.58 ns | NA | 23 B | 0.4787 | 0.0038 | - | 3,008 B | +| _PrimitiveULongSerialize | BinaryFormatter | 1,487.88 ns | NA | 59 B | 0.4902 | 0.0038 | - | 3,080 B | +| _PrimitiveULongSerialize | DataContract | 803.46 ns | NA | 109 B | 0.2880 | - | - | 1,808 B | +| _PrimitiveULongSerialize | Hyperion | 201.69 ns | NA | 9 B | 0.0801 | - | - | 504 B | +| _PrimitiveULongSerialize | Jil | 217.15 ns | NA | 20 B | 0.0663 | - | - | 416 B | +| _PrimitiveULongSerialize | SpanJson | 107.84 ns | NA | 20 B | 0.0076 | - | - | 48 B | +| _PrimitiveULongSerialize | UTF8Json | 102.53 ns | NA | 20 B | 0.0076 | - | - | 48 B | +| _PrimitiveULongSerialize | FsPickler | 506.13 ns | NA | 33 B | 0.1764 | - | - | 1,112 B | +| _PrimitiveULongSerialize | Ceras | 525.88 ns | NA | 8 B | 0.6614 | - | - | 4,152 B | +| _PrimitiveULongSerialize | OdinSerializer_ | 419.36 ns | NA | 9 B | 0.0062 | - | - | 40 B | +| _PrimitiveULongSerialize | Nino | 195.84 ns | NA | 8 B | 0.0050 | - | - | 32 B | +| **_PrimitiveUShortDeserialize** | **MessagePack_Lz4** | **185.75 ns** | **NA** | **-** | **0.0100** | **-** | **-** | **64 B** | +| _PrimitiveUShortDeserialize | MessagePack_NoComp | 86.30 ns | NA | - | - | - | - | - | +| _PrimitiveUShortDeserialize | ProtobufNet | 337.07 ns | NA | - | 0.0138 | - | - | 88 B | +| _PrimitiveUShortDeserialize | JsonNet | 995.58 ns | NA | - | 0.9108 | 0.0057 | - | 5,720 B | +| _PrimitiveUShortDeserialize | BinaryFormatter | 2,415.21 ns | NA | - | 0.6561 | 0.0038 | - | 4,120 B | +| _PrimitiveUShortDeserialize | DataContract | 1,612.51 ns | NA | - | 0.6580 | 0.0057 | - | 4,136 B | +| _PrimitiveUShortDeserialize | Hyperion | 88.46 ns | NA | - | 0.0305 | - | - | 192 B | +| _PrimitiveUShortDeserialize | Jil | 82.67 ns | NA | - | 0.0204 | - | - | 128 B | +| _PrimitiveUShortDeserialize | SpanJson | 36.12 ns | NA | - | - | - | - | - | +| _PrimitiveUShortDeserialize | UTF8Json | 35.30 ns | NA | - | - | - | - | - | +| _PrimitiveUShortDeserialize | FsPickler | 500.83 ns | NA | - | 0.1612 | - | - | 1,016 B | +| _PrimitiveUShortDeserialize | Ceras | 83.13 ns | NA | - | - | - | - | - | +| _PrimitiveUShortDeserialize | OdinSerializer_ | 375.82 ns | NA | - | - | - | - | - | +| _PrimitiveUShortDeserialize | Nino | 94.70 ns | NA | - | - | - | - | - | +| **_PrimitiveUShortSerialize** | **MessagePack_Lz4** | **123.93 ns** | **NA** | **3 B** | **0.0153** | **-** | **-** | **96 B** | +| _PrimitiveUShortSerialize | MessagePack_NoComp | 124.18 ns | NA | 3 B | 0.0050 | - | - | 32 B | +| _PrimitiveUShortSerialize | ProtobufNet | 375.15 ns | NA | 4 B | 0.0591 | - | - | 376 B | +| _PrimitiveUShortSerialize | JsonNet | 567.28 ns | NA | 8 B | 0.4768 | 0.0010 | - | 2,992 B | +| _PrimitiveUShortSerialize | BinaryFormatter | 2,202.36 ns | NA | 53 B | 0.4883 | 0.0038 | - | 3,072 B | +| _PrimitiveUShortSerialize | DataContract | 877.34 ns | NA | 96 B | 0.2747 | - | - | 1,728 B | +| _PrimitiveUShortSerialize | Hyperion | 224.12 ns | NA | 3 B | 0.0789 | - | - | 496 B | +| _PrimitiveUShortSerialize | Jil | 116.58 ns | NA | 5 B | 0.0420 | - | - | 264 B | +| _PrimitiveUShortSerialize | SpanJson | 75.19 ns | NA | 5 B | 0.0050 | - | - | 32 B | +| _PrimitiveUShortSerialize | UTF8Json | 52.63 ns | NA | 5 B | 0.0051 | - | - | 32 B | +| _PrimitiveUShortSerialize | FsPickler | 504.66 ns | NA | 27 B | 0.1755 | - | - | 1,104 B | +| _PrimitiveUShortSerialize | Ceras | 358.84 ns | NA | 2 B | 0.6614 | - | - | 4,152 B | +| _PrimitiveUShortSerialize | OdinSerializer_ | 404.87 ns | NA | 3 B | 0.0048 | - | - | 32 B | +| _PrimitiveUShortSerialize | Nino | 130.35 ns | NA | 2 B | 0.0050 | - | - | 32 B | +| **AccessTokenDeserialize** | **MessagePack_Lz4** | **316.43 ns** | **NA** | **-** | **0.0176** | **-** | **-** | **112 B** | +| AccessTokenDeserialize | MessagePack_NoComp | 221.01 ns | NA | - | 0.0076 | - | - | 48 B | +| AccessTokenDeserialize | ProtobufNet | 457.79 ns | NA | - | 0.0215 | - | - | 136 B | +| AccessTokenDeserialize | JsonNet | 2,294.51 ns | NA | - | 0.9193 | 0.0076 | - | 5,768 B | +| AccessTokenDeserialize | BinaryFormatter | 3,523.19 ns | NA | - | 0.8316 | 0.0076 | - | 5,240 B | +| AccessTokenDeserialize | DataContract | 4,765.78 ns | NA | - | 1.3733 | 0.0229 | - | 8,632 B | +| AccessTokenDeserialize | Hyperion | 413.93 ns | NA | - | 0.0710 | - | - | 448 B | +| AccessTokenDeserialize | Jil | 425.25 ns | NA | - | 0.0520 | - | - | 328 B | +| AccessTokenDeserialize | SpanJson | 168.87 ns | NA | - | 0.0076 | - | - | 48 B | +| AccessTokenDeserialize | UTF8Json | 348.10 ns | NA | - | 0.0076 | - | - | 48 B | +| AccessTokenDeserialize | FsPickler | 592.29 ns | NA | - | 0.1974 | - | - | 1,240 B | +| AccessTokenDeserialize | Ceras | 250.57 ns | NA | - | 0.0076 | - | - | 48 B | +| AccessTokenDeserialize | OdinSerializer_ | 2,443.11 ns | NA | - | 0.0992 | - | - | 632 B | +| AccessTokenDeserialize | Nino | 123.04 ns | NA | - | 0.0076 | - | - | 48 B | +| **AccessTokenSerialize** | **MessagePack_Lz4** | **456.46 ns** | **NA** | **19 B** | **0.0176** | **-** | **-** | **112 B** | +| AccessTokenSerialize | MessagePack_NoComp | 165.94 ns | NA | 19 B | 0.0076 | - | - | 48 B | +| AccessTokenSerialize | ProtobufNet | 381.50 ns | NA | 6 B | 0.0596 | - | - | 376 B | +| AccessTokenSerialize | JsonNet | 1,223.19 ns | NA | 82 B | 0.5016 | 0.0019 | - | 3,152 B | +| AccessTokenSerialize | BinaryFormatter | 3,770.73 ns | NA | 392 B | 0.7782 | 0.0076 | - | 4,888 B | +| AccessTokenSerialize | DataContract | 1,964.62 ns | NA | 333 B | 0.4234 | - | - | 2,680 B | +| AccessTokenSerialize | Hyperion | 292.70 ns | NA | 69 B | 0.1044 | - | - | 656 B | +| AccessTokenSerialize | Jil | 658.46 ns | NA | 80 B | 0.1478 | - | - | 928 B | +| AccessTokenSerialize | SpanJson | 139.64 ns | NA | 53 B | 0.0126 | - | - | 80 B | +| AccessTokenSerialize | UTF8Json | 232.84 ns | NA | 79 B | 0.0165 | - | - | 104 B | +| AccessTokenSerialize | FsPickler | 640.62 ns | NA | 67 B | 0.1907 | - | - | 1,200 B | +| AccessTokenSerialize | Ceras | 449.39 ns | NA | 12 B | 0.6628 | - | - | 4,160 B | +| AccessTokenSerialize | OdinSerializer_ | 1,787.99 ns | NA | 440 B | 0.0801 | - | - | 512 B | +| AccessTokenSerialize | Nino | 363.26 ns | NA | 15 B | 0.0062 | - | - | 40 B | +| **AccountMergeDeserialize** | **MessagePack_Lz4** | **292.78 ns** | **NA** | **-** | **0.0153** | **-** | **-** | **96 B** | +| AccountMergeDeserialize | MessagePack_NoComp | 183.28 ns | NA | - | 0.0050 | - | - | 32 B | +| AccountMergeDeserialize | ProtobufNet | 509.81 ns | NA | - | 0.0191 | - | - | 120 B | +| AccountMergeDeserialize | JsonNet | 2,410.99 ns | NA | - | 0.9155 | 0.0076 | - | 5,752 B | +| AccountMergeDeserialize | BinaryFormatter | 4,045.96 ns | NA | - | 0.7706 | 0.0076 | - | 4,848 B | +| AccountMergeDeserialize | DataContract | 4,617.67 ns | NA | - | 1.9913 | 0.0534 | - | 12,536 B | +| AccountMergeDeserialize | Hyperion | 452.35 ns | NA | - | 0.0687 | - | - | 432 B | +| AccountMergeDeserialize | Jil | 415.74 ns | NA | - | 0.0467 | - | - | 296 B | +| AccountMergeDeserialize | SpanJson | 245.11 ns | NA | - | 0.0048 | - | - | 32 B | +| AccountMergeDeserialize | UTF8Json | 369.16 ns | NA | - | 0.0048 | - | - | 32 B | +| AccountMergeDeserialize | FsPickler | 726.89 ns | NA | - | 0.1955 | - | - | 1,232 B | +| AccountMergeDeserialize | Ceras | 285.84 ns | NA | - | 0.0048 | - | - | 32 B | +| AccountMergeDeserialize | OdinSerializer_ | 2,342.40 ns | NA | - | 0.0916 | - | - | 576 B | +| AccountMergeDeserialize | Nino | 129.25 ns | NA | - | 0.0050 | - | - | 32 B | +| **AccountMergeSerialize** | **MessagePack_Lz4** | **390.86 ns** | **NA** | **18 B** | **0.0176** | **-** | **-** | **112 B** | +| AccountMergeSerialize | MessagePack_NoComp | 130.24 ns | NA | 18 B | 0.0076 | - | - | 48 B | +| AccountMergeSerialize | ProtobufNet | 384.64 ns | NA | 6 B | 0.0596 | - | - | 376 B | +| AccountMergeSerialize | JsonNet | 1,073.55 ns | NA | 72 B | 0.5035 | 0.0019 | - | 3,160 B | +| AccountMergeSerialize | BinaryFormatter | 2,546.03 ns | NA | 250 B | 0.6142 | 0.0038 | - | 3,872 B | +| AccountMergeSerialize | DataContract | 1,467.83 ns | NA | 253 B | 0.3929 | 0.0019 | - | 2,472 B | +| AccountMergeSerialize | Hyperion | 256.34 ns | NA | 72 B | 0.0992 | - | - | 624 B | +| AccountMergeSerialize | Jil | 582.03 ns | NA | 70 B | 0.1144 | - | - | 720 B | +| AccountMergeSerialize | SpanJson | 213.05 ns | NA | 69 B | 0.0153 | - | - | 96 B | +| AccountMergeSerialize | UTF8Json | 292.99 ns | NA | 69 B | 0.0153 | - | - | 96 B | +| AccountMergeSerialize | FsPickler | 1,148.42 ns | NA | 67 B | 0.1907 | - | - | 1,200 B | +| AccountMergeSerialize | Ceras | 827.40 ns | NA | 11 B | 0.6628 | - | - | 4,160 B | +| AccountMergeSerialize | OdinSerializer_ | 3,250.38 ns | NA | 408 B | 0.0801 | - | - | 504 B | +| AccountMergeSerialize | Nino | 725.92 ns | NA | 17 B | 0.0076 | - | - | 48 B | +| **AnswerDeserialize** | **MessagePack_Lz4** | **1,326.61 ns** | **NA** | **-** | **0.0324** | **-** | **-** | **208 B** | +| AnswerDeserialize | MessagePack_NoComp | 703.88 ns | NA | - | 0.0229 | - | - | 144 B | +| AnswerDeserialize | ProtobufNet | 936.46 ns | NA | - | 0.0362 | - | - | 232 B | +| AnswerDeserialize | JsonNet | 10,047.23 ns | NA | - | 0.9460 | - | - | 6,056 B | +| AnswerDeserialize | BinaryFormatter | 11,984.01 ns | NA | - | 1.3885 | 0.0153 | - | 8,784 B | +| AnswerDeserialize | DataContract | 13,221.88 ns | NA | - | 2.1210 | 0.0305 | - | 13,392 B | +| AnswerDeserialize | Hyperion | 662.89 ns | NA | - | 0.0849 | - | - | 536 B | +| AnswerDeserialize | Jil | 2,622.56 ns | NA | - | 0.1869 | - | - | 1,184 B | +| AnswerDeserialize | SpanJson | 978.31 ns | NA | - | 0.0229 | - | - | 144 B | +| AnswerDeserialize | UTF8Json | 1,991.88 ns | NA | - | 0.0229 | - | - | 144 B | +| AnswerDeserialize | FsPickler | 987.08 ns | NA | - | 0.2117 | - | - | 1,328 B | +| AnswerDeserialize | Ceras | 423.92 ns | NA | - | 0.0229 | - | - | 144 B | +| AnswerDeserialize | OdinSerializer_ | 8,844.30 ns | NA | - | 0.3815 | - | - | 2,416 B | +| AnswerDeserialize | Nino | 237.18 ns | NA | - | 0.0229 | - | - | 144 B | +| **AnswerSerialize** | **MessagePack_Lz4** | **1,591.24 ns** | **NA** | **53 B** | **0.0229** | **-** | **-** | **144 B** | +| AnswerSerialize | MessagePack_NoComp | 685.54 ns | NA | 97 B | 0.0200 | - | - | 128 B | +| AnswerSerialize | ProtobufNet | 1,112.38 ns | NA | 30 B | 0.0629 | - | - | 400 B | +| AnswerSerialize | JsonNet | 6,465.29 ns | NA | 458 B | 1.1902 | 0.0076 | - | 7,480 B | +| AnswerSerialize | BinaryFormatter | 12,973.97 ns | NA | 1117 B | 1.6785 | 0.0458 | - | 10,552 B | +| AnswerSerialize | DataContract | 6,201.87 ns | NA | 883 B | 0.9155 | 0.0076 | - | 5,768 B | +| AnswerSerialize | Hyperion | 708.94 ns | NA | 129 B | 0.1345 | - | - | 848 B | +| AnswerSerialize | Jil | 2,866.13 ns | NA | 460 B | 0.4730 | - | - | 2,984 B | +| AnswerSerialize | SpanJson | 659.48 ns | NA | 353 B | 0.0610 | - | - | 384 B | +| AnswerSerialize | UTF8Json | 1,181.20 ns | NA | 455 B | 0.0763 | - | - | 480 B | +| AnswerSerialize | FsPickler | 1,177.14 ns | NA | 130 B | 0.2003 | - | - | 1,264 B | +| AnswerSerialize | Ceras | 582.16 ns | NA | 58 B | 0.6704 | - | - | 4,208 B | +| AnswerSerialize | OdinSerializer_ | 5,573.59 ns | NA | 1584 B | 0.3128 | - | - | 1,968 B | +| AnswerSerialize | Nino | 1,249.43 ns | NA | 76 B | 0.0153 | - | - | 104 B | +| **BadgeDeserialize** | **MessagePack_Lz4** | **395.57 ns** | **NA** | **-** | **0.0176** | **-** | **-** | **112 B** | +| BadgeDeserialize | MessagePack_NoComp | 250.70 ns | NA | - | 0.0076 | - | - | 48 B | +| BadgeDeserialize | ProtobufNet | 340.47 ns | NA | - | 0.0215 | - | - | 136 B | +| BadgeDeserialize | JsonNet | 2,501.09 ns | NA | - | 0.9079 | 0.0038 | - | 5,720 B | +| BadgeDeserialize | BinaryFormatter | 3,852.13 ns | NA | - | 0.8011 | 0.0076 | - | 5,072 B | +| BadgeDeserialize | DataContract | 5,511.62 ns | NA | - | 1.3351 | 0.0076 | - | 8,400 B | +| BadgeDeserialize | Hyperion | 413.71 ns | NA | - | 0.0701 | - | - | 440 B | +| BadgeDeserialize | Jil | 308.57 ns | NA | - | 0.0496 | - | - | 312 B | +| BadgeDeserialize | SpanJson | 117.73 ns | NA | - | 0.0076 | - | - | 48 B | +| BadgeDeserialize | UTF8Json | 293.01 ns | NA | - | 0.0076 | - | - | 48 B | +| BadgeDeserialize | FsPickler | 648.55 ns | NA | - | 0.1955 | - | - | 1,232 B | +| BadgeDeserialize | Ceras | 293.78 ns | NA | - | 0.0076 | - | - | 48 B | +| BadgeDeserialize | OdinSerializer_ | 2,532.88 ns | NA | - | 0.0877 | - | - | 568 B | +| BadgeDeserialize | Nino | 132.14 ns | NA | - | 0.0076 | - | - | 48 B | +| **BadgeSerialize** | **MessagePack_Lz4** | **478.37 ns** | **NA** | **9 B** | **0.0162** | **-** | **-** | **104 B** | +| BadgeSerialize | MessagePack_NoComp | 174.82 ns | NA | 9 B | 0.0062 | - | - | 40 B | +| BadgeSerialize | ProtobufNet | 231.86 ns | NA | 0 B | 0.0100 | - | - | 64 B | +| BadgeSerialize | JsonNet | 1,262.12 ns | NA | 74 B | 0.4845 | 0.0019 | - | 3,048 B | +| BadgeSerialize | BinaryFormatter | 2,943.65 ns | NA | 278 B | 0.7172 | 0.0076 | - | 4,504 B | +| BadgeSerialize | DataContract | 1,702.01 ns | NA | 250 B | 0.3376 | - | - | 2,120 B | +| BadgeSerialize | Hyperion | 314.61 ns | NA | 59 B | 0.1135 | - | - | 712 B | +| BadgeSerialize | Jil | 502.98 ns | NA | 71 B | 0.1440 | - | - | 904 B | +| BadgeSerialize | SpanJson | 99.93 ns | NA | 28 B | 0.0088 | - | - | 56 B | +| BadgeSerialize | UTF8Json | 149.48 ns | NA | 71 B | 0.0153 | - | - | 96 B | +| BadgeSerialize | FsPickler | 798.78 ns | NA | 54 B | 0.1879 | - | - | 1,184 B | +| BadgeSerialize | Ceras | 582.07 ns | NA | 6 B | 0.6609 | - | - | 4,152 B | +| BadgeSerialize | OdinSerializer_ | 1,886.66 ns | NA | 382 B | 0.0725 | - | - | 456 B | +| BadgeSerialize | Nino | 435.72 ns | NA | 12 B | 0.0062 | - | - | 40 B | +| **CommentDeserialize** | **MessagePack_Lz4** | **486.44 ns** | **NA** | **-** | **0.0200** | **-** | **-** | **128 B** | +| CommentDeserialize | MessagePack_NoComp | 323.48 ns | NA | - | 0.0100 | - | - | 64 B | +| CommentDeserialize | ProtobufNet | 696.60 ns | NA | - | 0.0238 | - | - | 152 B | +| CommentDeserialize | JsonNet | 4,598.12 ns | NA | - | 0.9155 | - | - | 5,784 B | +| CommentDeserialize | BinaryFormatter | 6,282.90 ns | NA | - | 0.9232 | 0.0076 | - | 5,832 B | +| CommentDeserialize | DataContract | 8,445.41 ns | NA | - | 2.0142 | 0.0458 | - | 12,728 B | +| CommentDeserialize | Hyperion | 552.15 ns | NA | - | 0.0725 | - | - | 456 B | +| CommentDeserialize | Jil | 825.58 ns | NA | - | 0.0763 | - | - | 480 B | +| CommentDeserialize | SpanJson | 385.60 ns | NA | - | 0.0100 | - | - | 64 B | +| CommentDeserialize | UTF8Json | 773.54 ns | NA | - | 0.0095 | - | - | 64 B | +| CommentDeserialize | FsPickler | 821.49 ns | NA | - | 0.1984 | - | - | 1,248 B | +| CommentDeserialize | Ceras | 375.46 ns | NA | - | 0.0100 | - | - | 64 B | +| CommentDeserialize | OdinSerializer_ | 5,035.95 ns | NA | - | 0.1678 | - | - | 1,080 B | +| CommentDeserialize | Nino | 186.19 ns | NA | - | 0.0100 | - | - | 64 B | +| **CommentSerialize** | **MessagePack_Lz4** | **611.46 ns** | **NA** | **27 B** | **0.0191** | **-** | **-** | **120 B** | +| CommentSerialize | MessagePack_NoComp | 271.17 ns | NA | 27 B | 0.0086 | - | - | 56 B | +| CommentSerialize | ProtobufNet | 483.57 ns | NA | 6 B | 0.0591 | - | - | 376 B | +| CommentSerialize | JsonNet | 2,185.71 ns | NA | 151 B | 0.5264 | 0.0038 | - | 3,312 B | +| CommentSerialize | BinaryFormatter | 5,169.11 ns | NA | 403 B | 0.7935 | 0.0076 | - | 5,016 B | +| CommentSerialize | DataContract | 2,733.44 ns | NA | 361 B | 0.4272 | - | - | 2,696 B | +| CommentSerialize | Hyperion | 385.13 ns | NA | 76 B | 0.1159 | - | - | 728 B | +| CommentSerialize | Jil | 904.00 ns | NA | 149 B | 0.1898 | - | - | 1,192 B | +| CommentSerialize | SpanJson | 203.51 ns | NA | 104 B | 0.0203 | - | - | 128 B | +| CommentSerialize | UTF8Json | 368.54 ns | NA | 148 B | 0.0277 | - | - | 176 B | +| CommentSerialize | FsPickler | 1,231.04 ns | NA | 71 B | 0.1907 | - | - | 1,200 B | +| CommentSerialize | Ceras | 807.36 ns | NA | 17 B | 0.6638 | - | - | 4,168 B | +| CommentSerialize | OdinSerializer_ | 4,542.29 ns | NA | 708 B | 0.1373 | - | - | 880 B | +| CommentSerialize | Nino | 1,276.17 ns | NA | 26 B | 0.0076 | - | - | 56 B | +| **NestedDataDeserialize** | **MessagePack_Lz4** | **4,325,684.66 ns** | **NA** | **-** | **242.1875** | **242.1875** | **242.1875** | **940,355 B** | +| NestedDataDeserialize | MessagePack_NoComp | 4,122,675.18 ns | NA | - | 132.8125 | 132.8125 | 132.8125 | 560,180 B | +| NestedDataDeserialize | ProtobufNet | 4,467,512.12 ns | NA | - | 234.3750 | 234.3750 | 234.3750 | 989,190 B | +| NestedDataDeserialize | JsonNet | 52,505,701.30 ns | NA | - | 1100.0000 | 500.0000 | 500.0000 | 6,083,663 B | +| NestedDataDeserialize | BinaryFormatter | 71,770,976.14 ns | NA | - | 2285.7143 | 857.1429 | 428.5714 | 12,695,021 B | +| NestedDataDeserialize | DataContract | 43,894,391.58 ns | NA | - | 750.0000 | 416.6667 | 416.6667 | 4,487,180 B | +| NestedDataDeserialize | Hyperion | 4,058,719.35 ns | NA | - | 398.4375 | 132.8125 | 132.8125 | 2,241,259 B | +| NestedDataDeserialize | Jil | 15,136,395.33 ns | NA | - | 1125.0000 | 968.7500 | 953.1250 | 5,377,251 B | +| NestedDataDeserialize | SpanJson | 8,253,926.22 ns | NA | - | 203.1250 | 203.1250 | 203.1250 | 955,881 B | +| NestedDataDeserialize | UTF8Json | 17,345,135.78 ns | NA | - | 546.8750 | 468.7500 | 468.7500 | 2,449,894 B | +| NestedDataDeserialize | FsPickler | 2,035,366.98 ns | NA | - | 134.7656 | 134.7656 | 134.7656 | 561,865 B | +| NestedDataDeserialize | Ceras | 247,460.37 ns | NA | - | 75.9277 | 75.6836 | 75.6836 | 560,673 B | +| NestedDataDeserialize | OdinSerializer_ | 41,429,573.50 ns | NA | - | 916.6667 | 166.6667 | 166.6667 | 6,994,322 B | +| NestedDataDeserialize | Nino | 1,313,632.30 ns | NA | - | 138.6719 | 138.6719 | 138.6719 | 560,180 B | +| **NestedDataSerialize** | **MessagePack_Lz4** | **2,455,911.87 ns** | **NA** | **1553 B** | **-** | **-** | **-** | **1,653 B** | +| NestedDataSerialize | MessagePack_NoComp | 2,406,048.39 ns | NA | 380010 B | 97.6563 | 97.6563 | 97.6563 | 380,109 B | +| NestedDataSerialize | ProtobufNet | 3,384,039.64 ns | NA | 410006 B | 351.5625 | 332.0313 | 332.0313 | 1,465,474 B | +| NestedDataSerialize | JsonNet | 25,376,169.72 ns | NA | 920025 B | 1250.0000 | 656.2500 | 625.0000 | 6,950,205 B | +| NestedDataSerialize | BinaryFormatter | 35,539,531.00 ns | NA | 580388 B | 1571.4286 | 571.4286 | 571.4286 | 9,164,829 B | +| NestedDataSerialize | DataContract | 19,413,209.16 ns | NA | 1190173 B | 1187.5000 | 750.0000 | 718.7500 | 8,185,236 B | +| NestedDataSerialize | Hyperion | 5,051,485.30 ns | NA | 500203 B | 640.6250 | 367.1875 | 351.5625 | 3,230,001 B | +| NestedDataSerialize | Jil | 9,324,166.25 ns | NA | 1010022 B | 1031.2500 | 921.8750 | 484.3750 | 6,513,292 B | +| NestedDataSerialize | SpanJson | 6,884,080.73 ns | NA | 1010022 B | 164.0625 | 164.0625 | 164.0625 | 1,010,161 B | +| NestedDataSerialize | UTF8Json | 9,239,658.41 ns | NA | 1010022 B | 781.2500 | 640.6250 | 640.6250 | 3,858,242 B | +| NestedDataSerialize | FsPickler | 2,004,896.36 ns | NA | 470066 B | 351.5625 | 332.0313 | 332.0313 | 1,521,334 B | +| NestedDataSerialize | Ceras | 464,136.09 ns | NA | 560009 B | 162.1094 | 161.1328 | 161.1328 | 1,613,471 B | +| NestedDataSerialize | OdinSerializer_ | 19,509,833.66 ns | NA | 1280351 B | 1812.5000 | 500.0000 | 500.0000 | 12,728,135 B | +| NestedDataSerialize | Nino | 604,728.28 ns | NA | 450019 B | 124.0234 | 124.0234 | 124.0234 | 450,162 B | ### 说明 -非Unity平台下,ZLib压缩解压算法的耗时较大,导致Nino耗时比较高(如果不开压缩则Nino最快),但是数据大的时候序列化和反序列化Nino都会比其他方案快,于此同时Nino的GC也比其他方案小,基础类型甚至做到了无GC序列化反序列化 - -### 性能 - -- **Nino无论在任何平台,GC都把控的很出色** -- Nino在**Unity平台**是目前当之无愧的**性能最卓越**的二进制序列化库,且真正意义上实现了**全平台都低GC**,并且在**Unity平台下**的**序列化速度远超同类**,甚至**在非Unity平台的反序列化速度都比MsgPack快** -- Nino**补上Emit后**,**非Unity平台**的序列化性能和GC可以**与MsgPack持平** -- Nino提供不同的压缩方案后,能做到在Net Core下也高性能 - -### 体积 - -- Nino的体积依然是最小的(某些情况下比MsgPack LZ4大一点,因为有了多态支持),**体积**是MsgPack LZ4压缩的**一半**,是Protobuf的**数百分之一** - -- 在**全部C#平台**下,Nino序列化结果的**体积**是**当之无愧最小**的,最利于数据存储和网络通信的。 - +因为别的方案大多是用`byte[]`的,没办法发挥Nino的长处(使用`Span`,包含`stackalloc`分配的内存) diff --git a/README.md b/README.md index 3133a2b..7810203 100644 --- a/README.md +++ b/README.md @@ -35,11 +35,13 @@ Definite useful and high performance modules for C# projects, especially for Uni > > **注意**,该模块的序列化数据,仅支持在C#平台使用该库进行序列化和反序列化,无法跨语言使用 > + > ```Nino.Serialization v1.2.0```与其**前面**的**所有版本**都**不兼容**,详细请查看使用教程 + > > ```Nino.Serialization v1.1.2```与其**前面**的**所有版本**都**不兼容**,详细请查看使用教程 > > ```Nino.Serialization v1.1.0```与其**前面**的**所有版本**都**不兼容**,详细请查看使用教程 > - > ```Nino.Serialization v1.0.21.2```与其**前面**的**所有版本**都**不兼容**,详细请查看使用教程(```v1.0.21```有个Log忘删了,所以补发了```v1.0.21.2```) + > ```Nino.Serialization v1.0.21.2```与其**前面**的**所有版本**都**不兼容**,详细请查看使用教程 - 测试案例 - [Test1](Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test1.cs) Nino VS Protobuf-net 序列化 @@ -70,13 +72,6 @@ Definite useful and high performance modules for C# projects, especially for Uni > MsgPack在IL2CPP下不生成代码无法使用 - [性能报告](Performance/Serialization.md) - - - RoadMap - - - ILRuntime针对性优化(直接操作ILTypeInstance的成员而不是用反射) - - ~~IL Emit -> 非IL2CPP环境~~ - - ~~ExpressionTree -> 非IL2CPP环境~~ - - analyser -> 全局 @@ -113,7 +108,7 @@ Definite useful and high performance modules for C# projects, especially for Uni ``` ```bash - PM> Install-Package Nino.Serialization -Version 1.1.2 + PM> Install-Package Nino.Serialization -Version 1.2.0 ``` - 使用src下的代码(复制进自己项目即可) diff --git a/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_AccessToken_Serialize.cs b/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_AccessToken_Serialize.cs new file mode 100644 index 0000000..45f104b --- /dev/null +++ b/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_AccessToken_Serialize.cs @@ -0,0 +1,62 @@ +/* this is generated by nino */ +using System.Runtime.CompilerServices; + +namespace Nino.Benchmark.Models +{ + public partial class AccessToken + { + public static AccessToken.SerializationHelper NinoSerializationHelper = new AccessToken.SerializationHelper(); + public unsafe class SerializationHelper: Nino.Serialization.NinoWrapperBase + { + #region NINO_CODEGEN + public SerializationHelper() + { + + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void Serialize(AccessToken value, ref Nino.Serialization.Writer writer) + { + if(value == null) + { + writer.Write(false); + return; + } + writer.Write(true); + writer.Write(value.Token); + writer.Write(value.ExpiresOnDate); + writer.Write(value.AccountId); + writer.Write(value.Scope); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override AccessToken Deserialize(Nino.Serialization.Reader reader) + { + if(!reader.ReadBool()) + return null; + AccessToken value = new AccessToken(); + value.Token = reader.ReadString(); + value.ExpiresOnDate = reader.Read(sizeof(System.DateTime)); + value.AccountId = reader.Read(sizeof(System.Int32)); + value.Scope = reader.ReadList(); + return value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetSize(AccessToken value) + { + if(value == null) + { + return 1; + } + int ret = 1; + ret += Nino.Serialization.Serializer.GetSize(value.Token); + ret += Nino.Serialization.Serializer.GetSize(value.ExpiresOnDate); + ret += Nino.Serialization.Serializer.GetSize(value.AccountId); + ret += Nino.Serialization.Serializer.GetSize(value.Scope); + return ret; + } + #endregion + } + } +} \ No newline at end of file diff --git a/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_AccountMerge_Serialize.cs b/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_AccountMerge_Serialize.cs new file mode 100644 index 0000000..dcdfbea --- /dev/null +++ b/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_AccountMerge_Serialize.cs @@ -0,0 +1,59 @@ +/* this is generated by nino */ +using System.Runtime.CompilerServices; + +namespace Nino.Benchmark.Models +{ + public partial class AccountMerge + { + public static AccountMerge.SerializationHelper NinoSerializationHelper = new AccountMerge.SerializationHelper(); + public unsafe class SerializationHelper: Nino.Serialization.NinoWrapperBase + { + #region NINO_CODEGEN + public SerializationHelper() + { + + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void Serialize(AccountMerge value, ref Nino.Serialization.Writer writer) + { + if(value == null) + { + writer.Write(false); + return; + } + writer.Write(true); + writer.Write(value.OldAccountId); + writer.Write(value.NewAccountId); + writer.Write(value.MergeDate); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override AccountMerge Deserialize(Nino.Serialization.Reader reader) + { + if(!reader.ReadBool()) + return null; + AccountMerge value = new AccountMerge(); + value.OldAccountId = reader.Read(sizeof(System.Int32)); + value.NewAccountId = reader.Read(sizeof(System.Int32)); + value.MergeDate = reader.Read(sizeof(System.DateTime)); + return value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetSize(AccountMerge value) + { + if(value == null) + { + return 1; + } + int ret = 1; + ret += Nino.Serialization.Serializer.GetSize(value.OldAccountId); + ret += Nino.Serialization.Serializer.GetSize(value.NewAccountId); + ret += Nino.Serialization.Serializer.GetSize(value.MergeDate); + return ret; + } + #endregion + } + } +} \ No newline at end of file diff --git a/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_Answer_Serialize.cs b/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_Answer_Serialize.cs new file mode 100644 index 0000000..3d474d2 --- /dev/null +++ b/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_Answer_Serialize.cs @@ -0,0 +1,116 @@ +/* this is generated by nino */ +using System.Runtime.CompilerServices; + +namespace Nino.Benchmark.Models +{ + public partial class Answer + { + public static Answer.SerializationHelper NinoSerializationHelper = new Answer.SerializationHelper(); + public unsafe class SerializationHelper: Nino.Serialization.NinoWrapperBase + { + #region NINO_CODEGEN + public SerializationHelper() + { + + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void Serialize(Answer value, ref Nino.Serialization.Writer writer) + { + if(value == null) + { + writer.Write(false); + return; + } + writer.Write(true); + writer.Write(value.QuestionId); + writer.Write(value.AnswerId); + writer.Write(value.LockedDate); + writer.Write(value.CreationDate); + writer.Write(value.LastEditDate); + writer.Write(value.LastActivityDate); + writer.Write(value.Score); + writer.Write(value.CommunityOwnedDate); + writer.Write(value.IsAccepted); + writer.Write(value.Body); + writer.Write(value.Title); + writer.Write(value.UpVoteCount); + writer.Write(value.DownVoteCount); + writer.Write(value.Comments); + writer.Write(value.Link); + writer.Write(value.Tags); + writer.Write(value.Upvoted); + writer.Write(value.Downvoted); + writer.Write(value.Accepted); + writer.Write(value.CommentCount); + writer.Write(value.BodyMarkdown); + writer.Write(value.ShareLink); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override Answer Deserialize(Nino.Serialization.Reader reader) + { + if(!reader.ReadBool()) + return null; + Answer value = new Answer(); + value.QuestionId = reader.Read(sizeof(System.Int32)); + value.AnswerId = reader.Read(sizeof(System.Int32)); + value.LockedDate = reader.Read(sizeof(System.DateTime)); + value.CreationDate = reader.Read(sizeof(System.DateTime)); + value.LastEditDate = reader.Read(sizeof(System.DateTime)); + value.LastActivityDate = reader.Read(sizeof(System.DateTime)); + value.Score = reader.Read(sizeof(System.Int32)); + value.CommunityOwnedDate = reader.Read(sizeof(System.DateTime)); + value.IsAccepted = reader.Read(sizeof(System.Boolean)); + value.Body = reader.ReadString(); + value.Title = reader.ReadString(); + value.UpVoteCount = reader.Read(sizeof(System.Int32)); + value.DownVoteCount = reader.Read(sizeof(System.Int32)); + value.Comments = reader.ReadList(); + value.Link = reader.ReadString(); + value.Tags = reader.ReadList(); + value.Upvoted = reader.Read(sizeof(System.Boolean)); + value.Downvoted = reader.Read(sizeof(System.Boolean)); + value.Accepted = reader.Read(sizeof(System.Boolean)); + value.CommentCount = reader.Read(sizeof(System.Int32)); + value.BodyMarkdown = reader.ReadString(); + value.ShareLink = reader.ReadString(); + return value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetSize(Answer value) + { + if(value == null) + { + return 1; + } + int ret = 1; + ret += Nino.Serialization.Serializer.GetSize(value.QuestionId); + ret += Nino.Serialization.Serializer.GetSize(value.AnswerId); + ret += Nino.Serialization.Serializer.GetSize(value.LockedDate); + ret += Nino.Serialization.Serializer.GetSize(value.CreationDate); + ret += Nino.Serialization.Serializer.GetSize(value.LastEditDate); + ret += Nino.Serialization.Serializer.GetSize(value.LastActivityDate); + ret += Nino.Serialization.Serializer.GetSize(value.Score); + ret += Nino.Serialization.Serializer.GetSize(value.CommunityOwnedDate); + ret += Nino.Serialization.Serializer.GetSize(value.IsAccepted); + ret += Nino.Serialization.Serializer.GetSize(value.Body); + ret += Nino.Serialization.Serializer.GetSize(value.Title); + ret += Nino.Serialization.Serializer.GetSize(value.UpVoteCount); + ret += Nino.Serialization.Serializer.GetSize(value.DownVoteCount); + ret += Nino.Serialization.Serializer.GetSize(value.Comments); + ret += Nino.Serialization.Serializer.GetSize(value.Link); + ret += Nino.Serialization.Serializer.GetSize(value.Tags); + ret += Nino.Serialization.Serializer.GetSize(value.Upvoted); + ret += Nino.Serialization.Serializer.GetSize(value.Downvoted); + ret += Nino.Serialization.Serializer.GetSize(value.Accepted); + ret += Nino.Serialization.Serializer.GetSize(value.CommentCount); + ret += Nino.Serialization.Serializer.GetSize(value.BodyMarkdown); + ret += Nino.Serialization.Serializer.GetSize(value.ShareLink); + return ret; + } + #endregion + } + } +} \ No newline at end of file diff --git a/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_Badge_Serialize.cs b/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_Badge_Serialize.cs new file mode 100644 index 0000000..ab942b1 --- /dev/null +++ b/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_Badge_Serialize.cs @@ -0,0 +1,65 @@ +/* this is generated by nino */ +using System.Runtime.CompilerServices; + +namespace Nino.Benchmark.Models +{ + public partial class Badge + { + public static Badge.SerializationHelper NinoSerializationHelper = new Badge.SerializationHelper(); + public unsafe class SerializationHelper: Nino.Serialization.NinoWrapperBase + { + #region NINO_CODEGEN + public SerializationHelper() + { + + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void Serialize(Badge value, ref Nino.Serialization.Writer writer) + { + if(value == null) + { + writer.Write(false); + return; + } + writer.Write(true); + writer.Write(value.BadgeId); + writer.Write(value.Name); + writer.Write(value.Description); + writer.Write(value.AwardCount); + writer.Write(value.Link); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override Badge Deserialize(Nino.Serialization.Reader reader) + { + if(!reader.ReadBool()) + return null; + Badge value = new Badge(); + value.BadgeId = reader.Read(sizeof(System.Int32)); + value.Name = reader.ReadString(); + value.Description = reader.ReadString(); + value.AwardCount = reader.Read(sizeof(System.Int32)); + value.Link = reader.ReadString(); + return value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetSize(Badge value) + { + if(value == null) + { + return 1; + } + int ret = 1; + ret += Nino.Serialization.Serializer.GetSize(value.BadgeId); + ret += Nino.Serialization.Serializer.GetSize(value.Name); + ret += Nino.Serialization.Serializer.GetSize(value.Description); + ret += Nino.Serialization.Serializer.GetSize(value.AwardCount); + ret += Nino.Serialization.Serializer.GetSize(value.Link); + return ret; + } + #endregion + } + } +} \ No newline at end of file diff --git a/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_Comment_Serialize.cs b/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_Comment_Serialize.cs new file mode 100644 index 0000000..1441fe2 --- /dev/null +++ b/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_Comment_Serialize.cs @@ -0,0 +1,77 @@ +/* this is generated by nino */ +using System.Runtime.CompilerServices; + +namespace Nino.Benchmark.Models +{ + public partial class Comment + { + public static Comment.SerializationHelper NinoSerializationHelper = new Comment.SerializationHelper(); + public unsafe class SerializationHelper: Nino.Serialization.NinoWrapperBase + { + #region NINO_CODEGEN + public SerializationHelper() + { + + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void Serialize(Comment value, ref Nino.Serialization.Writer writer) + { + if(value == null) + { + writer.Write(false); + return; + } + writer.Write(true); + writer.Write(value.CommentId); + writer.Write(value.PostId); + writer.Write(value.CreationDate); + writer.Write(value.Score); + writer.Write(value.Edited); + writer.Write(value.Body); + writer.Write(value.Link); + writer.Write(value.BodyMarkdown); + writer.Write(value.Upvoted); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override Comment Deserialize(Nino.Serialization.Reader reader) + { + if(!reader.ReadBool()) + return null; + Comment value = new Comment(); + value.CommentId = reader.Read(sizeof(System.Int32)); + value.PostId = reader.Read(sizeof(System.Int32)); + value.CreationDate = reader.Read(sizeof(System.DateTime)); + value.Score = reader.Read(sizeof(System.Int32)); + value.Edited = reader.Read(sizeof(System.Boolean)); + value.Body = reader.ReadString(); + value.Link = reader.ReadString(); + value.BodyMarkdown = reader.ReadString(); + value.Upvoted = reader.Read(sizeof(System.Boolean)); + return value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetSize(Comment value) + { + if(value == null) + { + return 1; + } + int ret = 1; + ret += Nino.Serialization.Serializer.GetSize(value.CommentId); + ret += Nino.Serialization.Serializer.GetSize(value.PostId); + ret += Nino.Serialization.Serializer.GetSize(value.CreationDate); + ret += Nino.Serialization.Serializer.GetSize(value.Score); + ret += Nino.Serialization.Serializer.GetSize(value.Edited); + ret += Nino.Serialization.Serializer.GetSize(value.Body); + ret += Nino.Serialization.Serializer.GetSize(value.Link); + ret += Nino.Serialization.Serializer.GetSize(value.BodyMarkdown); + ret += Nino.Serialization.Serializer.GetSize(value.Upvoted); + return ret; + } + #endregion + } + } +} \ No newline at end of file diff --git a/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_Data_Serialize.cs b/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_Data_Serialize.cs new file mode 100644 index 0000000..bf745a2 --- /dev/null +++ b/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_Data_Serialize.cs @@ -0,0 +1,67 @@ +/* this is generated by nino */ +using System.Runtime.CompilerServices; + +namespace Nino.Benchmark.Models +{ + public partial struct Data + { + public static Data.SerializationHelper NinoSerializationHelper = new Data.SerializationHelper(); + public unsafe class SerializationHelper: Nino.Serialization.NinoWrapperBase + { + #region NINO_CODEGEN + public SerializationHelper() + { + int ret = 1; + ret += sizeof(System.Int32); + ret += sizeof(System.Int16); + ret += sizeof(System.Int64); + ret += sizeof(System.Single); + ret += sizeof(System.Decimal); + ret += sizeof(System.Double); + ret += sizeof(System.Boolean); + ret += sizeof(Nino.Benchmark.Models.TestEnum); + Nino.Serialization.Serializer.SetFixedSize(ret); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void Serialize(Data value, ref Nino.Serialization.Writer writer) + { + + writer.Write(true); + writer.Write(ref value.X, sizeof(System.Int32)); + writer.Write(ref value.Y, sizeof(System.Int16)); + writer.Write(ref value.Z, sizeof(System.Int64)); + writer.Write(ref value.F, sizeof(System.Single)); + writer.Write(ref value.D, sizeof(System.Decimal)); + writer.Write(ref value.Db, sizeof(System.Double)); + writer.Write(ref value.Bo, sizeof(System.Boolean)); + writer.WriteEnum(value.En); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override Data Deserialize(Nino.Serialization.Reader reader) + { + if(!reader.ReadBool()) + return default; + Data value = new Data(); + reader.Read(ref value.X, sizeof(System.Int32)); + reader.Read(ref value.Y, sizeof(System.Int16)); + reader.Read(ref value.Z, sizeof(System.Int64)); + reader.Read(ref value.F, sizeof(System.Single)); + reader.Read(ref value.D, sizeof(System.Decimal)); + reader.Read(ref value.Db, sizeof(System.Double)); + reader.Read(ref value.Bo, sizeof(System.Boolean)); + reader.ReadEnum(ref value.En); + return value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetSize(Data value) + { + + return Nino.Serialization.Serializer.GetFixedSize(); + } + #endregion + } + } +} \ No newline at end of file diff --git a/src/Nino.Benchmark/Nino/Generated/Nino_Benchmark_Models_NestedData_Serialize.cs b/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_NestedData_Serialize.cs similarity index 52% rename from src/Nino.Benchmark/Nino/Generated/Nino_Benchmark_Models_NestedData_Serialize.cs rename to src/Nino.Benchmark/Generated/Nino_Benchmark_Models_NestedData_Serialize.cs index 0e3fff1..1a3b50e 100644 --- a/src/Nino.Benchmark/Nino/Generated/Nino_Benchmark_Models_NestedData_Serialize.cs +++ b/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_NestedData_Serialize.cs @@ -1,13 +1,21 @@ /* this is generated by nino */ +using System.Runtime.CompilerServices; + namespace Nino.Benchmark.Models { public partial class NestedData { public static NestedData.SerializationHelper NinoSerializationHelper = new NestedData.SerializationHelper(); - public class SerializationHelper: Nino.Serialization.NinoWrapperBase + public unsafe class SerializationHelper: Nino.Serialization.NinoWrapperBase { #region NINO_CODEGEN - public override void Serialize(NestedData value, Nino.Serialization.Writer writer) + public SerializationHelper() + { + + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void Serialize(NestedData value, ref Nino.Serialization.Writer writer) { if(value == null) { @@ -19,6 +27,7 @@ public override void Serialize(NestedData value, Nino.Serialization.Writer write writer.Write(value.Ps); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override NestedData Deserialize(Nino.Serialization.Reader reader) { if(!reader.ReadBool()) @@ -28,6 +37,19 @@ public override NestedData Deserialize(Nino.Serialization.Reader reader) value.Ps = reader.ReadArray(); return value; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetSize(NestedData value) + { + if(value == null) + { + return 1; + } + int ret = 1; + ret += Nino.Serialization.Serializer.GetSize(value.Name); + ret += Nino.Serialization.Serializer.GetSize(value.Ps); + return ret; + } #endregion } } diff --git a/src/Nino.Benchmark/Nino/Generated/Nino_Benchmark_Models_AccessToken_Serialize.cs b/src/Nino.Benchmark/Nino/Generated/Nino_Benchmark_Models_AccessToken_Serialize.cs deleted file mode 100644 index 1c0a174..0000000 --- a/src/Nino.Benchmark/Nino/Generated/Nino_Benchmark_Models_AccessToken_Serialize.cs +++ /dev/null @@ -1,38 +0,0 @@ -/* this is generated by nino */ -namespace Nino.Benchmark.Models -{ - public partial class AccessToken - { - public static AccessToken.SerializationHelper NinoSerializationHelper = new AccessToken.SerializationHelper(); - public class SerializationHelper: Nino.Serialization.NinoWrapperBase - { - #region NINO_CODEGEN - public override void Serialize(AccessToken value, Nino.Serialization.Writer writer) - { - if(value == null) - { - writer.Write(false); - return; - } - writer.Write(true); - writer.Write(value.Token); - writer.Write(value.ExpiresOnDate); - writer.CompressAndWrite(value.AccountId); - writer.Write(value.Scope); - } - - public override AccessToken Deserialize(Nino.Serialization.Reader reader) - { - if(!reader.ReadBool()) - return null; - AccessToken value = new AccessToken(); - value.Token = reader.ReadString(); - value.ExpiresOnDate = reader.ReadDateTime(); - value.AccountId = reader.DecompressAndReadNumber(); - value.Scope = reader.ReadList(); - return value; - } - #endregion - } - } -} \ No newline at end of file diff --git a/src/Nino.Benchmark/Nino/Generated/Nino_Benchmark_Models_AccountMerge_Serialize.cs b/src/Nino.Benchmark/Nino/Generated/Nino_Benchmark_Models_AccountMerge_Serialize.cs deleted file mode 100644 index 609be6e..0000000 --- a/src/Nino.Benchmark/Nino/Generated/Nino_Benchmark_Models_AccountMerge_Serialize.cs +++ /dev/null @@ -1,36 +0,0 @@ -/* this is generated by nino */ -namespace Nino.Benchmark.Models -{ - public partial class AccountMerge - { - public static AccountMerge.SerializationHelper NinoSerializationHelper = new AccountMerge.SerializationHelper(); - public class SerializationHelper: Nino.Serialization.NinoWrapperBase - { - #region NINO_CODEGEN - public override void Serialize(AccountMerge value, Nino.Serialization.Writer writer) - { - if(value == null) - { - writer.Write(false); - return; - } - writer.Write(true); - writer.CompressAndWrite(value.OldAccountId); - writer.CompressAndWrite(value.NewAccountId); - writer.Write(value.MergeDate); - } - - public override AccountMerge Deserialize(Nino.Serialization.Reader reader) - { - if(!reader.ReadBool()) - return null; - AccountMerge value = new AccountMerge(); - value.OldAccountId = reader.DecompressAndReadNumber(); - value.NewAccountId = reader.DecompressAndReadNumber(); - value.MergeDate = reader.ReadDateTime(); - return value; - } - #endregion - } - } -} \ No newline at end of file diff --git a/src/Nino.Benchmark/Nino/Generated/Nino_Benchmark_Models_Answer_Serialize.cs b/src/Nino.Benchmark/Nino/Generated/Nino_Benchmark_Models_Answer_Serialize.cs deleted file mode 100644 index 91821f2..0000000 --- a/src/Nino.Benchmark/Nino/Generated/Nino_Benchmark_Models_Answer_Serialize.cs +++ /dev/null @@ -1,74 +0,0 @@ -/* this is generated by nino */ -namespace Nino.Benchmark.Models -{ - public partial class Answer - { - public static Answer.SerializationHelper NinoSerializationHelper = new Answer.SerializationHelper(); - public class SerializationHelper: Nino.Serialization.NinoWrapperBase - { - #region NINO_CODEGEN - public override void Serialize(Answer value, Nino.Serialization.Writer writer) - { - if(value == null) - { - writer.Write(false); - return; - } - writer.Write(true); - writer.CompressAndWrite(value.QuestionId); - writer.CompressAndWrite(value.AnswerId); - writer.Write(value.LockedDate); - writer.Write(value.CreationDate); - writer.Write(value.LastEditDate); - writer.Write(value.LastActivityDate); - writer.CompressAndWrite(value.Score); - writer.Write(value.CommunityOwnedDate); - writer.Write(value.IsAccepted); - writer.Write(value.Body); - writer.Write(value.Title); - writer.CompressAndWrite(value.UpVoteCount); - writer.CompressAndWrite(value.DownVoteCount); - writer.Write(value.Comments); - writer.Write(value.Link); - writer.Write(value.Tags); - writer.Write(value.Upvoted); - writer.Write(value.Downvoted); - writer.Write(value.Accepted); - writer.CompressAndWrite(value.CommentCount); - writer.Write(value.BodyMarkdown); - writer.Write(value.ShareLink); - } - - public override Answer Deserialize(Nino.Serialization.Reader reader) - { - if(!reader.ReadBool()) - return null; - Answer value = new Answer(); - value.QuestionId = reader.DecompressAndReadNumber(); - value.AnswerId = reader.DecompressAndReadNumber(); - value.LockedDate = reader.ReadDateTime(); - value.CreationDate = reader.ReadDateTime(); - value.LastEditDate = reader.ReadDateTime(); - value.LastActivityDate = reader.ReadDateTime(); - value.Score = reader.DecompressAndReadNumber(); - value.CommunityOwnedDate = reader.ReadDateTime(); - value.IsAccepted = reader.ReadBool(); - value.Body = reader.ReadString(); - value.Title = reader.ReadString(); - value.UpVoteCount = reader.DecompressAndReadNumber(); - value.DownVoteCount = reader.DecompressAndReadNumber(); - value.Comments = reader.ReadList(); - value.Link = reader.ReadString(); - value.Tags = reader.ReadList(); - value.Upvoted = reader.ReadBool(); - value.Downvoted = reader.ReadBool(); - value.Accepted = reader.ReadBool(); - value.CommentCount = reader.DecompressAndReadNumber(); - value.BodyMarkdown = reader.ReadString(); - value.ShareLink = reader.ReadString(); - return value; - } - #endregion - } - } -} \ No newline at end of file diff --git a/src/Nino.Benchmark/Nino/Generated/Nino_Benchmark_Models_Badge_Serialize.cs b/src/Nino.Benchmark/Nino/Generated/Nino_Benchmark_Models_Badge_Serialize.cs deleted file mode 100644 index 13277ed..0000000 --- a/src/Nino.Benchmark/Nino/Generated/Nino_Benchmark_Models_Badge_Serialize.cs +++ /dev/null @@ -1,40 +0,0 @@ -/* this is generated by nino */ -namespace Nino.Benchmark.Models -{ - public partial class Badge - { - public static Badge.SerializationHelper NinoSerializationHelper = new Badge.SerializationHelper(); - public class SerializationHelper: Nino.Serialization.NinoWrapperBase - { - #region NINO_CODEGEN - public override void Serialize(Badge value, Nino.Serialization.Writer writer) - { - if(value == null) - { - writer.Write(false); - return; - } - writer.Write(true); - writer.CompressAndWrite(value.BadgeId); - writer.Write(value.Name); - writer.Write(value.Description); - writer.CompressAndWrite(value.AwardCount); - writer.Write(value.Link); - } - - public override Badge Deserialize(Nino.Serialization.Reader reader) - { - if(!reader.ReadBool()) - return null; - Badge value = new Badge(); - value.BadgeId = reader.DecompressAndReadNumber(); - value.Name = reader.ReadString(); - value.Description = reader.ReadString(); - value.AwardCount = reader.DecompressAndReadNumber(); - value.Link = reader.ReadString(); - return value; - } - #endregion - } - } -} \ No newline at end of file diff --git a/src/Nino.Benchmark/Nino/Generated/Nino_Benchmark_Models_Comment_Serialize.cs b/src/Nino.Benchmark/Nino/Generated/Nino_Benchmark_Models_Comment_Serialize.cs deleted file mode 100644 index 69821c9..0000000 --- a/src/Nino.Benchmark/Nino/Generated/Nino_Benchmark_Models_Comment_Serialize.cs +++ /dev/null @@ -1,48 +0,0 @@ -/* this is generated by nino */ -namespace Nino.Benchmark.Models -{ - public partial class Comment - { - public static Comment.SerializationHelper NinoSerializationHelper = new Comment.SerializationHelper(); - public class SerializationHelper: Nino.Serialization.NinoWrapperBase - { - #region NINO_CODEGEN - public override void Serialize(Comment value, Nino.Serialization.Writer writer) - { - if(value == null) - { - writer.Write(false); - return; - } - writer.Write(true); - writer.CompressAndWrite(value.CommentId); - writer.CompressAndWrite(value.PostId); - writer.Write(value.CreationDate); - writer.CompressAndWrite(value.Score); - writer.Write(value.Edited); - writer.Write(value.Body); - writer.Write(value.Link); - writer.Write(value.BodyMarkdown); - writer.Write(value.Upvoted); - } - - public override Comment Deserialize(Nino.Serialization.Reader reader) - { - if(!reader.ReadBool()) - return null; - Comment value = new Comment(); - value.CommentId = reader.DecompressAndReadNumber(); - value.PostId = reader.DecompressAndReadNumber(); - value.CreationDate = reader.ReadDateTime(); - value.Score = reader.DecompressAndReadNumber(); - value.Edited = reader.ReadBool(); - value.Body = reader.ReadString(); - value.Link = reader.ReadString(); - value.BodyMarkdown = reader.ReadString(); - value.Upvoted = reader.ReadBool(); - return value; - } - #endregion - } - } -} \ No newline at end of file diff --git a/src/Nino.Benchmark/Nino/Generated/Nino_Benchmark_Models_Data_Serialize.cs b/src/Nino.Benchmark/Nino/Generated/Nino_Benchmark_Models_Data_Serialize.cs deleted file mode 100644 index 958c73a..0000000 --- a/src/Nino.Benchmark/Nino/Generated/Nino_Benchmark_Models_Data_Serialize.cs +++ /dev/null @@ -1,48 +0,0 @@ -/* this is generated by nino */ -namespace Nino.Benchmark.Models -{ - public partial class Data - { - public static Data.SerializationHelper NinoSerializationHelper = new Data.SerializationHelper(); - public class SerializationHelper: Nino.Serialization.NinoWrapperBase - { - #region NINO_CODEGEN - public override void Serialize(Data value, Nino.Serialization.Writer writer) - { - if(value == null) - { - writer.Write(false); - return; - } - writer.Write(true); - writer.CompressAndWrite(ref value.X); - writer.Write(value.Y); - writer.CompressAndWrite(ref value.Z); - writer.Write(value.F); - writer.Write(value.D); - writer.Write(value.Db); - writer.Write(value.Bo); - writer.CompressAndWriteEnum(value.En); - writer.Write(value.Name); - } - - public override Data Deserialize(Nino.Serialization.Reader reader) - { - if(!reader.ReadBool()) - return null; - Data value = new Data(); - reader.DecompressAndReadNumber(ref value.X); - reader.Read(ref value.Y, Nino.Shared.Mgr.ConstMgr.SizeOfShort); - reader.DecompressAndReadNumber(ref value.Z); - reader.Read(ref value.F, Nino.Shared.Mgr.ConstMgr.SizeOfUInt); - reader.Read(ref value.D, Nino.Shared.Mgr.ConstMgr.SizeOfDecimal); - reader.Read(ref value.Db, Nino.Shared.Mgr.ConstMgr.SizeOfULong); - reader.Read(ref value.Bo, 1); - reader.DecompressAndReadEnum(ref value.En); - value.Name = reader.ReadString(); - return value; - } - #endregion - } - } -} \ No newline at end of file diff --git a/src/Nino.Benchmark/Serialization/Models/Data.cs b/src/Nino.Benchmark/Serialization/Models/Data.cs index b213b10..a1f3b69 100644 --- a/src/Nino.Benchmark/Serialization/Models/Data.cs +++ b/src/Nino.Benchmark/Serialization/Models/Data.cs @@ -11,7 +11,7 @@ namespace Nino.Benchmark.Models [NinoSerialize] [MessagePackObject] [System.Runtime.Serialization.DataContract] - public partial class Data + public partial struct Data { [ProtoMember(1)] [NinoMember(1)] @@ -62,15 +62,9 @@ public partial class Data [System.Runtime.Serialization.EnumMember] public TestEnum En; - [ProtoMember(9)] - [NinoMember(9)] - [Key(9)] - [System.Runtime.Serialization.DataMember] - public string Name = ""; - public override string ToString() { - return $"{X},{Y},{Z},{F},{D},{Db},{Bo},{En},{Name}"; + return $"{X},{Y},{Z},{F},{D},{Db},{Bo},{En}"; } } diff --git a/src/Nino.Benchmark/Serialization/SerializationBenchmark.cs b/src/Nino.Benchmark/Serialization/SerializationBenchmark.cs index 3afaed9..e8e918b 100644 --- a/src/Nino.Benchmark/Serialization/SerializationBenchmark.cs +++ b/src/Nino.Benchmark/Serialization/SerializationBenchmark.cs @@ -28,8 +28,7 @@ public class SerializationBenchmark new FsPicklerSerializer(), new CerasSerializer(), new OdinSerializer_(), - new NinoSerializer_ZLib(), - new NinoSerializer_NoCompression() + new NinoSerializer(), }; static SerializationBenchmark() @@ -48,7 +47,6 @@ static SerializationBenchmark() Db = 999.999999999999, Bo = true, En = TestEnum.A, - Name = GetString(20) }; } diff --git a/src/Nino.Benchmark/Serialization/Serializers/NinoSerializer.cs b/src/Nino.Benchmark/Serialization/Serializers/NinoSerializer.cs index de41bbd..379fe6f 100644 --- a/src/Nino.Benchmark/Serialization/Serializers/NinoSerializer.cs +++ b/src/Nino.Benchmark/Serialization/Serializers/NinoSerializer.cs @@ -2,7 +2,7 @@ namespace Nino.Benchmark.Serializers { - public class NinoSerializer_ZLib : SerializerBase + public class NinoSerializer : SerializerBase { public override T Deserialize(object input) { @@ -16,24 +16,7 @@ public override object Serialize(T input) public override string ToString() { - return "Nino_Zlib"; - } - } - public class NinoSerializer_NoCompression : SerializerBase - { - public override T Deserialize(object input) - { - return Deserializer.Deserialize((byte[])input, CompressOption.NoCompression); - } - - public override object Serialize(T input) - { - return Serializer.Serialize(input, CompressOption.NoCompression); - } - - public override string ToString() - { - return "Nino_NoComp"; + return "Nino"; } } } diff --git a/src/Nino.Serialization/CodeGenerator.cs b/src/Nino.Serialization/CodeGenerator.cs index 015f1d5..9bff4d5 100644 --- a/src/Nino.Serialization/CodeGenerator.cs +++ b/src/Nino.Serialization/CodeGenerator.cs @@ -6,6 +6,7 @@ using Nino.Shared.Util; using System.Reflection; using System.Collections.Generic; +using System.Runtime.CompilerServices; namespace Nino.Serialization { @@ -93,32 +94,44 @@ public static void GenerateSerializationCode(Type type, string outputPath = "Nin //code template string template = @"/* this is generated by nino */ +using System.Runtime.CompilerServices; + {namespace} {start} public partial struct {type} { public static {type}.SerializationHelper NinoSerializationHelper = new {type}.SerializationHelper(); - public class SerializationHelper: Nino.Serialization.NinoWrapperBase<{type}> + public unsafe class SerializationHelper: Nino.Serialization.NinoWrapperBase<{type}> { #region NINO_CODEGEN - public override void Serialize({type} value, Nino.Serialization.Writer writer) + public SerializationHelper() { - if(value == null) - { - writer.Write(false); - return; - } +{ctor} + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void Serialize({type} value, ref Nino.Serialization.Writer writer) + { + {nullCheck} writer.Write(true); {members} } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override {type} Deserialize(Nino.Serialization.Reader reader) { if(!reader.ReadBool()) - return null; + {returnNull} {type} value = new {type}(); {fields} } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetSize({type} value) + { + {sizeNull} +{size} + } #endregion } } @@ -126,6 +139,22 @@ public override void Serialize({type} value, Nino.Serialization.Writer writer) if (type.IsClass) { template = template.Replace("struct", "class"); + template = template.Replace("{nullCheck}", @"if(value == null) + { + writer.Write(false); + return; + }"); + template = template.Replace("{returnNull}", "return null;"); + template = template.Replace("{sizeNull}", @"if(value == null) + { + return 1; + }"); + } + else + { + template = template.Replace("{nullCheck}", @""); + template = template.Replace("{returnNull}", "return default;"); + template = template.Replace("{sizeNull}", @""); } //replace namespace @@ -178,7 +207,7 @@ public override void Serialize({type} value, Nino.Serialization.Writer writer) if (mt.IsEnum) { sb.Append( - $" writer.CompressAndWriteEnum<{BeautifulLongTypeName(mt)}>(value.{member.Name});\n"); + $" writer.WriteEnum<{BeautifulLongTypeName(mt)}>(value.{member.Name});\n"); } //array/list else if (mt.IsArray || (mt.IsGenericType && mt.GetGenericTypeDefinition() == ConstMgr.ListDefType)) @@ -193,7 +222,8 @@ public override void Serialize({type} value, Nino.Serialization.Writer writer) //basic type else { - sb.Append($" {GetSerializeBasicTypeStatement(mt, $"value.{member.Name}", member is PropertyInfo)};\n"); + sb.Append( + $" {GetSerializeBasicTypeStatement(mt, $"value.{member.Name}", member is PropertyInfo)};\n"); } } @@ -220,12 +250,12 @@ public override void Serialize({type} value, Nino.Serialization.Writer writer) if (member is PropertyInfo) { sb.Append( - $" value.{member.Name} = reader.DecompressAndReadEnum<{BeautifulLongTypeName(mt)}>();\n"); + $" value.{member.Name} = reader.ReadEnum<{BeautifulLongTypeName(mt)}>();\n"); } else { sb.Append( - $" reader.DecompressAndReadEnum<{BeautifulLongTypeName(mt)}>(ref value.{member.Name});\n"); + $" reader.ReadEnum<{BeautifulLongTypeName(mt)}>(ref value.{member.Name});\n"); } } //array/list @@ -242,7 +272,7 @@ public override void Serialize({type} value, Nino.Serialization.Writer writer) throw new NotSupportedException( "can not serialize multidimensional array, use jagged array instead"); } - + sb.Append( $" value.{member.Name} = reader.ReadArray<{BeautifulLongTypeName(elemType)}>();\n"); } @@ -267,20 +297,7 @@ public override void Serialize({type} value, Nino.Serialization.Writer writer) { string val = GetDeserializeBasicTypeStatement(mt, member is PropertyInfo, $"value.{member.Name}"); - switch (Type.GetTypeCode(mt)) - { - case TypeCode.Int32: - case TypeCode.UInt32: - case TypeCode.Int64: - case TypeCode.UInt64: - sb.Append($" {val}\n"); - break; - default: - sb.Append(FullDeserializeStatement(mt, member is PropertyInfo) - ? $" {val}\n" - : $" value.{member.Name} = {val};\n"); - break; - } + sb.Append($" {val}\n"); } } @@ -293,6 +310,49 @@ public override void Serialize({type} value, Nino.Serialization.Writer writer) #endregion + #region getsize + + sb.Clear(); + if (TypeModel.IsUnmanaged(type)) + { + sb.Append($" return Nino.Serialization.Serializer.GetFixedSize<{BeautifulLongTypeName(type)}>();"); + } + else + { + sb.Append(" int ret = 1;\n"); + foreach (var member in members) + { + sb.Append( + $" ret += Nino.Serialization.Serializer.GetSize(value.{member.Name});\n"); + } + sb.Append(" return ret;"); + } + + //replace template fields + template = template.Replace("{size}", sb.ToString()); + + #endregion + + #region ctor + + sb.Clear(); + if (TypeModel.IsUnmanaged(type)) + { + sb.Append(" int ret = 1;\n"); + foreach (var member in members) + { + var mt = member is FieldInfo fi ? fi.FieldType : ((PropertyInfo)member).PropertyType; + sb.Append( + $" ret += sizeof({BeautifulLongTypeName(mt)});\n"); + } + sb.Append($" Nino.Serialization.Serializer.SetFixedSize<{BeautifulLongTypeName(type)}>(ret);"); + } + + //replace template fields + template = template.Replace("{ctor}", sb.ToString()); + + #endregion + //save path var output = Path.Combine(ConstMgr.AssetPath, outputPath); if (!Directory.Exists(output)) @@ -321,31 +381,6 @@ public override void Serialize({type} value, Nino.Serialization.Writer writer) #endif } - private static bool FullDeserializeStatement(Type type, bool isProperty) - { - if (isProperty) return false; - switch (Type.GetTypeCode(type)) - { - case TypeCode.Byte: - case TypeCode.SByte: - case TypeCode.Int16: - case TypeCode.UInt16: - case TypeCode.Boolean: - case TypeCode.Double: - case TypeCode.Single: - case TypeCode.Decimal: - case TypeCode.Char: - return true; - default: - if ((type.IsGenericType && type.GetGenericTypeDefinition() == ConstMgr.DictDefType)) - { - return true; - } - - return false; - } - } - // ReSharper disable CognitiveComplexity private static string GetDeserializeBasicTypeStatement(Type mt, bool isProperty, string val = "", string space = " ") @@ -357,55 +392,33 @@ private static string GetDeserializeBasicTypeStatement(Type mt, bool isProperty, case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: - return isProperty - ? $"{val} = reader.DecompressAndReadNumber<{BeautifulLongTypeName(mt)}>();" - : $"reader.DecompressAndReadNumber<{BeautifulLongTypeName(mt)}>(ref {val});"; case TypeCode.Byte: - return isProperty ? "reader.ReadByte()" : $"reader.Read(ref {val}, 1);"; case TypeCode.SByte: - return isProperty ? "reader.ReadSByte()" : $"reader.Read(ref {val}, 1);"; case TypeCode.Int16: - return isProperty - ? "reader.ReadInt16()" - : $"reader.Read(ref {val}, Nino.Shared.Mgr.ConstMgr.SizeOfShort);"; case TypeCode.UInt16: - return isProperty - ? "reader.ReadUInt16()" - : $"reader.Read(ref {val}, Nino.Shared.Mgr.ConstMgr.SizeOfUShort);"; - case TypeCode.String: - return "reader.ReadString()"; case TypeCode.Boolean: - return isProperty ? "reader.ReadBool()" : $"reader.Read(ref {val}, 1);"; case TypeCode.Double: - return isProperty - ? "reader.ReadDouble()" - : $"reader.Read(ref {val}, Nino.Shared.Mgr.ConstMgr.SizeOfULong);"; case TypeCode.Single: - return isProperty - ? "reader.ReadSingle()" - : $"reader.Read(ref {val}, Nino.Shared.Mgr.ConstMgr.SizeOfUInt);"; case TypeCode.Decimal: - return isProperty - ? "reader.ReadDecimal()" - : $"reader.Read(ref {val}, Nino.Shared.Mgr.ConstMgr.SizeOfDecimal);"; case TypeCode.Char: - return isProperty - ? "reader.ReadChar()" - : $"reader.Read(ref {val}, Nino.Shared.Mgr.ConstMgr.SizeOfUShort);"; case TypeCode.DateTime: - return "reader.ReadDateTime()"; + return isProperty + ? $"{val} = reader.Read<{BeautifulLongTypeName(mt)}>(sizeof({BeautifulLongTypeName(mt)}));" + : $"reader.Read<{BeautifulLongTypeName(mt)}>(ref {val}, sizeof({BeautifulLongTypeName(mt)}));"; + case TypeCode.String: + return $"{val} = reader.ReadString();"; default: if (GetValidNinoClass(mt, false)) { - return $"{BeautifulLongTypeName(mt)}.NinoSerializationHelper.Deserialize(reader)"; + return $"{val} = {BeautifulLongTypeName(mt)}.NinoSerializationHelper.Deserialize(reader)"; } - + //enum if (mt.IsEnum) { return isProperty - ? $"reader.DecompressAndReadEnum<{BeautifulLongTypeName(mt)}>()" - : $"reader.DecompressAndReadEnum<{BeautifulLongTypeName(mt)}>(ref {val});"; + ? $"{val} = reader.ReadEnum<{BeautifulLongTypeName(mt)}>();" + : $"reader.ReadEnum<{BeautifulLongTypeName(mt)}>(ref {val});"; } if (mt.IsArray || @@ -421,15 +434,16 @@ private static string GetDeserializeBasicTypeStatement(Type mt, bool isProperty, throw new NotSupportedException( "can not serialize multidimensional array, use jagged array instead"); } - + builder.Append( - $"reader.ReadArray<{BeautifulLongTypeName(elemType)}>();\n"); + $"{val} = reader.ReadArray<{BeautifulLongTypeName(elemType)}>();\n"); } else { builder.Append( - $"reader.ReadList<{BeautifulLongTypeName(elemType)}>();\n"); + $"{val} = reader.ReadList<{BeautifulLongTypeName(elemType)}>();\n"); } + return builder.ToString(); } @@ -445,7 +459,7 @@ private static string GetDeserializeBasicTypeStatement(Type mt, bool isProperty, return builder.ToString(); } - return $"reader.ReadCommonVal<{BeautifulLongTypeName(mt)}>()"; + return $"{val} = reader.ReadCommonVal<{BeautifulLongTypeName(mt)}>();"; } } @@ -460,18 +474,20 @@ private static string GetSerializeBasicTypeStatement(Type mt, string val, bool i case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: - return isProperty ? $"writer.CompressAndWrite({val})" : $"writer.CompressAndWrite(ref {val})"; case TypeCode.Byte: case TypeCode.SByte: case TypeCode.Int16: case TypeCode.UInt16: - case TypeCode.String: case TypeCode.Boolean: case TypeCode.Double: case TypeCode.Single: case TypeCode.Decimal: case TypeCode.Char: case TypeCode.DateTime: + return isProperty + ? $"writer.Write({val})" + : $"writer.Write(ref {val}, sizeof({BeautifulLongTypeName(mt)}))"; + case TypeCode.String: return $"writer.Write({val})"; default: if (GetValidNinoClass(mt, false)) diff --git a/src/Nino.Serialization/Deserializer.Generic.cs b/src/Nino.Serialization/Deserializer.Generic.cs index 554043f..7de3e7e 100644 --- a/src/Nino.Serialization/Deserializer.Generic.cs +++ b/src/Nino.Serialization/Deserializer.Generic.cs @@ -13,34 +13,30 @@ public static partial class Deserializer /// /// /// - /// /// - public static T[] DeserializeArray(byte[] data, CompressOption option = CompressOption.Zlib) - => DeserializeArray(new Span(data), option); + public static T[] DeserializeArray(byte[] data) + => DeserializeArray(new Span(data)); /// /// Deserialize an array NinoSerialize object /// /// /// - /// /// - public static T[] DeserializeArray(ArraySegment data, CompressOption option = CompressOption.Zlib) - => DeserializeArray(new Span(data.Array, data.Offset, data.Count), option); + public static T[] DeserializeArray(ArraySegment data) + => DeserializeArray(new Span(data.Array, data.Offset, data.Count)); /// /// Deserialize an array of NinoSerialize object /// /// /// - /// /// - public static T[] DeserializeArray(Span data, CompressOption option = CompressOption.Zlib) + public static T[] DeserializeArray(Span data) { var type = typeof(T[]); var reader = ObjectPool.Request(); - reader.Init(data, data.Length, - TypeModel.IsNonCompressibleType(type) ? CompressOption.NoCompression : option); + reader.Init(data, data.Length); /* * NO GC DESERIALIZATION ATTEMPT @@ -64,37 +60,32 @@ public static T[] DeserializeArray(Span data, CompressOption option = C /// /// /// - /// /// - public static T? DeserializeNullable(byte[] data, CompressOption option = CompressOption.Zlib) + public static T? DeserializeNullable(byte[] data) where T : struct - => DeserializeNullable(new Span(data), option); + => DeserializeNullable(new Span(data)); /// /// Deserialize a nullable of NinoSerialize struct /// /// /// - /// /// - public static T? DeserializeNullable(ArraySegment data, CompressOption option = CompressOption.Zlib) + public static T? DeserializeNullable(ArraySegment data) where T : struct - => DeserializeNullable(new Span(data.Array, data.Offset, data.Count), option); + => DeserializeNullable(new Span(data.Array, data.Offset, data.Count)); /// /// Deserialize a nullable of NinoSerialize struct /// /// /// - /// /// - public static T? DeserializeNullable(Span data, CompressOption option = CompressOption.Zlib) + public static T? DeserializeNullable(Span data) where T : struct { - var type = typeof(T?); var reader = ObjectPool.Request(); - reader.Init(data, data.Length, - TypeModel.IsNonCompressibleType(type) ? CompressOption.NoCompression : option); + reader.Init(data, data.Length); //attempt to deserialize using generic method return reader.ReadNullable(); @@ -109,40 +100,36 @@ public static T[] DeserializeArray(Span data, CompressOption option = C /// /// /// - /// /// - public static List DeserializeList(byte[] data, CompressOption option = CompressOption.Zlib) - => DeserializeList(new Span(data), option); + public static List DeserializeList(byte[] data) + => DeserializeList(new Span(data)); /// /// Deserialize a list of NinoSerialize object /// /// /// - /// /// - public static List DeserializeList(ArraySegment data, CompressOption option = CompressOption.Zlib) - => DeserializeList(new Span(data.Array, data.Offset, data.Count), option); + public static List DeserializeList(ArraySegment data) + => DeserializeList(new Span(data.Array, data.Offset, data.Count)); /// /// Deserialize a list of NinoSerialize object /// /// /// - /// /// - public static List DeserializeList(Span data, CompressOption option = CompressOption.Zlib) + public static List DeserializeList(Span data) { var type = typeof(List); var reader = ObjectPool.Request(); - reader.Init(data, data.Length, - TypeModel.IsNonCompressibleType(type) ? CompressOption.NoCompression : option); + reader.Init(data, data.Length); /* * NO GC DESERIALIZATION ATTEMPT */ //basic type - if (TryDeserializeWrapperType(typeof(List), reader, false, true, out List ret)) + if (TryDeserializeWrapperType(type, reader, false, true, out List ret)) { return ret; } @@ -160,41 +147,36 @@ public static List DeserializeList(Span data, CompressOption option /// /// /// - /// /// - public static HashSet DeserializeHashSet(byte[] data, CompressOption option = CompressOption.Zlib) - => DeserializeHashSet(new Span(data), option); + public static HashSet DeserializeHashSet(byte[] data) + => DeserializeHashSet(new Span(data)); /// /// Deserialize a HashSet of NinoSerialize object /// /// /// - /// /// - public static HashSet DeserializeHashSet(ArraySegment data, - CompressOption option = CompressOption.Zlib) - => DeserializeHashSet(new Span(data.Array, data.Offset, data.Count), option); + public static HashSet DeserializeHashSet(ArraySegment data) + => DeserializeHashSet(new Span(data.Array, data.Offset, data.Count)); /// /// Deserialize a HashSet of NinoSerialize object /// /// /// - /// /// - public static HashSet DeserializeHashSet(Span data, CompressOption option = CompressOption.Zlib) + public static HashSet DeserializeHashSet(Span data) { var type = typeof(HashSet); var reader = ObjectPool.Request(); - reader.Init(data, data.Length, - TypeModel.IsNonCompressibleType(type) ? CompressOption.NoCompression : option); + reader.Init(data, data.Length); /* * NO GC DESERIALIZATION ATTEMPT */ //basic type - if (TryDeserializeWrapperType(typeof(HashSet), reader, false, true, out HashSet ret)) + if (TryDeserializeWrapperType(type, reader, false, true, out HashSet ret)) { return ret; } @@ -212,40 +194,36 @@ public static HashSet DeserializeHashSet(Span data, CompressOption o /// /// /// - /// /// - public static Queue DeserializeQueue(byte[] data, CompressOption option = CompressOption.Zlib) - => DeserializeQueue(new Span(data), option); + public static Queue DeserializeQueue(byte[] data) + => DeserializeQueue(new Span(data)); /// /// Deserialize a Queue of NinoSerialize object /// /// /// - /// /// - public static Queue DeserializeQueue(ArraySegment data, CompressOption option = CompressOption.Zlib) - => DeserializeQueue(new Span(data.Array, data.Offset, data.Count), option); + public static Queue DeserializeQueue(ArraySegment data) + => DeserializeQueue(new Span(data.Array, data.Offset, data.Count)); /// /// Deserialize a Queue of NinoSerialize object /// /// /// - /// /// - public static Queue DeserializeQueue(Span data, CompressOption option = CompressOption.Zlib) + public static Queue DeserializeQueue(Span data) { var type = typeof(Queue); var reader = ObjectPool.Request(); - reader.Init(data, data.Length, - TypeModel.IsNonCompressibleType(type) ? CompressOption.NoCompression : option); + reader.Init(data, data.Length); /* * NO GC DESERIALIZATION ATTEMPT */ //basic type - if (TryDeserializeWrapperType(typeof(Queue), reader, false, true, out Queue ret)) + if (TryDeserializeWrapperType(type, reader, false, true, out Queue ret)) { return ret; } @@ -263,40 +241,36 @@ public static Queue DeserializeQueue(Span data, CompressOption optio /// /// /// - /// /// - public static Stack DeserializeStack(byte[] data, CompressOption option = CompressOption.Zlib) - => DeserializeStack(new Span(data), option); + public static Stack DeserializeStack(byte[] data) + => DeserializeStack(new Span(data)); /// /// Deserialize a Stack of NinoSerialize object /// /// /// - /// /// - public static Stack DeserializeStack(ArraySegment data, CompressOption option = CompressOption.Zlib) - => DeserializeStack(new Span(data.Array, data.Offset, data.Count), option); + public static Stack DeserializeStack(ArraySegment data) + => DeserializeStack(new Span(data.Array, data.Offset, data.Count)); /// /// Deserialize a Stack of NinoSerialize object /// /// /// - /// /// - public static Stack DeserializeStack(Span data, CompressOption option = CompressOption.Zlib) + public static Stack DeserializeStack(Span data) { var type = typeof(Stack); var reader = ObjectPool.Request(); - reader.Init(data, data.Length, - TypeModel.IsNonCompressibleType(type) ? CompressOption.NoCompression : option); + reader.Init(data, data.Length); /* * NO GC DESERIALIZATION ATTEMPT */ //basic type - if (TryDeserializeWrapperType(typeof(Stack), reader, false, true, out Stack ret)) + if (TryDeserializeWrapperType(type, reader, false, true, out Stack ret)) { return ret; } @@ -315,11 +289,9 @@ public static Stack DeserializeStack(Span data, CompressOption optio /// /// /// - /// /// - public static Dictionary DeserializeDictionary(byte[] data, - CompressOption option = CompressOption.Zlib) - => DeserializeDictionary(new Span(data), option); + public static Dictionary DeserializeDictionary(byte[] data) + => DeserializeDictionary(new Span(data)); /// /// Deserialize a Dictionary of NinoSerialize object @@ -327,11 +299,9 @@ public static Dictionary DeserializeDictionary(byte[ /// /// /// - /// /// - public static Dictionary DeserializeDictionary(ArraySegment data, - CompressOption option = CompressOption.Zlib) - => DeserializeDictionary(new Span(data.Array, data.Offset, data.Count), option); + public static Dictionary DeserializeDictionary(ArraySegment data) + => DeserializeDictionary(new Span(data.Array, data.Offset, data.Count)); /// /// Deserialize a Dictionary of NinoSerialize object @@ -339,21 +309,18 @@ public static Dictionary DeserializeDictionary(Array /// /// /// - /// /// - public static Dictionary DeserializeDictionary(Span data, - CompressOption option = CompressOption.Zlib) + public static Dictionary DeserializeDictionary(Span data) { var type = typeof(Dictionary); var reader = ObjectPool.Request(); - reader.Init(data, data.Length, - TypeModel.IsNonCompressibleType(type) ? CompressOption.NoCompression : option); + reader.Init(data, data.Length); /* * NO GC DESERIALIZATION ATTEMPT */ //basic type - if (TryDeserializeWrapperType(typeof(Dictionary), reader, false, true, + if (TryDeserializeWrapperType(type, reader, false, true, out Dictionary ret)) { return ret; diff --git a/src/Nino.Serialization/Deserializer.cs b/src/Nino.Serialization/Deserializer.cs index ed4d367..8273981 100644 --- a/src/Nino.Serialization/Deserializer.cs +++ b/src/Nino.Serialization/Deserializer.cs @@ -3,7 +3,6 @@ using Nino.Shared.Mgr; using System.Reflection; using System.Collections; -using System.Collections.Generic; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; @@ -12,71 +11,58 @@ namespace Nino.Serialization public static partial class Deserializer { /// - /// Custom Exporter delegate that reads bytes to object + /// Deserialize a NinoSerialize object /// - internal delegate T ExporterDelegate(Reader reader); + /// + /// + /// + public static T Deserialize(byte[] data) + => Deserialize(new Span(data), null); /// - /// Add custom Exporter of all type T objects + /// Deserialize a NinoSerialize object /// - /// /// - public static void AddCustomExporter(Func func) - { - var type = typeof(T); - if (WrapperManifest.TryGetWrapper(type, out var wrapper)) - { - ((GenericWrapper)wrapper).Exporter = func.Invoke; - return; - } - - GenericWrapper genericWrapper = new GenericWrapper - { - Exporter = func.Invoke - }; - WrapperManifest.AddWrapper(typeof(T), genericWrapper); - } + /// + /// + public static T Deserialize(ArraySegment data) + => Deserialize(new Span(data.Array, data.Offset, data.Count), null); /// /// Deserialize a NinoSerialize object /// /// /// - /// /// - public static T Deserialize(byte[] data, CompressOption option = CompressOption.Zlib) - => Deserialize(new Span(data), null, option); + public static T Deserialize(Span data) + => Deserialize(data, null); /// /// Deserialize a NinoSerialize object /// - /// + /// /// - /// /// - public static T Deserialize(ArraySegment data, CompressOption option = CompressOption.Zlib) - => Deserialize(new Span(data.Array, data.Offset, data.Count), null, option); + public static object Deserialize(Type type, byte[] data) + => Deserialize(type, null, new Span(data), null); /// /// Deserialize a NinoSerialize object /// /// /// - /// /// - public static object Deserialize(Type type, byte[] data, CompressOption option = CompressOption.Zlib) - => Deserialize(type, null, new Span(data), null, option); + public static object Deserialize(Type type, ArraySegment data) + => Deserialize(type, null, new Span(data.Array, data.Offset, data.Count), null); /// /// Deserialize a NinoSerialize object /// /// /// - /// /// - public static object Deserialize(Type type, ArraySegment data, - CompressOption option = CompressOption.Zlib) - => Deserialize(type, null, new Span(data.Array, data.Offset, data.Count), null, option); + public static object Deserialize(Type type, Span data) + => Deserialize(type, null, data, null); /// /// Deserialize a NinoSerialize object @@ -84,19 +70,17 @@ public static object Deserialize(Type type, ArraySegment data, /// /// /// - /// /// /// internal static T Deserialize(Span data, Reader reader, - CompressOption option = CompressOption.Zlib, [MarshalAs(UnmanagedType.U1)] bool returnDispose = true) + [MarshalAs(UnmanagedType.U1)] bool returnDispose = true) { Type type = typeof(T); if (reader == null) { reader = ObjectPool.Request(); - reader.Init(data, data.Length, - TypeModel.IsNonCompressibleType(type) ? CompressOption.NoCompression : option); + reader.Init(data, data.Length); } /* @@ -117,7 +101,7 @@ internal static T Deserialize(Span data, Reader reader, /* * GC DESERIALIZATION WHILE T IS STRUCT */ - var result = Deserialize(type, null, data, reader, option, returnDispose); + var result = Deserialize(type, null, data, reader, returnDispose); if (result != null) return (T)result; ObjectPool.Return(reader); return default; @@ -130,19 +114,17 @@ internal static T Deserialize(Span data, Reader reader, /// /// /// - /// /// /// /// /// internal static object Deserialize(Type type, object val, Span data, Reader reader, - CompressOption option = CompressOption.Zlib, [MarshalAs(UnmanagedType.U1)] bool returnDispose = true) + [MarshalAs(UnmanagedType.U1)] bool returnDispose = true) { if (reader == null) { reader = ObjectPool.Request(); - reader.Init(data, data.Length, - TypeModel.IsNonCompressibleType(type) ? CompressOption.NoCompression : option); + reader.Init(data, data.Length); } //array @@ -222,51 +204,18 @@ internal static object Deserialize(Type type, object val, Span data, Reade } //start Deserialize - //only include all model need this - if (model.IncludeAll) + foreach (var member in model.Members) { - //read len - var len = reader.ReadLength(); - Dictionary values = ObjectPool>.Request(); - values.Clear(); - //read elements key by key - for (int i = 0; i < len; i++) - { - var key = reader.ReadString(); - var typeFullName = reader.ReadString(); - var value = Deserialize(Type.GetType(typeFullName), ConstMgr.Null, ConstMgr.Null, reader, - option, false); - values.Add(key, value); - } - - //set elements - foreach (var member in model.Members) + //if end, skip + if (reader.EndOfReader) { - //try get same member and set it - if (values.TryGetValue(member.Name, out var ret)) - { - SetMember(member, val, ret); - } + break; } - values.Clear(); - ObjectPool>.Return(values); - } - else - { - foreach (var member in model.Members) - { - //if end, skip - if (reader.EndOfReader) - { - break; - } - - type = member is FieldInfo fi ? fi.FieldType : ((PropertyInfo)member).PropertyType; + type = member is FieldInfo fi ? fi.FieldType : ((PropertyInfo)member).PropertyType; - //read basic values - SetMember(member, val, Deserialize(type, ConstMgr.Null, Span.Empty, reader, option, false)); - } + //read basic values + SetMember(member, val, Deserialize(type, ConstMgr.Null, Span.Empty, reader, false)); } if (returnDispose) @@ -450,7 +399,7 @@ private static bool TryDeserializeEnum(Type type, Reader reader, if (TypeModel.IsEnum(type)) { var underlyingType = Enum.GetUnderlyingType(type); - var ret = reader.DecompressAndReadEnum(underlyingType); + var ret = reader.ReadEnum(underlyingType); #if ILRuntime if (type is ILRuntime.Reflection.ILRuntimeType) { diff --git a/src/Nino.Serialization/Interfaces/INinoWrapper.cs b/src/Nino.Serialization/Interfaces/INinoWrapper.cs index c2aad16..e88bc93 100644 --- a/src/Nino.Serialization/Interfaces/INinoWrapper.cs +++ b/src/Nino.Serialization/Interfaces/INinoWrapper.cs @@ -2,13 +2,15 @@ namespace Nino.Serialization { public interface INinoWrapper { - void Serialize(T val, Writer writer); + void Serialize(T val, ref Writer writer); T Deserialize(Reader reader); + int GetSize(T val); } public interface INinoWrapper { - void Serialize(object val, Writer writer); + void Serialize(object val, ref Writer writer); object Deserialize(Reader reader); + int GetSize(object val); } } \ No newline at end of file diff --git a/src/Nino.Serialization/Nino.Serialization.csproj b/src/Nino.Serialization/Nino.Serialization.csproj index eeccb96..07d4ef6 100644 --- a/src/Nino.Serialization/Nino.Serialization.csproj +++ b/src/Nino.Serialization/Nino.Serialization.csproj @@ -18,12 +18,12 @@ https://github.com/JasonXuDeveloper/Nino en-001 true - 1.1.2.1 + 1.2.0 true - Nino.Serialization v1.1.2 + Nino.Serialization v1.2 - [optimization] optimized serializer/deserializer/writer/reader -- [feat] support nullable/hashset/queue/stack -- [feat] support Polymorphism for array/list/hashset/queue/stack/dictionary +- [fix] fixed issues i.e. crashes on 32 bits machines +- [feat] support to serialize with stackalloc - [IMPORTANT] this version is not compatible with past versions git diff --git a/src/Nino.Serialization/README.md b/src/Nino.Serialization/README.md index 334c7db..77c16d3 100644 --- a/src/Nino.Serialization/README.md +++ b/src/Nino.Serialization/README.md @@ -7,8 +7,10 @@ High performance and low size binary serialization solution, especially for Unit > > **注意**,该模块的序列化数据,仅支持在C#平台使用该库进行序列化和反序列化,无法跨语言使用 > +> ```Nino.Serialization v1.2.0```与其**前面**的**所有版本**都**不兼容**,详细请查看使用教程 +> > ```Nino.Serialization v1.1.2```与其**前面**的**所有版本**都**不兼容**,详细请查看使用教程 > > ```Nino.Serialization v1.1.0```与其**前面**的**所有版本**都**不兼容**,详细请查看使用教程 -> +> > ```Nino.Serialization v1.0.21```与其**前面**的**所有版本**都**不兼容**,详细请查看使用教程 diff --git a/src/Nino.Serialization/Reader.Generic.cs b/src/Nino.Serialization/Reader.Generic.cs index a45f605..fa1a1fc 100644 --- a/src/Nino.Serialization/Reader.Generic.cs +++ b/src/Nino.Serialization/Reader.Generic.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace Nino.Serialization { @@ -15,83 +16,16 @@ public unsafe partial class Reader /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public T ReadCommonVal() => - Deserializer.Deserialize(buffer.AsSpan(position, _length - position), this, _option, - false); - - /// - /// Decompress number for int32, int64, uint32, uint64 - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public T DecompressAndReadNumber() where T : unmanaged - { - T result = default; - DecompressAndReadNumber(ref result); - return result; - } - - /// - /// Decompress number for int32, int64, uint32, uint64 - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void DecompressAndReadNumber(ref T result) where T : unmanaged - { - if (EndOfReader) - { - result = default; - return; - } - - ref var type = ref GetCompressType(); - fixed (T* ptr = &result) - { - switch (type) - { - case CompressType.Byte: - Unsafe.As(ref result) = ReadByte(); - return; - case CompressType.SByte: - Unsafe.InitBlock(ptr, 255, (uint)sizeof(T)); - Unsafe.As(ref result) = ReadSByte(); - return; - case CompressType.Int16: - Unsafe.InitBlock(ptr, 255, (uint)sizeof(T)); - Unsafe.As(ref result) = ReadInt16(); - return; - case CompressType.UInt16: - Unsafe.As(ref result) = ReadUInt16(); - return; - case CompressType.Int32: - Unsafe.InitBlock(ptr, 255, (uint)sizeof(T)); - Unsafe.As(ref result) = ReadInt32(); - return; - case CompressType.UInt32: - Unsafe.As(ref result) = ReadUInt32(); - return; - case CompressType.Int64: - Unsafe.InitBlock(ptr, 255, (uint)sizeof(T)); - Unsafe.As(ref result) = ReadInt64(); - return; - case CompressType.UInt64: - Unsafe.As(ref result) = ReadUInt64(); - return; - default: - throw new InvalidOperationException("invalid compress type"); - } - } - } + Deserializer.Deserialize(buffer.AsSpan(position, _length - position), this, false); /// /// Compress and write enum /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public T DecompressAndReadEnum() + public T ReadEnum() { T val = default; - DecompressAndReadEnum(ref val); + ReadEnum(ref val); return val; } @@ -100,7 +34,7 @@ public T DecompressAndReadEnum() /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void DecompressAndReadEnum(ref T val) + public void ReadEnum(ref T val) { if (EndOfReader) return; @@ -118,18 +52,17 @@ public void DecompressAndReadEnum(ref T val) case TypeCode.UInt16: Unsafe.As(ref val) = ReadUInt16(); return; - //need to consider compress case TypeCode.Int32: - Unsafe.As(ref val) = DecompressAndReadNumber(); + Unsafe.As(ref val) = ReadInt32(); return; case TypeCode.UInt32: - Unsafe.As(ref val) = DecompressAndReadNumber(); + Unsafe.As(ref val) = ReadUInt32(); return; case TypeCode.Int64: - Unsafe.As(ref val) = DecompressAndReadNumber(); + Unsafe.As(ref val) = ReadInt64(); return; case TypeCode.UInt64: - Unsafe.As(ref val) = DecompressAndReadNumber(); + Unsafe.As(ref val) = ReadUInt64(); return; } } @@ -139,16 +72,16 @@ public void DecompressAndReadEnum(ref T val) /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - private T Read(int len) where T : unmanaged + public T Read(int len) where T : unmanaged { if (EndOfReader) { return default; } - var ptr = buffer.Data + position; + var ret = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T))); position += len; - return Unsafe.Read(ptr); + return ret; } /// @@ -166,7 +99,7 @@ public void Read(ref T val, int len) where T : unmanaged return; } - val = Unsafe.Read(buffer.Data + position); + val = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T))); position += len; } @@ -205,8 +138,7 @@ public T[] ReadArray() int i = 0; while (i < len) { - arr[i++] = (T)ReadCommonVal( - TypeModel.AllTypes.TryGetValue(ReadInt32(), out var type) ? type : typeof(T)); + arr[i++] = ReadCommonVal(); } return arr; @@ -228,8 +160,7 @@ public List ReadList() //read item while (len-- > 0) { - lst.Add((T)ReadCommonVal( - TypeModel.AllTypes.TryGetValue(ReadInt32(), out var type) ? type : typeof(T))); + lst.Add(ReadCommonVal()); } return lst; @@ -251,8 +182,7 @@ public HashSet ReadHashSet() //read item while (len-- > 0) { - lst.Add((T)ReadCommonVal( - TypeModel.AllTypes.TryGetValue(ReadInt32(), out var type) ? type : typeof(T))); + lst.Add(ReadCommonVal()); } return lst; @@ -274,8 +204,7 @@ public Queue ReadQueue() //read item while (len-- > 0) { - lst.Enqueue((T)ReadCommonVal( - TypeModel.AllTypes.TryGetValue(ReadInt32(), out var type) ? type : typeof(T))); + lst.Enqueue(ReadCommonVal()); } return lst; @@ -317,10 +246,8 @@ public Dictionary ReadDictionary() //read item while (len-- > 0) { - var key = (TKey)ReadCommonVal( - TypeModel.AllTypes.TryGetValue(ReadInt32(), out var type) ? type : typeof(TKey)); - var val = (TValue)ReadCommonVal( - TypeModel.AllTypes.TryGetValue(ReadInt32(), out type) ? type : typeof(TValue)); + var key = ReadCommonVal(); + var val = ReadCommonVal(); dic.Add(key, val); } diff --git a/src/Nino.Serialization/Reader.cs b/src/Nino.Serialization/Reader.cs index 41ea44e..5109e8b 100644 --- a/src/Nino.Serialization/Reader.cs +++ b/src/Nino.Serialization/Reader.cs @@ -3,7 +3,6 @@ using Nino.Shared.Mgr; using System.Collections; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; namespace Nino.Serialization { @@ -32,11 +31,6 @@ public unsafe partial class Reader /// private int _length; - /// - /// compress option - /// - private CompressOption _option; - /// /// End of Reader /// @@ -54,10 +48,9 @@ public Reader() /// /// /// - /// - public Reader(byte[] data, int outputLength, CompressOption option = CompressOption.Zlib) + public Reader(byte[] data, int outputLength) { - Init(data, outputLength, option); + Init(data, outputLength); } /// @@ -65,9 +58,8 @@ public Reader(byte[] data, int outputLength, CompressOption option = CompressOpt /// /// /// - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void Init(IntPtr data, int outputLength, CompressOption option) + private void Init(IntPtr data, int outputLength) { if (buffer == null) { @@ -85,11 +77,6 @@ private void Init(IntPtr data, int outputLength, CompressOption option) buffer.CopyFrom((byte*)data, 0, 0, outputLength); position = 0; _length = outputLength; - _option = option; - if (_option == CompressOption.Zlib) - { - Marshal.FreeHGlobal(data); - } } /// @@ -97,24 +84,12 @@ private void Init(IntPtr data, int outputLength, CompressOption option) /// /// /// - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Init(Span data, int outputLength, CompressOption compressOption) + public void Init(Span data, int outputLength) { - switch (compressOption) + fixed (byte* ptr = &data.GetPinnableReference()) { - case CompressOption.NoCompression: - fixed (byte* ptr = &data.GetPinnableReference()) - { - Init((IntPtr)ptr, outputLength, compressOption); - } - - break; - case CompressOption.Lz4: - throw new NotSupportedException("not support lz4 yet"); - case CompressOption.Zlib: - Init(CompressMgr.Decompress(data.ToArray(), out var length), length, compressOption); - break; + Init((IntPtr)ptr, outputLength); } } @@ -123,24 +98,12 @@ public void Init(Span data, int outputLength, CompressOption compressOptio /// /// /// - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Init(byte[] data, int outputLength, CompressOption compressOption) + public void Init(byte[] data, int outputLength) { - switch (compressOption) + fixed (byte* ptr = data) { - case CompressOption.NoCompression: - fixed (byte* ptr = data) - { - Init((IntPtr)ptr, outputLength, compressOption); - } - - break; - case CompressOption.Lz4: - throw new NotSupportedException("not support lz4 yet"); - case CompressOption.Zlib: - Init(CompressMgr.Decompress(data, out var length), length, compressOption); - break; + Init((IntPtr)ptr, outputLength); } } @@ -149,12 +112,7 @@ public void Init(byte[] data, int outputLength, CompressOption compressOption) /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int ReadLength() - { - if (EndOfReader) return default; - - return DecompressAndReadNumber(); - } + public int ReadLength() => ReadInt32(); /// /// Read primitive value from binary writer, DO NOT USE THIS FOR CUSTOM EXPORTER @@ -163,81 +121,7 @@ public int ReadLength() /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public object ReadCommonVal(Type type) => - Deserializer.Deserialize(type, ConstMgr.Null, ConstMgr.Null, this, _option, false); - - /// - /// Decompress number for int32, int64, uint32, uint64 - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Obsolete("use generic method instead")] - public ulong DecompressAndReadNumber() - { - if (EndOfReader) return default; - - ref var type = ref GetCompressType(); - switch (type) - { - case CompressType.Byte: - return ReadByte(); - case CompressType.SByte: - return (ulong)ReadSByte(); - case CompressType.Int16: - return (ulong)ReadInt16(); - case CompressType.UInt16: - return ReadUInt16(); - case CompressType.Int32: - return (ulong)ReadInt32(); - case CompressType.UInt32: - return ReadUInt32(); - case CompressType.Int64: - return (ulong)ReadInt64(); - case CompressType.UInt64: - return ReadUInt64(); - default: - throw new InvalidOperationException("invalid compress type"); - } - } - - /// - /// Compress and write enum - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ulong DecompressAndReadEnum(Type enumType) - { - if (EndOfReader) return default; - - switch (TypeModel.GetTypeCode(enumType)) - { - case TypeCode.Byte: - return ReadByte(); - case TypeCode.SByte: - return (ulong)ReadSByte(); - case TypeCode.Int16: - return (ulong)ReadInt16(); - case TypeCode.UInt16: - return ReadUInt16(); - //need to consider compress - case TypeCode.Int32: - return (ulong)DecompressAndReadNumber(); - case TypeCode.UInt32: - return DecompressAndReadNumber(); - case TypeCode.Int64: - return (ulong)DecompressAndReadNumber(); - case TypeCode.UInt64: - return DecompressAndReadNumber(); - } - - return 0; - } - - /// - /// Get CompressType - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private ref CompressType GetCompressType() => ref *(CompressType*)(&buffer.Data[position++]); + Deserializer.Deserialize(type, ConstMgr.Null, ConstMgr.Null, this, false); /// /// Read a byte @@ -302,7 +186,7 @@ public DateTime ReadDateTime() { if (EndOfReader) return default; - return DateTime.FromOADate(ReadDouble()); + return Read(ConstMgr.SizeOfLong); } /// @@ -397,7 +281,7 @@ public string ReadString() if (EndOfReader) return default; if (!ReadBool()) return null; - int len = DecompressAndReadNumber(); + int len = ReadInt32(); //empty string -> no gc if (len == 0) { @@ -410,6 +294,37 @@ public string ReadString() return new string(chars, 0, len / ConstMgr.SizeOfUShort); } + /// + /// Compress and write enum + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ulong ReadEnum(Type enumType) + { + if (EndOfReader) return default; + + switch (TypeModel.GetTypeCode(enumType)) + { + case TypeCode.Byte: + return ReadByte(); + case TypeCode.SByte: + return (ulong)ReadSByte(); + case TypeCode.Int16: + return (ulong)ReadInt16(); + case TypeCode.UInt16: + return ReadUInt16(); + case TypeCode.Int32: + return (ulong)ReadInt32(); + case TypeCode.UInt32: + return ReadUInt32(); + case TypeCode.Int64: + return (ulong)ReadInt64(); + case TypeCode.UInt64: + return ReadUInt64(); + } + + return 0; + } + /// /// Read Array /// @@ -444,9 +359,7 @@ public Array ReadArray(Type type) int i = 0; while (i < len) { - var obj = Deserializer.Deserialize( - TypeModel.AllTypes.TryGetValue(ReadInt32(), out type) ? type : elemType, ConstMgr.Null, - ConstMgr.Null, this, _option, false); + var obj = ReadCommonVal(elemType); #if ILRuntime arr.SetValue(ILRuntime.CLR.Utils.Extensions.CheckCLRTypes(elemType, obj), i++); continue; @@ -499,9 +412,7 @@ public IList ReadList(Type type) int i = 0; while (i++ < len) { - var obj = Deserializer.Deserialize( - TypeModel.AllTypes.TryGetValue(ReadInt32(), out type) ? type : elemType, ConstMgr.Null, - ConstMgr.Null, this, _option, false); + var obj = ReadCommonVal(elemType); #if ILRuntime arr?.Add(ILRuntime.CLR.Utils.Extensions.CheckCLRTypes(elemType, obj)); continue; @@ -561,13 +472,9 @@ public IDictionary ReadDictionary(Type type) while (i++ < len) { //read key - var key = Deserializer.Deserialize( - TypeModel.AllTypes.TryGetValue(ReadInt32(), out type) ? type : keyType, ConstMgr.Null, - ConstMgr.Null, this, _option, false); + var key = ReadCommonVal(keyType); //read value - var val = Deserializer.Deserialize( - TypeModel.AllTypes.TryGetValue(ReadInt32(), out type) ? type : valueType, ConstMgr.Null, - ConstMgr.Null, this, _option, false); + var val = ReadCommonVal(valueType); //add #if ILRuntime diff --git a/src/Nino.Serialization/Serializer.Generic.cs b/src/Nino.Serialization/Serializer.Generic.cs index 2594e2c..7c60631 100644 --- a/src/Nino.Serialization/Serializer.Generic.cs +++ b/src/Nino.Serialization/Serializer.Generic.cs @@ -1,4 +1,5 @@ -using Nino.Shared.IO; +using System; +using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; @@ -6,30 +7,181 @@ namespace Nino.Serialization { public static partial class Serializer { + /// + /// Attempt to serialize hard-coded types + code gen types + custom delegate types + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TrySerializeWrapperType(Type type, ref T value, ref Writer writer) + { + //basic type + if (!WrapperManifest.TryGetWrapper(type, out var wrapper)) + { + return false; + } + + if (wrapper is NinoWrapperBase @base) + { + @base.Serialize(value, ref writer); + } + else + { + wrapper.Serialize(value, ref writer); + } + + return true; + } + + /// + /// Attempt to serialize enum + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TrySerializeEnumType(Type type, ref T value, ref Writer writer) + { + //enum + if (!TypeModel.IsEnum(type)) + { + return false; + } + + writer.WriteEnum(value); + return true; + } + + /// + /// Attempt to serialize code gen type (first time only) + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TrySerializeCodeGenType(Type type, ref T value, ref Writer writer) + { + //code generated type + if (!TypeModel.TryGetWrapper(type, out var wrapper)) + { + return false; + } + + //add wrapper + WrapperManifest.AddWrapper(type, wrapper); + + //start serialize + if (wrapper is NinoWrapperBase @base) + { + @base.Serialize(value, ref writer); + } + else + { + wrapper.Serialize(value, ref writer); + } + + return true; + } + + /// + /// Attempt to serialize array + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TrySerializeArray(ref T value, ref Writer writer) + { + //array + if (!(value is Array arr)) + { + return false; + } + + writer.Write(arr); + return true; + } + + /// + /// Attempt to serialize list (boxed) + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TrySerializeList(ref T value, ref Writer writer) + { + if (!(value is IList lst)) + { + return false; + } + + writer.Write(lst); + return true; + } + + /// + /// Attempt to serialize dict + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TrySerializeDict(ref T value, ref Writer writer) + { + if (!(value is IDictionary dict)) + { + return false; + } + + writer.Write(dict); + return true; + } + /// /// Serialize an array of NinoSerialize object /// /// /// - /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte[] Serialize(T[] val, CompressOption option = CompressOption.Zlib) + public static byte[] Serialize(T[] val) { - Writer writer = ObjectPool.Request(); - writer.Init(option); + int length = GetSize(in val); + if (length == 0) + { + return Array.Empty(); + } + + byte[] ret = new byte[length]; + if (val == null) + { + return ret; + } + + Writer writer = new Writer(ret.AsSpan(), 0); /* * HARD-CODED SERIALIZATION */ - if (TrySerializeWrapperType(typeof(T[]), val, writer, false, true, out var ret)) + if (TrySerializeWrapperType(typeof(T[]), ref val, ref writer)) { return ret; } //attempt to serialize using generic method writer.Write(val); - return Return(true, writer); + return ret; } /// @@ -37,17 +189,27 @@ public static byte[] Serialize(T[] val, CompressOption option = CompressOptio /// /// /// - /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte[] Serialize(T? val, CompressOption option = CompressOption.Zlib) where T : struct + public static byte[] Serialize(T? val) where T : struct { - Writer writer = ObjectPool.Request(); - writer.Init(option); + int length = GetSize(in val); + if (length == 0) + { + return Array.Empty(); + } + + byte[] ret = new byte[length]; + if (val == null) + { + return ret; + } + + Writer writer = new Writer(ret.AsSpan(), 0); //attempt to serialize using generic method writer.Write(val); - return Return(true, writer); + return ret; } /// @@ -55,25 +217,35 @@ public static byte[] Serialize(T? val, CompressOption option = CompressOption /// /// /// - /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte[] Serialize(List val, CompressOption option = CompressOption.Zlib) + public static byte[] Serialize(List val) { - Writer writer = ObjectPool.Request(); - writer.Init(option); + int length = GetSize(in val); + if (length == 0) + { + return Array.Empty(); + } + + byte[] ret = new byte[length]; + if (val == null) + { + return ret; + } + + Writer writer = new Writer(ret.AsSpan(), 0); /* * HARD-CODED SERIALIZATION */ - if (TrySerializeWrapperType(typeof(List), val, writer, false, true, out var ret)) + if (TrySerializeWrapperType(typeof(List), ref val, ref writer)) { return ret; } //attempt to serialize using generic method writer.Write(val); - return Return(true, writer); + return ret; } /// @@ -81,25 +253,35 @@ public static byte[] Serialize(List val, CompressOption option = CompressO /// /// /// - /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte[] Serialize(HashSet val, CompressOption option = CompressOption.Zlib) + public static byte[] Serialize(HashSet val) { - Writer writer = ObjectPool.Request(); - writer.Init(option); + int length = GetSize(in val); + if (length == 0) + { + return Array.Empty(); + } + + byte[] ret = new byte[length]; + if (val == null) + { + return ret; + } + + Writer writer = new Writer(ret.AsSpan(), 0); /* * HARD-CODED SERIALIZATION */ - if (TrySerializeWrapperType(typeof(HashSet), val, writer, false, true, out var ret)) + if (TrySerializeWrapperType(typeof(HashSet), ref val, ref writer)) { return ret; } //attempt to serialize using generic method writer.Write(val); - return Return(true, writer); + return ret; } /// @@ -107,25 +289,35 @@ public static byte[] Serialize(HashSet val, CompressOption option = Compre /// /// /// - /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte[] Serialize(Queue val, CompressOption option = CompressOption.Zlib) + public static byte[] Serialize(Queue val) { - Writer writer = ObjectPool.Request(); - writer.Init(option); + int length = GetSize(in val); + if (length == 0) + { + return Array.Empty(); + } + + byte[] ret = new byte[length]; + if (val == null) + { + return ret; + } + + Writer writer = new Writer(ret.AsSpan(), 0); /* * HARD-CODED SERIALIZATION */ - if (TrySerializeWrapperType(typeof(Queue), val, writer, false, true, out var ret)) + if (TrySerializeWrapperType(typeof(Queue), ref val, ref writer)) { return ret; } //attempt to serialize using generic method writer.Write(val); - return Return(true, writer); + return ret; } /// @@ -133,25 +325,35 @@ public static byte[] Serialize(Queue val, CompressOption option = Compress /// /// /// - /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte[] Serialize(Stack val, CompressOption option = CompressOption.Zlib) + public static byte[] Serialize(Stack val) { - Writer writer = ObjectPool.Request(); - writer.Init(option); + int length = GetSize(in val); + if (length == 0) + { + return Array.Empty(); + } + + byte[] ret = new byte[length]; + if (val == null) + { + return ret; + } + + Writer writer = new Writer(ret.AsSpan(), 0); /* * HARD-CODED SERIALIZATION */ - if (TrySerializeWrapperType(typeof(Stack), val, writer, false, true, out var ret)) + if (TrySerializeWrapperType(typeof(Stack), ref val, ref writer)) { return ret; } //attempt to serialize using generic method writer.Write(val); - return Return(true, writer); + return ret; } /// @@ -160,26 +362,35 @@ public static byte[] Serialize(Stack val, CompressOption option = Compress /// /// /// - /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte[] Serialize(Dictionary val, - CompressOption option = CompressOption.Zlib) + public static byte[] Serialize(Dictionary val) { - Writer writer = ObjectPool.Request(); - writer.Init(option); + int length = GetSize(in val); + if (length == 0) + { + return Array.Empty(); + } + + byte[] ret = new byte[length]; + if (val == null) + { + return ret; + } + + Writer writer = new Writer(ret.AsSpan(), 0); /* * HARD-CODED SERIALIZATION */ - if (TrySerializeWrapperType(typeof(Dictionary), val, writer, false, true, out var ret)) + if (TrySerializeWrapperType(typeof(Dictionary), ref val, ref writer)) { return ret; } //attempt to serialize using generic method writer.Write(val); - return Return(true, writer); + return ret; } } } \ No newline at end of file diff --git a/src/Nino.Serialization/Serializer.Helper.cs b/src/Nino.Serialization/Serializer.Helper.cs new file mode 100644 index 0000000..0205c69 --- /dev/null +++ b/src/Nino.Serialization/Serializer.Helper.cs @@ -0,0 +1,346 @@ +// Serializer.Helper.cs +// +// Author: +// JasonXuDeveloper(傑) +// +// Copyright (c) 2023 Nino + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using Nino.Shared.Mgr; + +namespace Nino.Serialization +{ + public static partial class Serializer + { + private static readonly Dictionary FixedSizeCache = new Dictionary() + { + { typeof(bool), 1 }, + { typeof(byte), 1 }, + { typeof(sbyte), 1 }, + { typeof(char), 2 }, + { typeof(short), 2 }, + { typeof(ushort), 2 }, + { typeof(int), 4 }, + { typeof(uint), 4 }, + { typeof(long), 8 }, + { typeof(ulong), 8 }, + { typeof(float), 4 }, + { typeof(double), 8 }, + { typeof(decimal), 16 }, + { typeof(DateTime), 8 }, + { typeof(TimeSpan), 8 }, + { typeof(Guid), 16 }, + { typeof(IntPtr), 8 }, + { typeof(UIntPtr), 8 }, + }; + + public static int GetFixedSize() where T : unmanaged + { + if (FixedSizeCache.TryGetValue(typeof(T), out var size)) + { + return size; + } + + return -1; + } + + public static void SetFixedSize(int size) where T : unmanaged + { + FixedSizeCache[typeof(T)] = size; + } + + public static int GetSize(in T val = default, Dictionary members = null) + { + var type = typeof(T); + int size = 0; + if (TypeModel.IsEnum(type)) type = type.GetEnumUnderlyingType(); + + //nullable + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) + { + type = type.GetGenericArguments()[0]; + size += 1; + } + + if (val == null) return 1; + + if (FixedSizeCache.TryGetValue(type, out var size2)) + { + return size + size2; + } + + if (!WrapperManifest.TryGetWrapper(type, out var wrapper)) + { + //code generated type + if (TypeModel.TryGetWrapper(type, out wrapper)) + { + //add wrapper + WrapperManifest.AddWrapper(type, wrapper); + } + } + + if (wrapper != null) + { + if (wrapper is NinoWrapperBase @base) + { + return size + @base.GetSize(val); + } + + return size + wrapper.GetSize(val); + } + + return GetSize(type, val, members); + } + + public static int GetSize(Type type, object obj, Dictionary members = null) + { + if (TypeModel.IsEnum(type)) type = type.GetEnumUnderlyingType(); + + int size = 0; + bool isGeneric = type.IsGenericType; + Type genericTypeDef = null; + Type[] genericArgs = null; + if (isGeneric) + { + genericTypeDef = type.GetGenericTypeDefinition(); + genericArgs = type.GetGenericArguments(); + } + + //nullable + if (genericTypeDef != null && genericTypeDef == typeof(Nullable<>)) + { + type = genericArgs[0]; + size += 1; + } + + if (obj == null) return 1; + + if (FixedSizeCache.TryGetValue(type, out var size2)) + { + return size + size2; + } + + if (!WrapperManifest.TryGetWrapper(type, out var wrapper)) + { + //code generated type + if (TypeModel.TryGetWrapper(type, out wrapper)) + { + //add wrapper + WrapperManifest.AddWrapper(type, wrapper); + } + } + + if (wrapper != null) + { + return size + wrapper.GetSize(obj); + } + + size = 1; //null indicator + + if (type == ConstMgr.ObjectType) + { + type = obj.GetType(); + } + + if (type.IsArray) + { + var elementType = type.GetElementType(); + var array = obj as Array; + if (array == null) + { + return size; + } + + size += 4; //length + if (array.Length == 0) return size; + + if (elementType != null && FixedSizeCache.TryGetValue(elementType, out var eleSize)) + { + size += eleSize * array.Length; + return size; + } + + foreach (var item in array) + { + size += GetSize(elementType, item); + } + + return size; + } + + if (isGeneric && genericTypeDef != null) + { + switch (genericTypeDef) + { + case var _ when genericTypeDef.GetInterface(nameof(IList)) != null: + var lstElemType = genericArgs[0]; + var lst = obj as ICollection; + if (lst == null) + { + return size; + } + + size += 4; //length + if (lst.Count == 0) return size; + + if (FixedSizeCache.TryGetValue(lstElemType, out var lstEleSize)) + { + size += lstEleSize * lst.Count; + return size; + } + + foreach (var item in lst) + { + size += GetSize(lstElemType, item); + } + + return size; + case var _ when genericTypeDef.GetInterface(nameof(IDictionary)) != null: + var keyType = genericArgs[0]; + var valueType = genericArgs[1]; + var dict = obj as IDictionary; + if (dict == null) + { + return size; + } + + size += 4; //length + if (dict.Count == 0) return size; + + bool hasKeySize = FixedSizeCache.TryGetValue(keyType, out var keySize); + bool hasValueSize = FixedSizeCache.TryGetValue(valueType, out var valueSize); + + if (hasKeySize && hasValueSize) + { + size += (keySize + valueSize) * dict.Count; + return size; + } + + if (hasKeySize) + { + size += keySize * dict.Count; + foreach (var item in dict.Values) + { + size += GetSize(valueType, item); + } + + return size; + } + + if (hasValueSize) + { + size += valueSize * dict.Count; + foreach (var item in dict.Keys) + { + size += GetSize(keyType, item); + } + + return size; + } + + foreach (DictionaryEntry item in dict) + { + size += GetSize(keyType, item.Key); + size += GetSize(valueType, item.Value); + } + + return size; + case var _ when genericTypeDef.GetInterface(nameof(ICollection)) != null: + var elementType2 = genericArgs[0]; + var collection = obj as ICollection; + if (collection == null) + { + return size; + } + + size += 4; //length + if (collection.Count == 0) return size; + + if (FixedSizeCache.TryGetValue(elementType2, out var eleSize)) + { + size += eleSize * collection.Count; + return size; + } + + foreach (var item in collection) + { + size += GetSize(elementType2, item); + } + + return size; + case var _ when genericTypeDef.GetInterface(nameof(IEnumerable)) != null: + var elementType = genericArgs[0]; + var enumerable = obj as IEnumerable; + if (enumerable == null) + { + return size; + } + + size += 4; //length + + var enumerator = enumerable.GetEnumerator(); + if (!enumerator.MoveNext()) return size; + do + { + size += GetSize(elementType, enumerator.Current); + } while (enumerator.MoveNext()); + + return size; + } + } + + //Nino serializable type + TypeModel.TryGetModel(type, out var model); + + //invalid model + if (model != null && !model.Valid) + { + throw new InvalidOperationException($"Invalid model for type {type}"); + } + + //generate model + if (model == null) + { + model = TypeModel.CreateModel(type); + } + + var isFixed = true; + foreach (var member in model.Members) + { + Type memberType; + object memberObj; + switch (member) + { + case FieldInfo fi: + memberType = fi.FieldType; + memberObj = fi.GetValue(obj); + break; + case PropertyInfo pi: + memberType = pi.PropertyType; + memberObj = pi.GetValue(obj); + break; + default: + throw new Exception("Invalid member type"); + } + + if (members != null) + { + members[member] = memberObj; + } + + size += GetSize(memberType, memberObj); + if (!FixedSizeCache.ContainsKey(memberType)) + { + isFixed = false; + } + } + + if (isFixed) + FixedSizeCache[type] = size; + return size; + } + } +} \ No newline at end of file diff --git a/src/Nino.Serialization/Serializer.cs b/src/Nino.Serialization/Serializer.cs index e6e93cc..8b6b4a2 100644 --- a/src/Nino.Serialization/Serializer.cs +++ b/src/Nino.Serialization/Serializer.cs @@ -1,106 +1,103 @@ using System; -using Nino.Shared.IO; -using Nino.Shared.Mgr; +using System.Collections.Generic; using System.Reflection; -using System.Collections; -using System.Runtime.InteropServices; using System.Runtime.CompilerServices; +using Nino.Shared.IO; namespace Nino.Serialization { public static partial class Serializer { /// - /// Custom importer delegate that writes object to writer - /// - internal delegate void ImporterDelegate(T val, Writer writer); - - /// - /// Add custom importer of all type T objects + /// Serialize a NinoSerialize object /// - /// /// - public static void AddCustomImporter(Action action) + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] Serialize(in T val) { - var type = typeof(T); - if (WrapperManifest.TryGetWrapper(type, out var wrapper)) + Dictionary fields = ObjectPool>.Request(); + fields.Clear(); + int length = GetSize(in val, fields); + if (length == 0) { - ((GenericWrapper)wrapper).Importer = action.Invoke; - return; + return Array.Empty(); } - GenericWrapper genericWrapper = new GenericWrapper - { - Importer = action.Invoke - }; - WrapperManifest.AddWrapper(type, genericWrapper); + byte[] ret = new byte[length]; + Serialize(ret.AsSpan(), in val, fields); + ObjectPool>.Return(fields); + return ret; } /// /// Serialize a NinoSerialize object /// /// + /// /// - /// - /// + /// + /// actual written size [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte[] Serialize(T val, CompressOption option = CompressOption.Zlib) + public static int Serialize(Span buffer, in T val, Dictionary fields = null) { - Writer writer = ObjectPool.Request(); - writer.Init(option); - return Serialize(typeof(T), val, writer, option); + if (val == null) + { + buffer[0] = 0; + return 1; + } + + return Serialize(typeof(T), val, fields, buffer, 0); } /// /// Serialize a NinoSerialize object /// /// - /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte[] Serialize(object val, CompressOption option = CompressOption.Zlib) + public static byte[] Serialize(object val) { - Writer writer = ObjectPool.Request(); - writer.Init(option); - return Serialize(val is null ? typeof(void) : val.GetType(), val, writer, option); + Dictionary fields = ObjectPool>.Request(); + fields.Clear(); + int length = GetSize(in val, fields); + if (length == 0) + { + return Array.Empty(); + } + + byte[] ret = new byte[length]; + if (val == null) + { + ObjectPool>.Return(fields); + return ret; + } + Serialize(val.GetType(), val, fields, ret.AsSpan(), 0); + ObjectPool>.Return(fields); + return ret; } /// /// Serialize a NinoSerialize object /// - /// - /// - /// - /// - /// + /// + /// /// - /// - /// - // ReSharper disable CognitiveComplexity - internal static byte[] Serialize(Type type, T value, Writer writer, - CompressOption option = CompressOption.Zlib, [MarshalAs(UnmanagedType.U1)] bool returnValue = true) - // ReSharper restore CognitiveComplexity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int Serialize(Span buffer, object val) { - bool boxed = false; - Type tType = typeof(T); - if (type != tType || tType == ConstMgr.ObjectType) + if (val == null) { - if (type != ConstMgr.ObjectType) - { - boxed = true; - } - else - { - if (value == null) - { - throw new InvalidOperationException("Failed to retrieve unbox type"); - } - - type = value.GetType(); - boxed = true; - } + buffer[0] = 0; + return 1; } + return Serialize(val.GetType(), val, null, buffer, 0); + } + + internal static int Serialize(Type type, T value, Dictionary fields ,Span buffer, int pos) + { //ILRuntime #if ILRuntime if(value is ILRuntime.Runtime.Intepreter.ILTypeInstance ins) @@ -111,61 +108,57 @@ internal static byte[] Serialize(Type type, T value, Writer writer, type = type.ResolveRealType(); #endif - if (writer == null) - { - writer = ObjectPool.Request(); - } + Writer writer = new Writer(buffer, pos); - if (returnValue) + //null check + if (value == null) { - writer.Init(TypeModel.IsNonCompressibleType(type) ? CompressOption.NoCompression : option); + writer.Write(false); // false -> is null + return writer.Position; } /* * HARD-CODED SERIALIZATION */ - if (TrySerializeWrapperType(type, value, writer, boxed, returnValue, out var ret)) + if (TrySerializeWrapperType(type, ref value, ref writer)) { - return ret; + return writer.Position; } - if (TrySerializeEnumType(type, value, writer, returnValue, out ret)) + if (TrySerializeEnumType(type, ref value, ref writer)) { - return ret; + return writer.Position; } - if (TrySerializeCodeGenType(type, value, writer, boxed, returnValue, out ret)) + if (TrySerializeCodeGenType(type, ref value, ref writer)) { - return ret; + return writer.Position; } - if (TrySerializeArray(value, writer, returnValue, out ret)) + if (TrySerializeArray(ref value, ref writer)) { - return ret; + return writer.Position; } //generic if (type.IsGenericType) { - if (TrySerializeList(value, writer, returnValue, out ret)) + if (TrySerializeList(ref value, ref writer)) { - return ret; + return writer.Position; } - if (TrySerializeDict(value, writer, returnValue, out ret)) + if (TrySerializeDict(ref value, ref writer)) { - return ret; + return writer.Position; } } /* * CUSTOM STRUCT/CLASS SERIALIZATION */ - if (WriteNullCheck(value, writer, returnValue, out ret)) - { - return ret; - } + writer.Write(true); //true -> not null //Get Attribute that indicates a class/struct to be serialized TypeModel.TryGetModel(type, out var model); @@ -173,8 +166,7 @@ internal static byte[] Serialize(Type type, T value, Writer writer, //invalid model if (model != null && !model.Valid) { - ObjectPool.Return(writer); - return ConstMgr.Null; + return 0; } //generate model @@ -183,13 +175,6 @@ internal static byte[] Serialize(Type type, T value, Writer writer, model = TypeModel.CreateModel(type); } - //only include all model need this - if (model.IncludeAll) - { - //write len - writer.CompressAndWrite(model.Members.Count); - } - //serialize all recorded members foreach (var member in model.Members) { @@ -198,247 +183,26 @@ internal static byte[] Serialize(Type type, T value, Writer writer, { case FieldInfo fo: type = fo.FieldType; - obj = fo.GetValue(value); + if(fields == null || !fields.TryGetValue(fo, out obj)) + { + obj = fo.GetValue(value); + } break; case PropertyInfo po: type = po.PropertyType; - obj = po.GetValue(value); + if (fields == null || !fields.TryGetValue(po, out obj)) + { + obj = po.GetValue(value); + } break; default: - return null; + return writer.Position; } - //only include all model need this - if (model.IncludeAll) - { - writer.Write(member.Name); - writer.Write(type.AssemblyQualifiedName); - } - - Serialize(type, obj, writer, option, false); - } - - return Return(returnValue, writer); - } - - /// - /// Attempt to serialize hard-coded types + code gen types + custom delegate types - /// - /// - /// - /// - /// - /// - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TrySerializeWrapperType(Type type, T value, Writer writer, - [MarshalAs(UnmanagedType.U1)] bool boxed, [MarshalAs(UnmanagedType.U1)] bool returnValue, - out byte[] ret) - { - //basic type - if (!WrapperManifest.TryGetWrapper(type, out var wrapper)) - { - ret = ConstMgr.Null; - return false; - } - - if (boxed) - { - wrapper.Serialize(value, writer); - } - else - { - ((NinoWrapperBase)wrapper).Serialize(value, writer); - } - - ret = Return(returnValue, writer); - return true; - } - - /// - /// Attempt to serialize enum - /// - /// - /// - /// - /// - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TrySerializeEnumType(Type type, T value, Writer writer, - [MarshalAs(UnmanagedType.U1)] bool returnValue, out byte[] ret) - { - //enum - if (!TypeModel.IsEnum(type)) - { - ret = ConstMgr.Null; - return false; - } - - writer.CompressAndWriteEnum(value); - ret = Return(returnValue, writer); - return true; - } - - /// - /// Attempt to serialize code gen type (first time only) - /// - /// - /// - /// - /// - /// - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TrySerializeCodeGenType(Type type, T value, Writer writer, - [MarshalAs(UnmanagedType.U1)] bool boxed, [MarshalAs(UnmanagedType.U1)] bool returnValue, - out byte[] ret) - { - //code generated type - if (!TypeModel.TryGetWrapper(type, out var wrapper)) - { - ret = ConstMgr.Null; - return false; - } - - //add wrapper - WrapperManifest.AddWrapper(type, wrapper); - - //start serialize - if (boxed) - { - wrapper.Serialize(value, writer); - } - else - { - ((NinoWrapperBase)wrapper).Serialize(value, writer); - } - - ret = Return(returnValue, writer); - return true; - } - - /// - /// Attempt to serialize array - /// - /// - /// - /// - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TrySerializeArray(T value, Writer writer, - [MarshalAs(UnmanagedType.U1)] bool returnValue, out byte[] ret) - { - //array - if (!(value is Array arr)) - { - ret = ConstMgr.Null; - return false; - } - - writer.Write(arr); - ret = Return(returnValue, writer); - return true; - } - - /// - /// Attempt to serialize list (boxed) - /// - /// - /// - /// - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TrySerializeList(T value, Writer writer, - [MarshalAs(UnmanagedType.U1)] bool returnValue, out byte[] ret) - { - if (!(value is IList lst)) - { - ret = ConstMgr.Null; - return false; - } - - writer.Write(lst); - ret = Return(returnValue, writer); - return true; - } - - /// - /// Attempt to serialize dict - /// - /// - /// - /// - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TrySerializeDict(T value, Writer writer, - [MarshalAs(UnmanagedType.U1)] bool returnValue, out byte[] ret) - { - if (!(value is IDictionary dict)) - { - ret = ConstMgr.Null; - return false; + writer.Position = Serialize(type, obj, null, buffer, writer.Position); } - writer.Write(dict); - ret = Return(returnValue, writer); - return true; - } - - /// - /// Check for null - /// - /// - /// - /// - /// - /// - /// true when null - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool WriteNullCheck(T value, Writer writer, - [MarshalAs(UnmanagedType.U1)] bool returnValue, out byte[] ret) - { - //null check - if (value == null) - { - writer.Write(false); // if null -> write false - ret = Return(returnValue, writer); - return true; - } - - writer.Write(true); // if not null -> write true - ret = ConstMgr.Null; - return false; - } - - /// - /// Get return value - /// - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static byte[] Return([MarshalAs(UnmanagedType.U1)] bool returnValue, Writer writer) - { - byte[] ret = ConstMgr.Null; - if (returnValue) - { - ret = writer.ToBytes(); - ObjectPool.Return(writer); - } - - return ret; + return writer.Position; } } } \ No newline at end of file diff --git a/src/Nino.Serialization/TypeModel.cs b/src/Nino.Serialization/TypeModel.cs index efa3822..ffa16c7 100644 --- a/src/Nino.Serialization/TypeModel.cs +++ b/src/Nino.Serialization/TypeModel.cs @@ -3,6 +3,7 @@ using Nino.Shared.Util; using System.Reflection; using System.Collections.Generic; +using System.Runtime.CompilerServices; using System.Threading; using Nino.Shared.IO; @@ -35,24 +36,6 @@ internal class TypeModel /// private static readonly Dictionary TypeModels = new Dictionary(10); - /// - /// Cached Models - /// - internal static Dictionary AllTypes = new Dictionary(100); - - static TypeModel() - { - var assemblies = AppDomain.CurrentDomain.GetAssemblies(); - foreach (var assembly in assemblies) - { - var types = assembly.GetTypes(); - foreach (var type in types) - { - AllTypes[type.GetHashCode()] = type; - } - } - } - /// /// Cached Models /// @@ -98,43 +81,12 @@ static TypeModel() { typeof(DateTime).GetTypeHashCode(), null }, }; - /// - /// No compression types - /// - private static readonly HashSet NoCompressionTypes = new HashSet() - { - typeof(int).GetTypeHashCode(), - typeof(uint).GetTypeHashCode(), - typeof(long).GetTypeHashCode(), - typeof(ulong).GetTypeHashCode(), - typeof(byte).GetTypeHashCode(), - typeof(sbyte).GetTypeHashCode(), - typeof(short).GetTypeHashCode(), - typeof(ushort).GetTypeHashCode(), - typeof(bool).GetTypeHashCode(), - typeof(char).GetTypeHashCode(), - typeof(decimal).GetTypeHashCode(), - typeof(double).GetTypeHashCode(), - typeof(float).GetTypeHashCode(), - typeof(DateTime).GetTypeHashCode(), - }; - /// /// Cached Models /// private static readonly ConcurrentDictionary IsEnumTypeCache = new ConcurrentDictionary(3, 30); - /// - /// Whether or not the type is a non compress type - /// - /// - /// - internal static bool IsNonCompressibleType(Type type) - { - return NoCompressionTypes.Contains(type.GetTypeHashCode()) || IsEnum(type); - } - /// /// Get a type code /// @@ -157,12 +109,42 @@ internal static TypeCode GetTypeCode(Type type) TypeCodes[hash] = ret = Type.GetTypeCode(type); return ret; } + + private static readonly ConcurrentDictionary IsManagedTypeCache = + new ConcurrentDictionary(); + + public static bool IsUnmanaged(Type type) + { + if (type.IsPrimitive || IsEnum(type)) return true; + if (!type.IsValueType) return false; + // check if we already know the answer + if (!IsManagedTypeCache.TryGetValue(type, out var ret)) + { + ret = true; + // otherwise check recursively + var fields = type + .GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); + foreach (var field in fields) + { + if (!IsUnmanaged(field.FieldType)) + { + ret = false; + break; + } + } + + IsManagedTypeCache[type] = ret; + } + + return ret; + } /// /// Get whether or not a type is enum /// /// /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool IsEnum(Type type) { if (IsEnumTypeCache.TryGetValue(type, out var ret)) return ret; @@ -176,6 +158,7 @@ internal static bool IsEnum(Type type) /// /// /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool TryGetWrapper(Type type, out INinoWrapper helper) { var hash = type.GetTypeHashCode(); @@ -286,6 +269,7 @@ internal static TypeModel CreateModel(Type type) //has to have getter and setter if (!(p.CanRead && p.CanWrite)) { + if (model.IncludeAll) continue; throw new InvalidOperationException( $"Cannot read or write property {p.Name} in {type.FullName}, cannot Serialize or Deserialize this property"); } @@ -330,5 +314,4 @@ internal static TypeModel CreateModel(Type type) return model; } } -} - +} \ No newline at end of file diff --git a/src/Nino.Serialization/Wrappers/Common/NinoWrapperBase.cs b/src/Nino.Serialization/Wrappers/Common/NinoWrapperBase.cs index 35b40aa..897f114 100644 --- a/src/Nino.Serialization/Wrappers/Common/NinoWrapperBase.cs +++ b/src/Nino.Serialization/Wrappers/Common/NinoWrapperBase.cs @@ -1,18 +1,32 @@ +using System.Runtime.CompilerServices; + namespace Nino.Serialization { public abstract class NinoWrapperBase : INinoWrapper, INinoWrapper { - public abstract void Serialize(T val, Writer writer); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public abstract void Serialize(T val, ref Writer writer); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public abstract T Deserialize(Reader reader); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public abstract int GetSize(T val); - public void Serialize(object val, Writer writer) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Serialize(object val, ref Writer writer) { - Serialize((T)val, writer); + Serialize((T)val, ref writer); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] object INinoWrapper.Deserialize(Reader reader) { return Deserialize(reader); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int GetSize(object val) + { + return GetSize((T)val); + } } } \ No newline at end of file diff --git a/src/Nino.Serialization/Wrappers/Primitives/Basics.cs b/src/Nino.Serialization/Wrappers/Primitives/Basics.cs index 81cbddc..66c58ed 100644 --- a/src/Nino.Serialization/Wrappers/Primitives/Basics.cs +++ b/src/Nino.Serialization/Wrappers/Primitives/Basics.cs @@ -5,7 +5,7 @@ namespace Nino.Serialization { internal class BoolWrapper : NinoWrapperBase { - public override void Serialize(bool val, Writer writer) + public override void Serialize(bool val, ref Writer writer) { writer.Write(val); } @@ -14,27 +14,18 @@ public override bool Deserialize(Reader reader) { return reader.ReadBool(); } + + public override int GetSize(bool val) + { + return 1; + } } internal class BoolArrWrapper : NinoWrapperBase { - public override unsafe void Serialize(bool[] val, Writer writer) + public override void Serialize(bool[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - int len = val.Length; - writer.CompressAndWrite(ref len); - if (len > 0) - { - fixed (bool* ptr = val) - { - writer.Write((byte*)ptr, ref len); - } - } + writer.Write(val.AsSpan()); } public override unsafe bool[] Deserialize(Reader reader) @@ -57,19 +48,26 @@ public override unsafe bool[] Deserialize(Reader reader) return arr; } + + public override int GetSize(bool[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length; + } } internal class BoolListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { writer.Write(v); @@ -87,13 +85,20 @@ public override List Deserialize(Reader reader) { arr.Add(reader.ReadBool()); } + return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + return 1 + 4 + val.Count; + } } internal class CharWrapper : NinoWrapperBase { - public override void Serialize(char val, Writer writer) + public override void Serialize(char val, ref Writer writer) { writer.Write(val); } @@ -102,28 +107,18 @@ public override char Deserialize(Reader reader) { return reader.ReadChar(); } + + public override int GetSize(char val) + { + return 2; + } } internal class CharArrWrapper : NinoWrapperBase { - public override unsafe void Serialize(char[] val, Writer writer) + public override void Serialize(char[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - int len = val.Length; - writer.CompressAndWrite(ref len); - if (len > 0) - { - len *= 2; - fixed (char* ptr = val) - { - writer.Write((byte*)ptr, ref len); - } - } + writer.Write(val.AsSpan()); } public override unsafe char[] Deserialize(Reader reader) @@ -143,21 +138,29 @@ public override unsafe char[] Deserialize(Reader reader) reader.ReadToBuffer((byte*)arrPtr, len * 2); } } + return arr; } + + public override int GetSize(char[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length * 2; + } } internal class CharListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { writer.Write(v); @@ -175,13 +178,20 @@ public override List Deserialize(Reader reader) { arr.Add(reader.ReadChar()); } + return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + return 1 + 4 + val.Count * 2; + } } internal class StringWrapper : NinoWrapperBase { - public override void Serialize(string val, Writer writer) + public override void Serialize(string val, ref Writer writer) { writer.Write(val); } @@ -190,19 +200,26 @@ public override string Deserialize(Reader reader) { return reader.ReadString(); } + + public override int GetSize(string val) + { + if (val is null) return 1; + return 1 + 4 + val.Length * 2; + } } internal class StringArrWrapper : NinoWrapperBase { - public override void Serialize(string[] val, Writer writer) + public override void Serialize(string[] val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Length); + writer.Write(val.Length); foreach (var v in val) { writer.Write(v); @@ -219,21 +236,35 @@ public override string[] Deserialize(Reader reader) { arr[i++] = reader.ReadString(); } + return arr; } + + public override int GetSize(string[] val) + { + if (val is null) return 1; + int size = 1 + 4; + foreach (var v in val) + { + size += 1 + 4 + v.Length * 2; + } + + return size; + } } internal class StringListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { writer.Write(v); @@ -251,13 +282,26 @@ public override List Deserialize(Reader reader) { arr.Add(reader.ReadString()); } + return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + int size = 1 + 4; + foreach (var v in val) + { + size += 1 + 4 + v.Length * 2; + } + + return size; + } } internal class DateTimeWrapper : NinoWrapperBase { - public override void Serialize(DateTime val, Writer writer) + public override void Serialize(DateTime val, ref Writer writer) { writer.Write(val); } @@ -266,50 +310,60 @@ public override DateTime Deserialize(Reader reader) { return reader.ReadDateTime(); } + + public override int GetSize(DateTime val) + { + return 8; + } } internal class DateTimeArrWrapper : NinoWrapperBase { - public override void Serialize(DateTime[] val, Writer writer) + public override void Serialize(DateTime[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - writer.CompressAndWrite(val.Length); - foreach (var v in val) - { - writer.Write(v); - } + writer.Write(val.AsSpan()); } - public override DateTime[] Deserialize(Reader reader) + public override unsafe DateTime[] Deserialize(Reader reader) { if (!reader.ReadBool()) return null; int len = reader.ReadLength(); - var arr = new DateTime[len]; - int i = 0; - while (i < len) + DateTime[] arr; + if (len == 0) { - arr[i++] = reader.ReadDateTime(); + arr = Array.Empty(); } + else + { + arr = new DateTime[len]; + fixed (DateTime* arrPtr = arr) + { + reader.ReadToBuffer((byte*)arrPtr, len * 8); + } + } + return arr; } + + public override int GetSize(DateTime[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length * 8; + } } internal class DateTimeListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { writer.Write(v); @@ -326,34 +380,16 @@ public override List Deserialize(Reader reader) { arr.Add(reader.ReadDateTime()); } + return arr; } - } - internal class GenericWrapper : NinoWrapperBase - { - public Serializer.ImporterDelegate Importer; - public Deserializer.ExporterDelegate Exporter; - - public override void Serialize(T val, Writer writer) + public override int GetSize(List val) { - if (val == null) - { - writer.Write(false); - return; - } - writer.Write(true); - if(Importer == null) - throw new InvalidOperationException($"Importer is null for type: {typeof(T)}"); - Importer(val, writer); - } + if (val is null) return 1; + int size = 1 + 4 + val.Count * 8; - public override T Deserialize(Reader reader) - { - if (!reader.ReadBool()) return default; - if(Exporter == null) - throw new InvalidOperationException($"Exporter is null for type: {typeof(T)}"); - return Exporter(reader); + return size; } } } \ No newline at end of file diff --git a/src/Nino.Serialization/Wrappers/Primitives/Decimals.cs b/src/Nino.Serialization/Wrappers/Primitives/Decimals.cs index 4cd02ca..6a376bc 100644 --- a/src/Nino.Serialization/Wrappers/Primitives/Decimals.cs +++ b/src/Nino.Serialization/Wrappers/Primitives/Decimals.cs @@ -1,11 +1,13 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace Nino.Serialization { internal class FloatWrapper : NinoWrapperBase { - public override void Serialize(float val, Writer writer) + public override void Serialize(float val, ref Writer writer) { writer.Write(val); } @@ -14,28 +16,18 @@ public override float Deserialize(Reader reader) { return reader.ReadSingle(); } + + public override int GetSize(float val) + { + return 4; + } } internal class FloatArrWrapper : NinoWrapperBase { - public override unsafe void Serialize(float[] val, Writer writer) + public override void Serialize(float[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - int len = val.Length; - writer.CompressAndWrite(ref len); - if (len > 0) - { - len *= 4; - fixed (float* ptr = val) - { - writer.Write((byte*)ptr, ref len); - } - } + writer.Write(val.AsSpan()); } public override unsafe float[] Deserialize(Reader reader) @@ -55,21 +47,29 @@ public override unsafe float[] Deserialize(Reader reader) reader.ReadToBuffer((byte*)arrPtr, len * 4); } } + return arr; } + + public override int GetSize(float[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length * 4; + } } internal class FloatListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { writer.Write(v); @@ -86,13 +86,22 @@ public override List Deserialize(Reader reader) { arr.Add(reader.ReadSingle()); } + return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + int size = 1 + 4 + val.Count * 4; + + return size; + } } internal class DoubleWrapper : NinoWrapperBase { - public override void Serialize(double val, Writer writer) + public override void Serialize(double val, ref Writer writer) { writer.Write(val); } @@ -101,28 +110,18 @@ public override double Deserialize(Reader reader) { return reader.ReadDouble(); } + + public override int GetSize(double val) + { + return 8; + } } internal class DoubleArrWrapper : NinoWrapperBase { - public override unsafe void Serialize(double[] val, Writer writer) + public override void Serialize(double[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - int len = val.Length; - writer.CompressAndWrite(ref len); - if (len > 0) - { - len *= 8; - fixed (double* ptr = val) - { - writer.Write((byte*)ptr, ref len); - } - } + writer.Write(val.AsSpan()); } public override unsafe double[] Deserialize(Reader reader) @@ -142,21 +141,29 @@ public override unsafe double[] Deserialize(Reader reader) reader.ReadToBuffer((byte*)arrPtr, len * 8); } } + return arr; } + + public override int GetSize(double[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length * 8; + } } internal class DoubleListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { writer.Write(v); @@ -173,13 +180,22 @@ public override List Deserialize(Reader reader) { arr.Add(reader.ReadDouble()); } + return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + int size = 1 + 4 + val.Count * 8; + + return size; + } } internal class DecimalWrapper : NinoWrapperBase { - public override void Serialize(decimal val, Writer writer) + public override void Serialize(decimal val, ref Writer writer) { writer.Write(val); } @@ -188,28 +204,18 @@ public override decimal Deserialize(Reader reader) { return reader.ReadDecimal(); } + + public override int GetSize(decimal val) + { + return 16; + } } internal class DecimalArrWrapper : NinoWrapperBase { - public override unsafe void Serialize(decimal[] val, Writer writer) + public override void Serialize(decimal[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - int len = val.Length; - writer.CompressAndWrite(ref len); - if (len > 0) - { - len *= 16; - fixed (decimal* ptr = val) - { - writer.Write((byte*)ptr, ref len); - } - } + writer.Write(val.AsSpan()); } public override unsafe decimal[] Deserialize(Reader reader) @@ -229,21 +235,29 @@ public override unsafe decimal[] Deserialize(Reader reader) reader.ReadToBuffer((byte*)arrPtr, len * 16); } } + return arr; } + + public override int GetSize(decimal[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length * 16; + } } internal class DecimalListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { writer.Write(v); @@ -260,7 +274,16 @@ public override List Deserialize(Reader reader) { arr.Add(reader.ReadDecimal()); } + return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + int size = 1 + 4 + val.Count * 16; + + return size; + } } } \ No newline at end of file diff --git a/src/Nino.Serialization/Wrappers/Primitives/Integers.cs b/src/Nino.Serialization/Wrappers/Primitives/Integers.cs index 67847f6..be67ac2 100644 --- a/src/Nino.Serialization/Wrappers/Primitives/Integers.cs +++ b/src/Nino.Serialization/Wrappers/Primitives/Integers.cs @@ -5,7 +5,7 @@ namespace Nino.Serialization { internal class ByteWrapper : NinoWrapperBase { - public override void Serialize(byte val, Writer writer) + public override void Serialize(byte val, ref Writer writer) { writer.Write(val); } @@ -14,27 +14,18 @@ public override byte Deserialize(Reader reader) { return reader.ReadByte(); } + + public override int GetSize(byte val) + { + return 1; + } } internal class ByteArrWrapper : NinoWrapperBase { - public override unsafe void Serialize(byte[] val, Writer writer) + public override void Serialize(byte[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - int len = val.Length; - writer.CompressAndWrite(ref len); - if (len > 0) - { - fixed (byte* ptr = val) - { - writer.Write(ptr, ref len); - } - } + writer.Write(val.AsSpan()); } public override byte[] Deserialize(Reader reader) @@ -43,19 +34,26 @@ public override byte[] Deserialize(Reader reader) int len = reader.ReadLength(); return len != 0 ? reader.ReadBytes(len) : Array.Empty(); } + + public override int GetSize(byte[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length; + } } internal class ByteListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { writer.Write(v); @@ -76,11 +74,17 @@ public override List Deserialize(Reader reader) return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + return 1 + 4 + val.Count; + } } internal class SByteWrapper : NinoWrapperBase { - public override void Serialize(sbyte val, Writer writer) + public override void Serialize(sbyte val, ref Writer writer) { writer.Write(val); } @@ -89,27 +93,18 @@ public override sbyte Deserialize(Reader reader) { return reader.ReadSByte(); } + + public override int GetSize(sbyte val) + { + return 1; + } } internal class SByteArrWrapper : NinoWrapperBase { - public override unsafe void Serialize(sbyte[] val, Writer writer) + public override void Serialize(sbyte[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - int len = val.Length; - writer.CompressAndWrite(ref len); - if (len > 0) - { - fixed (sbyte* ptr = val) - { - writer.Write((byte*)ptr, ref len); - } - } + writer.Write(val.AsSpan()); } public override unsafe sbyte[] Deserialize(Reader reader) @@ -132,19 +127,26 @@ public override unsafe sbyte[] Deserialize(Reader reader) return arr; } + + public override int GetSize(sbyte[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length; + } } internal class SByteListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { writer.Write(v); @@ -162,13 +164,20 @@ public override List Deserialize(Reader reader) { arr.Add(reader.ReadSByte()); } + return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + return 1 + 4 + val.Count; + } } internal class ShortWrapper : NinoWrapperBase { - public override void Serialize(short val, Writer writer) + public override void Serialize(short val, ref Writer writer) { writer.Write(val); } @@ -177,28 +186,18 @@ public override short Deserialize(Reader reader) { return reader.ReadInt16(); } + + public override int GetSize(short val) + { + return 2; + } } internal class ShortArrWrapper : NinoWrapperBase { - public override unsafe void Serialize(short[] val, Writer writer) + public override void Serialize(short[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - int len = val.Length; - writer.CompressAndWrite(ref len); - if (len > 0) - { - len *= 2; - fixed (short* ptr = val) - { - writer.Write((byte*)ptr, ref len); - } - } + writer.Write(val.AsSpan()); } public override unsafe short[] Deserialize(Reader reader) @@ -218,21 +217,29 @@ public override unsafe short[] Deserialize(Reader reader) reader.ReadToBuffer((byte*)arrPtr, len * 2); } } + return arr; } + + public override int GetSize(short[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length * 2; + } } internal class ShortListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { writer.Write(v); @@ -250,13 +257,20 @@ public override List Deserialize(Reader reader) { arr.Add(reader.ReadInt16()); } + return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + return 1 + 4 + val.Count * 2; + } } internal class UShortWrapper : NinoWrapperBase { - public override void Serialize(ushort val, Writer writer) + public override void Serialize(ushort val, ref Writer writer) { writer.Write(val); } @@ -265,28 +279,18 @@ public override ushort Deserialize(Reader reader) { return reader.ReadUInt16(); } + + public override int GetSize(ushort val) + { + return 2; + } } internal class UShortArrWrapper : NinoWrapperBase { - public override unsafe void Serialize(ushort[] val, Writer writer) + public override void Serialize(ushort[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - int len = val.Length; - writer.CompressAndWrite(ref len); - if (len > 0) - { - len *= 2; - fixed (ushort* ptr = val) - { - writer.Write((byte*)ptr, ref len); - } - } + writer.Write(val.AsSpan()); } public override unsafe ushort[] Deserialize(Reader reader) @@ -306,21 +310,29 @@ public override unsafe ushort[] Deserialize(Reader reader) reader.ReadToBuffer((byte*)arrPtr, len * 2); } } + return arr; } + + public override int GetSize(ushort[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length * 2; + } } internal class UShortListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { writer.Write(v); @@ -338,69 +350,78 @@ public override List Deserialize(Reader reader) { arr.Add(reader.ReadUInt16()); } + return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + return 1 + 4 + val.Count * 2; + } } internal class IntWrapper : NinoWrapperBase { - public override void Serialize(int val, Writer writer) + public override void Serialize(int val, ref Writer writer) { - writer.CompressAndWrite(ref val); + writer.Write(val); } public override int Deserialize(Reader reader) { - return reader.DecompressAndReadNumber(); + return reader.ReadInt32(); + } + + public override int GetSize(int val) + { + return 4; } } internal class IntArrWrapper : NinoWrapperBase { - public override void Serialize(int[] val, Writer writer) + public override void Serialize(int[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - writer.CompressAndWrite(val.Length); - foreach (var v in val) - { - writer.CompressAndWrite(v); - } + writer.Write(val.AsSpan()); } - public override int[] Deserialize(Reader reader) + public override unsafe int[] Deserialize(Reader reader) { if (!reader.ReadBool()) return null; int len = reader.ReadLength(); var arr = new int[len]; //read item - int i = 0; - while (i < len) + fixed (int* arrPtr = arr) { - reader.DecompressAndReadNumber(ref arr[i++]); + reader.ReadToBuffer((byte*)arrPtr, len * 4); } + return arr; } + + public override int GetSize(int[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length * 4; + } } internal class IntListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { - writer.CompressAndWrite(v); + writer.Write(v); } } @@ -413,71 +434,80 @@ public override List Deserialize(Reader reader) int i = 0; while (i++ < len) { - arr.Add(reader.DecompressAndReadNumber()); + arr.Add(reader.ReadInt32()); } + return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + return 1 + 4 + val.Count * 4; + } } internal class UIntWrapper : NinoWrapperBase { - public override void Serialize(uint val, Writer writer) + public override void Serialize(uint val, ref Writer writer) { - writer.CompressAndWrite(ref val); + writer.Write(val); } public override uint Deserialize(Reader reader) { - return reader.DecompressAndReadNumber(); + return reader.ReadUInt32(); + } + + public override int GetSize(uint val) + { + return 4; } } internal class UIntArrWrapper : NinoWrapperBase { - public override void Serialize(uint[] val, Writer writer) + public override void Serialize(uint[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - writer.CompressAndWrite(val.Length); - foreach (var v in val) - { - writer.CompressAndWrite(v); - } + writer.Write(val.AsSpan()); } - public override uint[] Deserialize(Reader reader) + public override unsafe uint[] Deserialize(Reader reader) { if (!reader.ReadBool()) return null; int len = reader.ReadLength(); var arr = new uint[len]; //read item - int i = 0; - while (i < len) + fixed (uint* arrPtr = arr) { - reader.DecompressAndReadNumber(ref arr[i++]); + reader.ReadToBuffer((byte*)arrPtr, len * 4); } + return arr; } + + public override int GetSize(uint[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length * 4; + } } internal class UIntListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { - writer.CompressAndWrite(v); + writer.Write(v); } } @@ -490,71 +520,80 @@ public override List Deserialize(Reader reader) int i = 0; while (i++ < len) { - arr.Add(reader.DecompressAndReadNumber()); + arr.Add(reader.ReadUInt32()); } + return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + return 1 + 4 + val.Count * 4; + } } internal class LongWrapper : NinoWrapperBase { - public override void Serialize(long val, Writer writer) + public override void Serialize(long val, ref Writer writer) { - writer.CompressAndWrite(ref val); + writer.Write(val); } public override long Deserialize(Reader reader) { - return reader.DecompressAndReadNumber(); + return reader.ReadInt64(); + } + + public override int GetSize(long val) + { + return 8; } } internal class LongArrWrapper : NinoWrapperBase { - public override void Serialize(long[] val, Writer writer) + public override void Serialize(long[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - writer.CompressAndWrite(val.Length); - foreach (var v in val) - { - writer.CompressAndWrite(v); - } + writer.Write(val.AsSpan()); } - public override long[] Deserialize(Reader reader) + public override unsafe long[] Deserialize(Reader reader) { if (!reader.ReadBool()) return null; int len = reader.ReadLength(); var arr = new long[len]; //read item - int i = 0; - while (i < len) + fixed (long* arrPtr = arr) { - reader.DecompressAndReadNumber(ref arr[i++]); + reader.ReadToBuffer((byte*)arrPtr, len * 8); } + return arr; } + + public override int GetSize(long[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length * 8; + } } internal class LongListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { - writer.CompressAndWrite(v); + writer.Write(v); } } @@ -567,71 +606,80 @@ public override List Deserialize(Reader reader) int i = 0; while (i++ < len) { - arr.Add(reader.DecompressAndReadNumber()); + arr.Add(reader.ReadInt64()); } + return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + return 1 + 4 + val.Count * 8; + } } internal class ULongWrapper : NinoWrapperBase { - public override void Serialize(ulong val, Writer writer) + public override void Serialize(ulong val, ref Writer writer) { - writer.CompressAndWrite(ref val); + writer.Write(val); } public override ulong Deserialize(Reader reader) { - return reader.DecompressAndReadNumber(); + return reader.ReadUInt64(); + } + + public override int GetSize(ulong val) + { + return 8; } } internal class ULongArrWrapper : NinoWrapperBase { - public override void Serialize(ulong[] val, Writer writer) + public override void Serialize(ulong[] val, ref Writer writer) { - if (val is null) - { - writer.Write(false); - return; - } - writer.Write(true); - writer.CompressAndWrite(val.Length); - foreach (var v in val) - { - writer.CompressAndWrite(v); - } + writer.Write(val.AsSpan()); } - public override ulong[] Deserialize(Reader reader) + public override unsafe ulong[] Deserialize(Reader reader) { if (!reader.ReadBool()) return null; int len = reader.ReadLength(); var arr = new ulong[len]; //read item - int i = 0; - while (i < len) + fixed (ulong* arrPtr = arr) { - reader.DecompressAndReadNumber(ref arr[i++]); + reader.ReadToBuffer((byte*)arrPtr, len * 8); } + return arr; } + + public override int GetSize(ulong[] val) + { + if (val is null) return 1; + return 1 + 4 + val.Length * 8; + } } internal class ULongListWrapper : NinoWrapperBase> { - public override void Serialize(List val, Writer writer) + public override void Serialize(List val, ref Writer writer) { if (val is null) { writer.Write(false); return; } + writer.Write(true); - writer.CompressAndWrite(val.Count); + writer.Write(val.Count); foreach (var v in val) { - writer.CompressAndWrite(v); + writer.Write(v); } } @@ -644,9 +692,16 @@ public override List Deserialize(Reader reader) int i = 0; while (i++ < len) { - arr.Add(reader.DecompressAndReadNumber()); + arr.Add(reader.ReadUInt64()); } + return arr; } + + public override int GetSize(List val) + { + if (val is null) return 1; + return 1 + 4 + val.Count * 8; + } } } \ No newline at end of file diff --git a/src/Nino.Serialization/Writer.Generic.cs b/src/Nino.Serialization/Writer.Generic.cs index 3b9a6db..047f17b 100644 --- a/src/Nino.Serialization/Writer.Generic.cs +++ b/src/Nino.Serialization/Writer.Generic.cs @@ -1,12 +1,13 @@ using System; using System.IO; -using Nino.Shared.Mgr; using System.Collections.Generic; +using System.Runtime.InteropServices; using System.Runtime.CompilerServices; +using Nino.Shared.Mgr; namespace Nino.Serialization { - public partial class Writer + public ref partial struct Writer { /// /// Write primitive values, DO NOT USE THIS FOR CUSTOM IMPORTER @@ -14,8 +15,7 @@ public partial class Writer /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void WriteCommonVal(T val) => - Serializer.Serialize(typeof(T), val, this, option, false); + public void WriteCommonVal(T val) => Position = Serializer.Serialize(typeof(T), val, null, buffer, Position); /// /// Write primitive values, DO NOT USE THIS FOR CUSTOM IMPORTER @@ -25,7 +25,7 @@ public void WriteCommonVal(T val) => /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteCommonVal(Type type, T val) => - Serializer.Serialize(type, val, this, option, false); + Position = Serializer.Serialize(type, val, null, buffer, Position); /// /// Write unmanaged type @@ -33,80 +33,108 @@ public void WriteCommonVal(Type type, T val) => /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - private unsafe void Write(ref T val, byte len) where T : unmanaged + public void Write(ref T val, int len) where T : unmanaged { - Unsafe.Write(Unsafe.Add(buffer.Data, position), val); - position += len; + Unsafe.WriteUnaligned(ref buffer[Position], val); + Position += len; } /// - /// Compress and write enum + /// Write byte[] /// - /// + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public unsafe void CompressAndWriteEnum(T val) + public unsafe void Write(Span data) where T : unmanaged { - var type = typeof(T); - if (type == ConstMgr.ObjectType) + if (data == null) { - type = val.GetType(); - switch (TypeModel.GetTypeCode(type)) - { - case TypeCode.Byte: - buffer[position++] = Unsafe.Unbox(val); - return; - case TypeCode.SByte: - buffer[position++] = *(byte*)Unsafe.Unbox(val); - return; - case TypeCode.Int16: - Unsafe.As(ref buffer.AsSpan(position, 2).GetPinnableReference()) = - Unsafe.Unbox(val); - position += 2; - return; - case TypeCode.UInt16: - Unsafe.As(ref buffer.AsSpan(position, 2).GetPinnableReference()) = - Unsafe.Unbox(val); - position += 2; - return; - case TypeCode.Int32: - CompressAndWrite(ref Unsafe.Unbox(val)); - return; - case TypeCode.UInt32: - CompressAndWrite(ref Unsafe.Unbox(val)); - return; - case TypeCode.Int64: - CompressAndWrite(ref Unsafe.Unbox(val)); - return; - case TypeCode.UInt64: - CompressAndWrite(ref Unsafe.Unbox(val)); - return; - } + Write(false); + return; + } + + Write(true); + var len = data.Length; + Write(len); + len *= sizeof(T); + MemoryMarshal.AsBytes(data).CopyTo(buffer.Slice(Position, len)); + Position += len; + } + /// + /// write enum + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteEnum(T val) + { + //boxed + if (typeof(T) == ConstMgr.ObjectType) + { + WriteEnum((object)val); return; } + ref byte p = ref MemoryMarshal.GetReference(buffer); + switch (TypeModel.GetTypeCode(typeof(T))) + { + case TypeCode.Byte: + case TypeCode.SByte: + case TypeCode.Int16: + case TypeCode.UInt16: + case TypeCode.Int32: + case TypeCode.UInt32: + byte len = (byte)Unsafe.SizeOf(); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref p, Position), val); + Position += len; + return; + case TypeCode.Int64: + case TypeCode.UInt64: + Unsafe.WriteUnaligned(ref Unsafe.Add(ref p, Position), val); + Position += 8; + return; + } + } + + /// + /// write enum + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe void WriteEnum(object val) + { + var type = val.GetType(); + ref byte p = ref MemoryMarshal.GetReference(buffer); switch (TypeModel.GetTypeCode(type)) { case TypeCode.Byte: + buffer[Position++] = Unsafe.Unbox(val); + return; case TypeCode.SByte: - Unsafe.Write(buffer.Data + position++, val); + buffer[Position++] = *(byte*)Unsafe.Unbox(val); return; case TypeCode.Int16: + Unsafe.WriteUnaligned(ref Unsafe.Add(ref p, Position), Unsafe.Unbox(val)); + Position += 2; + return; case TypeCode.UInt16: - Unsafe.Write(buffer.Data + position, val); - position += 2; + Unsafe.WriteUnaligned(ref Unsafe.Add(ref p, Position), Unsafe.Unbox(val)); + Position += 2; return; case TypeCode.Int32: - CompressAndWrite(ref Unsafe.As(ref val)); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref p, Position), Unsafe.Unbox(val)); + Position += 4; return; case TypeCode.UInt32: - CompressAndWrite(ref Unsafe.As(ref val)); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref p, Position), Unsafe.Unbox(val)); + Position += 4; return; case TypeCode.Int64: - CompressAndWrite(ref Unsafe.As(ref val)); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref p, Position), Unsafe.Unbox(val)); + Position += 8; return; case TypeCode.UInt64: - CompressAndWrite(ref Unsafe.As(ref val)); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref p, Position), Unsafe.Unbox(val)); + Position += 8; return; } } @@ -126,17 +154,18 @@ public void Write(T[] arr) } Write(true); + //write len + int len = arr.Length; + //empty - if (arr.Length == 0) + if (len == 0) { //write len - CompressAndWrite(0); + Write(0); return; } - //write len - int len = arr.Length; - CompressAndWrite(ref len); + Write(len); //write item int i = 0; while (i < len) @@ -149,7 +178,6 @@ public void Write(T[] arr) #else var eType = obj.GetType(); #endif - Write(eType.GetHashCode()); WriteCommonVal(eType, obj); } } @@ -188,16 +216,15 @@ public void Write(List lst) } Write(true); + int len = lst.Count; + //write len + Write(lst.Count); //empty - if (lst.Count == 0) + if (len == 0) { - //write len - CompressAndWrite(0); return; } - //write len - CompressAndWrite(lst.Count); //write item foreach (var c in lst) { @@ -205,11 +232,10 @@ public void Write(List lst) var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns ? ilIns.Type.ReflectionType : c.GetType(); + WriteCommonVal(eType, c); #else - var eType = c.GetType(); + WriteCommonVal(c); #endif - Write(eType.GetHashCode()); - WriteCommonVal(eType, c); } } @@ -229,16 +255,16 @@ public void Write(HashSet lst) } Write(true); + int len = lst.Count; + //write len + Write(len); //empty - if (lst.Count == 0) + if (len == 0) { //write len - CompressAndWrite(0); return; } - //write len - CompressAndWrite(lst.Count); //write item foreach (var c in lst) { @@ -246,11 +272,10 @@ public void Write(HashSet lst) var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns ? ilIns.Type.ReflectionType : c.GetType(); + WriteCommonVal(eType, c); #else - var eType = c.GetType(); + WriteCommonVal(c); #endif - Write(eType.GetHashCode()); - WriteCommonVal(eType, c); } } @@ -270,16 +295,16 @@ public void Write(Queue lst) } Write(true); + int len = lst.Count; + //write len + Write(len); //empty - if (lst.Count == 0) + if (len == 0) { //write len - CompressAndWrite(0); return; } - //write len - CompressAndWrite(lst.Count); //write item foreach (var c in lst) { @@ -287,11 +312,10 @@ public void Write(Queue lst) var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns ? ilIns.Type.ReflectionType : c.GetType(); + WriteCommonVal(eType, c); #else - var eType = c.GetType(); + WriteCommonVal(c); #endif - Write(eType.GetHashCode()); - WriteCommonVal(eType, c); } } @@ -311,16 +335,16 @@ public void Write(Stack lst) } Write(true); + int len = lst.Count; + //write len + Write(len); //empty - if (lst.Count == 0) + if (len == 0) { //write len - CompressAndWrite(0); return; } - //write len - CompressAndWrite(lst.Count); //write item foreach (var c in lst) { @@ -328,11 +352,10 @@ public void Write(Stack lst) var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns ? ilIns.Type.ReflectionType : c.GetType(); + WriteCommonVal(eType, c); #else - var eType = c.GetType(); + WriteCommonVal(c); #endif - Write(eType.GetHashCode()); - WriteCommonVal(eType, c); } } @@ -353,17 +376,16 @@ public void Write(Dictionary dictionary) } Write(true); + int len = dictionary.Count; + //write len + Write(len); //empty - if (dictionary.Count == 0) + if (len == 0) { //write len - CompressAndWrite(0); return; } - //write len - int len = dictionary.Count; - CompressAndWrite(ref len); //record keys var keys = dictionary.Keys; //write items @@ -374,22 +396,20 @@ public void Write(Dictionary dictionary) var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns ? ilIns.Type.ReflectionType : c.GetType(); + WriteCommonVal(eType, c); #else - var eType = c.GetType(); + WriteCommonVal(c); #endif - Write(eType.GetHashCode()); - WriteCommonVal(eType, c); //write val var val = dictionary[c]; #if ILRuntime eType = val is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns2 ? ilIns2.Type.ReflectionType : val.GetType(); + WriteCommonVal(eType, val); #else - eType = val.GetType(); + WriteCommonVal(val); #endif - Write(eType.GetHashCode()); - WriteCommonVal(eType, val); } } } diff --git a/src/Nino.Serialization/Writer.cs b/src/Nino.Serialization/Writer.cs index 85671e6..20c3b68 100644 --- a/src/Nino.Serialization/Writer.cs +++ b/src/Nino.Serialization/Writer.cs @@ -1,6 +1,5 @@ using System; using System.IO; -using Nino.Shared.IO; using Nino.Shared.Mgr; using System.Collections; using System.Runtime.CompilerServices; @@ -10,84 +9,27 @@ namespace Nino.Serialization /// /// A writer that writes serialization Data /// - public partial class Writer + public ref partial struct Writer { - /// - /// block size when creating buffer - /// - private const ushort BufferBlockSize = ushort.MaxValue; - /// /// Buffer that stores data /// - private ExtensibleBuffer buffer; - - /// - /// compress option - /// - private CompressOption option; + private Span buffer; /// /// Position of the current buffer /// - private int position; - - /// - /// Convert writer to byte - /// - /// - public byte[] ToBytes() - { - switch (option) - { - case CompressOption.Zlib: - return CompressMgr.Compress(buffer, position); - case CompressOption.Lz4: - throw new NotSupportedException("not support lz4 yet"); - case CompressOption.NoCompression: - return buffer.ToArray(0, position); - } - - return ConstMgr.Null; - } - - /// - /// Create a writer (needs to set up values) - /// - public Writer() - { - } + public int Position; /// /// Create a nino writer /// - /// - public Writer(CompressOption option = CompressOption.Zlib) + /// + /// + public Writer(Span buffer, int position) { - Init(option); - } - - /// - /// Init writer - /// - /// - public void Init(CompressOption compressOption) - { - if (buffer == null) - { - var peak = ObjectPool>.Peak(); - if (peak != null && peak.ExpandSize == BufferBlockSize) - { - buffer = ObjectPool>.Request(); - } - else - { - buffer = new ExtensibleBuffer(BufferBlockSize); - } - } - - position = 0; - option = compressOption; + this.buffer = buffer; + Position = position; } /// @@ -98,22 +40,7 @@ public void Init(CompressOption compressOption) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteCommonVal(Type type, object val) => - Serializer.Serialize(type, val, this, option, false); - - /// - /// Write byte[] - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public unsafe void Write(byte[] data) - { - var len = data.Length; - CompressAndWrite(len); - fixed (byte* ptr = data) - { - Write(ptr, ref len); - } - } + Position = Serializer.Serialize(type, val, null, buffer, Position); /// /// Write byte[] @@ -127,16 +54,16 @@ internal unsafe void Write(byte* data, ref int len) { while (len-- > 0) { - buffer[position++] = *data++; + buffer[Position++] = *data++; } return; } - buffer.CopyFrom(data, 0, position, len); - position += len; + Unsafe.CopyBlockUnaligned(ref buffer[Position], ref *data, (uint)len); + Position += len; } - + /// /// Write a double /// @@ -164,7 +91,7 @@ public void Write(float value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Write(DateTime value) { - Write(value.ToOADate()); + Write(ref value, ConstMgr.SizeOfLong); } /// @@ -185,7 +112,7 @@ public void Write(decimal d) [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Write(bool value) { - buffer[position++] = Unsafe.As(ref value); + Unsafe.WriteUnaligned(ref buffer[Position++], value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -211,8 +138,7 @@ public unsafe void Write(string val) if (val == string.Empty) { - Write((byte)CompressType.Byte); - Write((byte)0); + Write(0); return; } @@ -220,7 +146,7 @@ public unsafe void Write(string val) int len = strSpan.Length * ConstMgr.SizeOfUShort; fixed (char* first = &strSpan.GetPinnableReference()) { - CompressAndWrite(len); + Write(len); Write((byte*)first, ref len); } } @@ -234,7 +160,7 @@ public unsafe void Write(string val) [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Write(byte num) { - buffer[position++] = num; + buffer[Position++] = num; } /// @@ -244,7 +170,7 @@ public void Write(byte num) [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Write(sbyte num) { - buffer[position++] = Unsafe.As(ref num); + Unsafe.WriteUnaligned(ref buffer[Position++], num); } /// @@ -309,227 +235,6 @@ public void Write(ulong num) #endregion - #region write whole number without sign - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CompressAndWrite(ref ulong num) - { - if (num <= uint.MaxValue) - { - if (num <= ushort.MaxValue) - { - if (num <= byte.MaxValue) - { - buffer[position++] = (byte)CompressType.Byte; - Write(ref num, 1); - return; - } - - buffer[position++] = (byte)CompressType.UInt16; - Write(ref num, ConstMgr.SizeOfUShort); - return; - } - - buffer[position++] = (byte)CompressType.UInt32; - Write(ref num, ConstMgr.SizeOfUInt); - return; - } - - buffer[position++] = (byte)CompressType.UInt64; - Write(ref num, ConstMgr.SizeOfULong); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CompressAndWrite(ref uint num) - { - if (num <= ushort.MaxValue) - { - if (num <= byte.MaxValue) - { - buffer[position++] = (byte)CompressType.Byte; - Write(ref num, 1); - return; - } - - buffer[position++] = (byte)CompressType.UInt16; - Write(ref num, ConstMgr.SizeOfUShort); - return; - } - - buffer[position++] = (byte)CompressType.UInt32; - Write(ref num, ConstMgr.SizeOfUInt); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CompressAndWrite(ulong num) - { - ref var n = ref num; - CompressAndWrite(ref n); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CompressAndWrite(uint num) - { - ref var n = ref num; - CompressAndWrite(ref n); - } - - #endregion - - #region write whole number with sign - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CompressAndWrite(ref long num) - { - if (num < 0) - { - if (num >= int.MinValue) - { - if (num >= short.MinValue) - { - if (num >= sbyte.MinValue) - { - buffer[position++] = (byte)CompressType.SByte; - Write(ref num, 1); - return; - } - - buffer[position++] = (byte)CompressType.Int16; - Write(ref num, ConstMgr.SizeOfShort); - return; - } - - buffer[position++] = (byte)CompressType.Int32; - Write(ref num, ConstMgr.SizeOfInt); - return; - } - - buffer[position++] = (byte)CompressType.Int64; - Write(ref num, ConstMgr.SizeOfLong); - return; - } - - if (num <= int.MaxValue) - { - if (num <= short.MaxValue) - { - if (num <= byte.MaxValue) - { - buffer[position++] = (byte)CompressType.Byte; - Write(ref num, 1); - return; - } - - buffer[position++] = (byte)CompressType.UInt16; - Write(ref num, ConstMgr.SizeOfShort); - return; - } - - buffer[position++] = (byte)CompressType.UInt32; - Write(ref num, ConstMgr.SizeOfInt); - return; - } - - buffer[position++] = (byte)CompressType.UInt64; - Write(ref num, ConstMgr.SizeOfLong); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CompressAndWrite(ref int num) - { - if (num < 0) - { - if (num >= short.MinValue) - { - if (num >= sbyte.MinValue) - { - buffer[position++] = (byte)CompressType.SByte; - Write(ref num, 1); - return; - } - - buffer[position++] = (byte)CompressType.Int16; - Write(ref num, ConstMgr.SizeOfShort); - return; - } - - buffer[position++] = (byte)CompressType.Int32; - Write(ref num, ConstMgr.SizeOfInt); - return; - } - - if (num <= short.MaxValue) - { - if (num <= byte.MaxValue) - { - buffer[position++] = (byte)CompressType.Byte; - Write(ref num, 1); - return; - } - - buffer[position++] = (byte)CompressType.UInt16; - Write(ref num, ConstMgr.SizeOfShort); - return; - } - - buffer[position++] = (byte)CompressType.UInt32; - Write(ref num, ConstMgr.SizeOfInt); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CompressAndWrite(long num) - { - ref var n = ref num; - CompressAndWrite(ref n); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CompressAndWrite(int num) - { - ref var n = ref num; - CompressAndWrite(ref n); - } - - #endregion - - /// - /// Compress and write enum (no boxing) - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Obsolete("Please re-generate nino serialize code to use the latest api")] - public void CompressAndWriteEnum(Type type, ulong val) - { - switch (TypeModel.GetTypeCode(type)) - { - case TypeCode.Byte: - Write((byte)val); - return; - case TypeCode.SByte: - Write((sbyte)val); - return; - case TypeCode.Int16: - Write((short)val); - return; - case TypeCode.UInt16: - Write((ushort)val); - return; - case TypeCode.Int32: - CompressAndWrite((int)val); - return; - case TypeCode.UInt32: - CompressAndWrite((uint)val); - return; - case TypeCode.Int64: - CompressAndWrite((long)val); - return; - case TypeCode.UInt64: - CompressAndWrite(val); - return; - } - } - /// /// Write array /// @@ -545,17 +250,10 @@ public void Write(Array arr) } Write(true); - //empty - if (arr.Length == 0) - { - //write len - CompressAndWrite(0); - return; - } - //write len int len = arr.Length; - CompressAndWrite(ref len); + //empty + Write(len); //write item int i = 0; while (i < len) @@ -568,7 +266,6 @@ public void Write(Array arr) #else var eType = obj.GetType(); #endif - Write(eType.GetHashCode()); WriteCommonVal(eType, obj); } } @@ -588,16 +285,15 @@ public void Write(IList arr) } Write(true); + var len = arr.Count; + //write len + Write(len); //empty - if (arr.Count == 0) + if (len == 0) { - //write len - CompressAndWrite(0); return; } - //write len - CompressAndWrite(arr.Count); //write item foreach (var c in arr) { @@ -608,7 +304,6 @@ public void Write(IList arr) #else var eType = c.GetType(); #endif - Write(eType.GetHashCode()); WriteCommonVal(eType, c); } } @@ -628,17 +323,15 @@ public void Write(IDictionary dictionary) } Write(true); + //write len + int len = dictionary.Count; + Write(len); //empty if (dictionary.Count == 0) { - //write len - CompressAndWrite(0); return; } - //write len - int len = dictionary.Count; - CompressAndWrite(ref len); //record keys var keys = dictionary.Keys; //write items @@ -652,7 +345,6 @@ public void Write(IDictionary dictionary) #else var eType = c.GetType(); #endif - Write(eType.GetHashCode()); WriteCommonVal(eType, c); //write val var val = dictionary[c]; @@ -663,7 +355,6 @@ public void Write(IDictionary dictionary) #else eType = val.GetType(); #endif - Write(eType.GetHashCode()); WriteCommonVal(eType, val); } } diff --git a/src/Nino.UnitTests/CodeGenSerializationTest.cs b/src/Nino.UnitTests/CodeGenSerializationTest.cs index 4904ed6..b7c29e7 100644 --- a/src/Nino.UnitTests/CodeGenSerializationTest.cs +++ b/src/Nino.UnitTests/CodeGenSerializationTest.cs @@ -8,7 +8,7 @@ namespace Nino.UnitTests { [NinoSerialize] - public partial class A + public partial struct A { [NinoMember(0)] public int Val { get; set; } @@ -16,7 +16,7 @@ public partial class A [NinoSerialize] [CodeGenIgnore] - public partial class B + public partial struct B { [NinoMember(0)] public int Val { get; set; } diff --git a/src/Nino.UnitTests/ComplexSerializationTest.cs b/src/Nino.UnitTests/ComplexSerializationTest.cs index 9ef899f..a734607 100644 --- a/src/Nino.UnitTests/ComplexSerializationTest.cs +++ b/src/Nino.UnitTests/ComplexSerializationTest.cs @@ -3,6 +3,7 @@ using Nino.Serialization; using System.Collections.Generic; using Microsoft.VisualStudio.TestTools.UnitTesting; + #pragma warning disable 8618 namespace Nino.UnitTests @@ -45,11 +46,11 @@ public override string ToString() $"{string.Join(",\n", J.SelectMany(x => x).Select(x => x).SelectMany(x => x).Select(x => x))}\n"; } - private string GetDictString(Dictionary> ddd) + private string GetDictString(Dictionary> ddd) { return $"{string.Join(",", ddd.Keys.ToList())},\n" + - $" {string.Join(",", ddd.Values.ToList().SelectMany(k=>k.Keys))},\n" + - $" {string.Join(",", ddd.Values.ToList().SelectMany(k=>k.Values))}"; + $" {string.Join(",", ddd.Values.ToList().SelectMany(k => k.Keys))},\n" + + $" {string.Join(",", ddd.Values.ToList().SelectMany(k => k.Values))}"; } } @@ -80,17 +81,15 @@ public override string ToString() return $"{X},{Y},{Z},{F},{D},{Db},{Bo},{En},{Name}"; } } - + [NinoSerialize] [CodeGenIgnore] public partial class NestedData { - [NinoMember(1)] - [System.Runtime.Serialization.DataMember] + [NinoMember(1)] [System.Runtime.Serialization.DataMember] public string Name = ""; - [NinoMember(2)] - public Data[] Ps = Array.Empty(); + [NinoMember(2)] public Data[] Ps = Array.Empty(); public override string ToString() { @@ -127,6 +126,7 @@ public void TestNonGenericNoCodeGen() var dt2 = Deserializer.Deserialize(typeof(Data), buf); Assert.IsTrue(dt.ToString() == dt2.ToString()); } + [TestMethod] public void TestNonGenericCodeGen() { @@ -139,7 +139,7 @@ public void TestNonGenericCodeGen() var dt2 = Deserializer.Deserialize(typeof(A), buf); Assert.IsTrue(dt.ToString() == dt2.ToString()); } - + [TestMethod] public void TestNestedData() { @@ -184,7 +184,7 @@ public void TestNestedData() Assert.AreEqual(nd.Ps[i].Name, nd2.Ps[i].Name); } } - + [TestMethod] public void TestComplexData() { @@ -410,55 +410,6 @@ public void TestComplexData() var buf = Serializer.Serialize(data); var data2 = Deserializer.Deserialize(buf); Assert.AreEqual(data.ToString(), data2.ToString()); - Console.WriteLine(data2); - } - } - - [NinoSerialize()] - public class Base - { - [NinoMember(0)] - public int A; - } - - [NinoSerialize()] - public class Derived : Base - { - [NinoMember(1)] - public int B; - } - - public partial class ComplexSerializationTest - { - [TestMethod] - public void TestPolymorphism() - { - var data = new Derived() - { - A = 123, - B = 456 - }; - var buf = Serializer.Serialize((Base)data); - var data2 = Deserializer.Deserialize(buf); - Assert.AreEqual(data.A, data2.A); - - var lst = new List() - { - new Base() - { - A = 111, - }, - new Derived() - { - A = 999, - B = 456 - } - }; - var buf2 = Serializer.Serialize(lst); - var lst2 = Deserializer.Deserialize>(buf2); - Assert.AreEqual(lst[0].A, lst2[0].A); - Assert.AreEqual(lst[1].A, lst2[1].A); - Assert.AreEqual(((Derived)lst[1]).B, ((Derived)lst2[1]).B); } } } \ No newline at end of file diff --git a/src/Nino.UnitTests/Generated/Nino_UnitTests_A_Serialize.cs b/src/Nino.UnitTests/Generated/Nino_UnitTests_A_Serialize.cs new file mode 100644 index 0000000..5f624f2 --- /dev/null +++ b/src/Nino.UnitTests/Generated/Nino_UnitTests_A_Serialize.cs @@ -0,0 +1,46 @@ +/* this is generated by nino */ +using System.Runtime.CompilerServices; + +namespace Nino.UnitTests +{ + public partial struct A + { + public static A.SerializationHelper NinoSerializationHelper = new A.SerializationHelper(); + public unsafe class SerializationHelper: Nino.Serialization.NinoWrapperBase + { + #region NINO_CODEGEN + public SerializationHelper() + { + int ret = 1; + ret += sizeof(System.Int32); + Nino.Serialization.Serializer.SetFixedSize(ret); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void Serialize(A value, ref Nino.Serialization.Writer writer) + { + + writer.Write(true); + writer.Write(value.Val); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override A Deserialize(Nino.Serialization.Reader reader) + { + if(!reader.ReadBool()) + return default; + A value = new A(); + value.Val = reader.Read(sizeof(System.Int32)); + return value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetSize(A value) + { + + return Nino.Serialization.Serializer.GetFixedSize(); + } + #endregion + } + } +} \ No newline at end of file diff --git a/src/Nino.UnitTests/Nino/Generated/Nino_UnitTests_C_Serialize.cs b/src/Nino.UnitTests/Generated/Nino_UnitTests_C_Serialize.cs similarity index 51% rename from src/Nino.UnitTests/Nino/Generated/Nino_UnitTests_C_Serialize.cs rename to src/Nino.UnitTests/Generated/Nino_UnitTests_C_Serialize.cs index e15739e..7464bb6 100644 --- a/src/Nino.UnitTests/Nino/Generated/Nino_UnitTests_C_Serialize.cs +++ b/src/Nino.UnitTests/Generated/Nino_UnitTests_C_Serialize.cs @@ -1,13 +1,21 @@ /* this is generated by nino */ +using System.Runtime.CompilerServices; + namespace Nino.UnitTests { public partial class C { public static C.SerializationHelper NinoSerializationHelper = new C.SerializationHelper(); - public class SerializationHelper: Nino.Serialization.NinoWrapperBase + public unsafe class SerializationHelper: Nino.Serialization.NinoWrapperBase { #region NINO_CODEGEN - public override void Serialize(C value, Nino.Serialization.Writer writer) + public SerializationHelper() + { + + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void Serialize(C value, ref Nino.Serialization.Writer writer) { if(value == null) { @@ -19,6 +27,7 @@ public override void Serialize(C value, Nino.Serialization.Writer writer) writer.Write(value.As); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override C Deserialize(Nino.Serialization.Reader reader) { if(!reader.ReadBool()) @@ -28,6 +37,19 @@ public override C Deserialize(Nino.Serialization.Reader reader) value.As = reader.ReadList(); return value; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetSize(C value) + { + if(value == null) + { + return 1; + } + int ret = 1; + ret += Nino.Serialization.Serializer.GetSize(value.Name); + ret += Nino.Serialization.Serializer.GetSize(value.As); + return ret; + } #endregion } } diff --git a/src/Nino.UnitTests/IssueTest.cs b/src/Nino.UnitTests/IssueTest.cs index f3905fc..38f1232 100644 --- a/src/Nino.UnitTests/IssueTest.cs +++ b/src/Nino.UnitTests/IssueTest.cs @@ -165,7 +165,7 @@ public partial class GamePatcher2 public class SerializationHelper: Nino.Serialization.NinoWrapperBase { #region NINO_CODEGEN - public override void Serialize(GamePatcher2 value, Nino.Serialization.Writer writer) + public override void Serialize(GamePatcher2 value, ref Writer writer) { if(value == null) { @@ -174,7 +174,7 @@ public override void Serialize(GamePatcher2 value, Nino.Serialization.Writer wri } writer.Write(true); writer.Write(value.StaticValidityDateTime); - writer.CompressAndWrite(ref value.CCC); + writer.Write(value.CCC); writer.Write(value.Key); } @@ -184,10 +184,21 @@ public override GamePatcher2 Deserialize(Nino.Serialization.Reader reader) return null; GamePatcher2 value = new GamePatcher2(); value.StaticValidityDateTime = reader.ReadDateTime(); - reader.DecompressAndReadNumber(ref value.CCC); + reader.Read(ref value.CCC, sizeof(int)); value.Key = reader.ReadString(); return value; } + + public override unsafe int GetSize(GamePatcher2 value) + { + if(value == null) + return sizeof(bool); + int size = sizeof(bool); + size += sizeof(DateTime); + size += sizeof(int); + size += 1 + 4 + value.Key.Length * 2; + return size; + } #endregion } } @@ -236,6 +247,7 @@ public void RunTest() var a = Nino.Serialization.Serializer.Serialize(package); + Console.WriteLine(string.Join(",", a)); var b = Nino.Serialization.Deserializer.Deserialize(a); Assert.IsTrue(package.agreement == b.agreement); Assert.IsTrue(package.move.id == b.move.id); diff --git a/src/Nino.UnitTests/Nino.UnitTests.csproj b/src/Nino.UnitTests/Nino.UnitTests.csproj index 01bab6e..f861f95 100644 --- a/src/Nino.UnitTests/Nino.UnitTests.csproj +++ b/src/Nino.UnitTests/Nino.UnitTests.csproj @@ -6,9 +6,11 @@ false - net461;net6.0;net7.0;netcoreapp3.1 + net6.0;net7.0;netcoreapp3.1 7.3 + + true diff --git a/src/Nino.UnitTests/Nino/Generated/Nino_UnitTests_A_Serialize.cs b/src/Nino.UnitTests/Nino/Generated/Nino_UnitTests_A_Serialize.cs deleted file mode 100644 index 80917e5..0000000 --- a/src/Nino.UnitTests/Nino/Generated/Nino_UnitTests_A_Serialize.cs +++ /dev/null @@ -1,32 +0,0 @@ -/* this is generated by nino */ -namespace Nino.UnitTests -{ - public partial class A - { - public static A.SerializationHelper NinoSerializationHelper = new A.SerializationHelper(); - public class SerializationHelper: Nino.Serialization.NinoWrapperBase - { - #region NINO_CODEGEN - public override void Serialize(A value, Nino.Serialization.Writer writer) - { - if(value == null) - { - writer.Write(false); - return; - } - writer.Write(true); - writer.CompressAndWrite(value.Val); - } - - public override A Deserialize(Nino.Serialization.Reader reader) - { - if(!reader.ReadBool()) - return null; - A value = new A(); - value.Val = reader.DecompressAndReadNumber(); - return value; - } - #endregion - } - } -} \ No newline at end of file diff --git a/src/Nino.UnitTests/PrimitivesSerializationTest.cs b/src/Nino.UnitTests/PrimitivesSerializationTest.cs index e6e0e03..ae0ab26 100644 --- a/src/Nino.UnitTests/PrimitivesSerializationTest.cs +++ b/src/Nino.UnitTests/PrimitivesSerializationTest.cs @@ -22,10 +22,9 @@ public struct EmptyStruct public void TestEmptyStruct() { var val = new EmptyStruct(); - byte[] buf = Serialization.Serializer.Serialize(val, Serialization.CompressOption.NoCompression); + byte[] buf = Serialization.Serializer.Serialize(val); EmptyStruct val2 = - Serialization.Deserializer.Deserialize(new ArraySegment(buf, 0, buf.Length), - Serialization.CompressOption.NoCompression); + Serialization.Deserializer.Deserialize(new ArraySegment(buf, 0, buf.Length)); Assert.AreEqual(val, val2); }