diff --git a/Docs/Serialization.md b/Docs/Serialization.md index 211b38d..5425da9 100644 --- a/Docs/Serialization.md +++ b/Docs/Serialization.md @@ -47,6 +47,8 @@ public partial struct NotIncludeAllClass > **强烈建议通过生成代码来提高性能,但是需要注意,每次更新字段或属性后需要重新生成代码来更新** > > 如果不需要序列化`字符串`或`非固定长度的集合(例如string[])`,则会生成非常高效的代码 +> +> **强烈推荐使用自动收集,这样会最大限度的优化生成出来的代码** @@ -54,6 +56,7 @@ public partial struct NotIncludeAllClass - 可以给已序列化的相同类型的字段/属性改名 - 可以给已序列化的字段/属性改成相同大小的类型(`int`->`uint`,`int`->`float`,`List`->`List`->`List - List<可Nino序列化类型>,HashSet<可Nino序列化类型>,Queue<可Nino序列化类型>,Stack<可Nino序列化类型>,可Nino序列化类型[], ICollection<可Nino序列化> - Dictionary,IDictionary<可Nino序列化> @@ -84,37 +87,11 @@ public partial struct NotIncludeAllClass -## ILRuntime - -Nino支持ILRuntime的使用,但需要初始化ILRuntime: - -1. 把ILRuntime导入Unity工程,并对ILRuntime目录生成assembly definition文件 - -2. 进入Nino_Unity/Assets/Nino/Serialization,找到```Nino.Serialization.asmdef```,选中后在Inspector上添加对ILRuntime的assembly definition的引用,并apply变动 - -3. 在PlayerSetting里Symbol区域添加```ILRuntime```(如果Symbol一栏不是空的,记得两个标签之间要用```;```隔开) - -4. 调用ILRuntime解析工具 - - ```csharp - Nino.Serialization.ILRuntimeResolver.RegisterILRuntimeClrRedirection(domain); - ``` +## 代码热更 - domain是ILRuntime的AppDomain,该方法应该在domain.LoadAssembly后,进入热更代码前调用,参考Test11 +- 暂时因为**ILRuntime**原理限制,Nino无法支持**ILRuntime** -5. 热更工程引用Library/ScriptAssemblies/Nino.Serialization.dll和Library/ScriptAssemblies/Nino.Shared.dll - -6. ILRuntime下**非常不建议**给热更工程的结构体生成静态性能优化代码,**因为原理限制会产生负优化!!!**,如果执意要生产代码,请参考后续步骤,反之可以忽略后面的步骤 - -7. 如果需要给热更工程生成代码,打开```Nino_Unity/Assets/Nino/Editor/SerializationHelper.cs```,修改```ExternalDLLPath```字段内的```Assets/Nino/Test/Editor/Serialization/Test11.bytes```,变为你的热更工程的DLL文件的路径,记得带后缀,修改生效后,在菜单栏点击```Nino/Generator/Serialization Code```即可给热更工程的Nino序列化类型生成代码 - -8. 生成热更工程的代码后,需要把生成的热更序列化类型的代码从Unity工程移到热更工程,并且在Unity工程删掉会报错的热更类型代码 - -> 如果用的是assembly definition来生成热更库的,需要把生成的热更代码放到assembly definition的目录内,把外部会报错的代码挪进去就好 -> -> 需要注意的是,ILRuntime下生成与不生成代码的差距不是特别大 -> -> ILRuntime下也不支持多态! +- Nino支持**HybridCLR** @@ -135,28 +112,71 @@ Nino支持ILRuntime的使用,但需要初始化ILRuntime: 示例: ```csharp -public class Vector3Wrapper : NinoWrapperBase +[NinoSerialize(false)] +public partial class CustomTypeTest +{ + [NinoMember(1)] public Vector3 v3; + + [NinoMember(2)] private DateTime dt = DateTime.Now; + + [NinoMember(3)] public int? ni { get; set; } + + [NinoMember(4)] public List qs; + + [NinoMember(5)] public Matrix4x4 m; + + [NinoMember(6)] public Dictionary dict; + + [NinoMember(7)] public Dictionary dict2; + + public override string ToString() + { + return + $"{v3}, {dt}, {ni}, {String.Join(",", qs)}, {m.ToString()}\n" + + $"dict.keys: {string.Join(",", dict.Keys)},\ndict.values:{string.Join(",", dict.Values)}\n" + + $"dict2.keys: {string.Join(",", dict2.Keys)},\ndict2.values:{string.Join(",", dict2.Values)}\n"; + } +} + +public class CustomTypeTestWrapper : NinoWrapperBase { - public override void Serialize(Vector3 val, ref Writer writer) + public override void Serialize(CustomTypeTest val, ref Writer writer) { - writer.Write(val.x); - writer.Write(val.y); - writer.Write(val.z); + writer.Write(ref val.v3, sizeof(float) * 3); + writer.Write(ref val.m, sizeof(float) * 16); + writer.Write(val.ni); + writer.Write(val.qs); + writer.Write(val.dict); + writer.Write(val.dict2); } - public override Vector3 Deserialize(Reader reader) + public override CustomTypeTest Deserialize(Reader reader) { - return new Vector3(reader.Read(4), reader.Read(4), reader.Read(4)); + var ret = new CustomTypeTest(); + reader.Read(ref ret.v3, sizeof(float) * 3); + reader.Read(ref ret.m, sizeof(float) * 16); + ret.ni = reader.ReadNullable(); + ret.qs = reader.ReadList(); + ret.dict = reader.ReadDictionary(); + ret.dict2 = reader.ReadDictionary(); + return ret; } - public override int GetSize(Vector3 val) + public override int GetSize(CustomTypeTest val) { - return 12; + int ret = 1; + ret += sizeof(float) * 3; + ret += sizeof(float) * 16; + ret += Serializer.GetSize(val.ni); + ret += Serializer.GetSize(val.qs); + ret += Serializer.GetSize(val.dict); + ret += Serializer.GetSize(val.dict2); + return ret; } } //别忘了在某个地方调用下面的代码: -WrapperManifest.AddWrapper(typeof(Vector3), new Vector3Wrapper()); +WrapperManifest.AddWrapper(typeof(CustomTypeTest), new CustomTypeTestWrapper()); ``` @@ -167,7 +187,7 @@ WrapperManifest.AddWrapper(typeof(Vector3), new Vector3Wrapper()); - 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)) @@ -185,7 +205,7 @@ Nino支持以下三种压缩方式: > 序列化和反序列化的时候可以选择压缩方式,但是需要注意反序列化数据的时候,需要用和序列化时相同的压缩方式去反序列化 > -> 注意,v1.2.0暂时仅支持无压缩 +> 注意,v1.2.0~1.2.2暂时仅支持无压缩 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 de666c2..e7acec1 100644 --- a/Nino_Unity/Assets/Nino/Generated/Nino_Test_BuildTestDataCodeGen_Serialize.cs +++ b/Nino_Unity/Assets/Nino/Generated/Nino_Test_BuildTestDataCodeGen_Serialize.cs @@ -23,19 +23,8 @@ public override void Serialize(BuildTestDataCodeGen value, ref Nino.Serializatio return; } writer.Write(true); - 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(ref value.a, sizeof(System.Byte),ref value.b, sizeof(System.SByte),ref value.c, sizeof(System.Int16),ref value.d, sizeof(System.UInt16),ref value.e, sizeof(System.Int32),ref value.f, sizeof(System.UInt32),ref value.g, sizeof(System.Int64),ref value.h, sizeof(System.UInt64)); + writer.Write(ref value.i, sizeof(System.Single),ref value.j, sizeof(System.Double),ref value.k, sizeof(System.Decimal),ref value.l, sizeof(System.Boolean),ref value.m, sizeof(System.Char)); writer.Write(value.n); writer.Write(value.o); writer.Write(value.p); @@ -53,19 +42,8 @@ public override BuildTestDataCodeGen Deserialize(Nino.Serialization.Reader reade if(!reader.ReadBool()) return null; BuildTestDataCodeGen value = new BuildTestDataCodeGen(); - 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)); + reader.Read(ref value.a, sizeof(System.Byte),ref value.b, sizeof(System.SByte),ref value.c, sizeof(System.Int16),ref value.d, sizeof(System.UInt16),ref value.e, sizeof(System.Int32),ref value.f, sizeof(System.UInt32),ref value.g, sizeof(System.Int64),ref value.h, sizeof(System.UInt64)); + reader.Read(ref value.i, sizeof(System.Single),ref value.j, sizeof(System.Double),ref value.k, sizeof(System.Decimal),ref value.l, sizeof(System.Boolean),ref value.m, sizeof(System.Char)); value.n = reader.ReadString(); value.o = reader.ReadList(); value.p = reader.ReadList(); 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 9d42158..861a096 100644 --- a/Nino_Unity/Assets/Nino/Generated/Nino_Test_CustomTypeTest_Serialize.cs +++ b/Nino_Unity/Assets/Nino/Generated/Nino_Test_CustomTypeTest_Serialize.cs @@ -23,11 +23,10 @@ public override void Serialize(CustomTypeTest value, ref Nino.Serialization.Writ return; } writer.Write(true); - writer.WriteCommonVal(value.v3); - writer.Write(ref value.dt, sizeof(System.DateTime)); - writer.WriteCommonVal>(value.ni); + writer.Write(ref value.v3, sizeof(UnityEngine.Vector3),ref value.dt, sizeof(System.DateTime)); + writer.Write(value.ni); writer.Write(value.qs); - writer.WriteCommonVal(value.m); + writer.Write(ref value.m, sizeof(UnityEngine.Matrix4x4)); writer.Write(value.dict); writer.Write(value.dict2); } @@ -38,11 +37,10 @@ public override CustomTypeTest Deserialize(Nino.Serialization.Reader reader) if(!reader.ReadBool()) return null; CustomTypeTest value = new CustomTypeTest(); - value.v3 = reader.ReadCommonVal(); - reader.Read(ref value.dt, sizeof(System.DateTime)); - value.ni = reader.ReadCommonVal>(); + reader.Read(ref value.v3, sizeof(UnityEngine.Vector3),ref value.dt, sizeof(System.DateTime)); + value.ni = reader.ReadNullable(); value.qs = reader.ReadList(); - value.m = reader.ReadCommonVal(); + reader.Read(ref value.m, sizeof(UnityEngine.Matrix4x4)); value.dict = reader.ReadDictionary(); value.dict2 = reader.ReadDictionary(); return value; 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 a896db9..082a81a 100644 --- a/Nino_Unity/Assets/Nino/Generated/Nino_Test_Data_Serialize.cs +++ b/Nino_Unity/Assets/Nino/Generated/Nino_Test_Data_Serialize.cs @@ -28,14 +28,7 @@ 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); + writer.Write(ref value.x, sizeof(System.Int32),ref value.y, sizeof(System.Int16),ref value.z, sizeof(System.Int64),ref value.f, sizeof(System.Single),ref value.d, sizeof(System.Decimal),ref value.db, sizeof(System.Double),ref value.bo, sizeof(System.Boolean),ref value.en, sizeof(Nino.Test.TestEnum)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -44,14 +37,7 @@ 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); + reader.Read(ref value.x, sizeof(System.Int32),ref value.y, sizeof(System.Int16),ref value.z, sizeof(System.Int64),ref value.f, sizeof(System.Single),ref value.d, sizeof(System.Decimal),ref value.db, sizeof(System.Double),ref value.bo, sizeof(System.Boolean),ref value.en, sizeof(Nino.Test.TestEnum)); return value; } 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 82d6d3d..a35fa86 100644 --- a/Nino_Unity/Assets/Nino/Generated/Nino_Test_IncludeAllClassCodeGen_Serialize.cs +++ b/Nino_Unity/Assets/Nino/Generated/Nino_Test_IncludeAllClassCodeGen_Serialize.cs @@ -28,10 +28,7 @@ public override void Serialize(IncludeAllClassCodeGen value, ref Nino.Serializat return; } writer.Write(true); - 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)); + writer.Write(ref value.a, sizeof(System.Int32),ref value.b, sizeof(System.Int64),ref value.c, sizeof(System.Single),ref value.d, sizeof(System.Double)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -40,10 +37,7 @@ public override IncludeAllClassCodeGen Deserialize(Nino.Serialization.Reader rea if(!reader.ReadBool()) return null; IncludeAllClassCodeGen value = new IncludeAllClassCodeGen(); - 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)); + reader.Read(ref value.a, sizeof(System.Int32),ref value.b, sizeof(System.Int64),ref value.c, sizeof(System.Single),ref value.d, sizeof(System.Double)); return value; } 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 3fde7a9..94dff11 100644 --- a/Nino_Unity/Assets/Nino/Generated/Nino_Test_NotIncludeAllClass_Serialize.cs +++ b/Nino_Unity/Assets/Nino/Generated/Nino_Test_NotIncludeAllClass_Serialize.cs @@ -28,10 +28,7 @@ public override void Serialize(NotIncludeAllClass value, ref Nino.Serialization. return; } writer.Write(true); - 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)); + writer.Write(ref value.a, sizeof(System.Int32),ref value.b, sizeof(System.Int64),ref value.c, sizeof(System.Single),ref value.d, sizeof(System.Double)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -40,10 +37,7 @@ public override NotIncludeAllClass Deserialize(Nino.Serialization.Reader reader) if(!reader.ReadBool()) return null; NotIncludeAllClass value = new NotIncludeAllClass(); - 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)); + reader.Read(ref value.a, sizeof(System.Int32),ref value.b, sizeof(System.Int64),ref value.c, sizeof(System.Single),ref value.d, sizeof(System.Double)); return value; } diff --git a/Nino_Unity/Assets/Nino/Serialization/CodeGenerator.cs b/Nino_Unity/Assets/Nino/Serialization/CodeGenerator.cs index 1c83bdf..d3ef3e7 100644 --- a/Nino_Unity/Assets/Nino/Serialization/CodeGenerator.cs +++ b/Nino_Unity/Assets/Nino/Serialization/CodeGenerator.cs @@ -1,12 +1,11 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using Nino.Shared.Mgr; using Nino.Shared.Util; using System.Reflection; -using System.Collections.Generic; -using System.Runtime.CompilerServices; namespace Nino.Serialization { @@ -194,15 +193,60 @@ public override int GetSize({type} value) model = TypeModel.CreateModel(type); } - HashSet members = model.Members; + var members = model.Members; #region serialize //build params StringBuilder sb = new StringBuilder(); - foreach (var member in members) + List unmanagedMembers = new List(); + for (int i = 0; i < members.Count; i++) { - var mt = member is FieldInfo fi ? fi.FieldType : ((PropertyInfo)member).PropertyType; + var info = members[i]; + var member = info.Member; + var mt = info.Type; + + //try optimize + if (TypeModel.IsUnmanaged(mt) && member is FieldInfo) + { + unmanagedMembers.Clear(); + unmanagedMembers.Add(info); + for (int j = i + 1; j < members.Count; j++) + { + var info2 = members[j]; + var member2 = info2.Member; + var mt2 = info2.Type; + if (TypeModel.IsUnmanaged(mt2) && member2 is FieldInfo) + { + unmanagedMembers.Add(info2); + } + else + { + break; + } + } + + i += unmanagedMembers.Count - 1; + //batch write with batch size 8 + while (unmanagedMembers.Count > 0) + { + if (unmanagedMembers.Count <= 8) + { + sb.Append( + $" writer.Write({string.Join(",", unmanagedMembers.Select(x => $"ref value.{x.Member.Name}, sizeof({BeautifulLongTypeName(x.Type)})"))});\n"); + unmanagedMembers.Clear(); + } + else + { + sb.Append( + $" writer.Write({string.Join(",", unmanagedMembers.Take(8).Select(x => $"ref value.{x.Member.Name}, sizeof({BeautifulLongTypeName(x.Type)})"))});\n"); + unmanagedMembers.RemoveRange(0, 8); + } + } + + continue; + } + //enum if (mt.IsEnum) { @@ -219,6 +263,11 @@ public override int GetSize({type} value) { sb.Append($" writer.Write(value.{member.Name});\n"); } + //nullable + else if (mt.IsGenericType && mt.GetGenericTypeDefinition() == ConstMgr.NullableDefType) + { + sb.Append($" writer.Write(value.{member.Name});\n"); + } //basic type else { @@ -241,9 +290,53 @@ public override int GetSize({type} value) #region deserialize sb.Clear(); - foreach (var member in members) + for (int i = 0; i < members.Count; i++) { - var mt = member is FieldInfo fi ? fi.FieldType : ((PropertyInfo)member).PropertyType; + var info = members[i]; + var member = info.Member; + var mt = info.Type; + + //try optimize + if (TypeModel.IsUnmanaged(mt) && member is FieldInfo) + { + unmanagedMembers.Clear(); + unmanagedMembers.Add(info); + for (int j = i + 1; j < members.Count; j++) + { + var info2 = members[j]; + var member2 = info2.Member; + var mt2 = info2.Type; + if (TypeModel.IsUnmanaged(mt2) && member2 is FieldInfo) + { + unmanagedMembers.Add(info2); + } + else + { + break; + } + } + + i += unmanagedMembers.Count - 1; + //batch write with batch size 8 + while (unmanagedMembers.Count > 0) + { + if (unmanagedMembers.Count <= 8) + { + sb.Append( + $" reader.Read({string.Join(",", unmanagedMembers.Select(x => $"ref value.{x.Member.Name}, sizeof({BeautifulLongTypeName(x.Type)})"))});\n"); + unmanagedMembers.Clear(); + } + else + { + sb.Append( + $" reader.Read({string.Join(",", unmanagedMembers.Take(8).Select(x => $"ref value.{x.Member.Name}, sizeof({BeautifulLongTypeName(x.Type)})"))});\n"); + unmanagedMembers.RemoveRange(0, 8); + } + } + + continue; + } + //enum if (mt.IsEnum) { @@ -292,6 +385,15 @@ public override int GetSize({type} value) sb.Append( $" value.{member.Name} = reader.ReadDictionary<{BeautifulLongTypeName(keyType)},{BeautifulLongTypeName(valueType)}>();\n"); } + //nullable + else if (mt.IsGenericType && mt.GetGenericTypeDefinition() == ConstMgr.NullableDefType) + { + var args = mt.GetGenericArguments(); + Type keyType = args[0]; + + sb.Append( + $" value.{member.Name} = reader.ReadNullable<{BeautifulLongTypeName(keyType)}>();\n"); + } //not enum -> basic type else { @@ -315,16 +417,19 @@ public override int GetSize({type} value) sb.Clear(); if (TypeModel.IsFixedSizeType(type)) { - sb.Append($" return Nino.Serialization.Serializer.GetFixedSize<{BeautifulLongTypeName(type)}>();"); + sb.Append( + $" return Nino.Serialization.Serializer.GetFixedSize<{BeautifulLongTypeName(type)}>();"); } else { sb.Append(" int ret = 1;\n"); - foreach (var member in members) + foreach (var info in members) { + var member = info.Member; sb.Append( $" ret += Nino.Serialization.Serializer.GetSize(value.{member.Name});\n"); } + sb.Append(" return ret;"); } @@ -339,13 +444,15 @@ public override int GetSize({type} value) if (TypeModel.IsFixedSizeType(type)) { sb.Append(" int ret = 1;\n"); - foreach (var member in members) + foreach (var info in members) { - var mt = member is FieldInfo fi ? fi.FieldType : ((PropertyInfo)member).PropertyType; + var mt = info.Type; sb.Append( $" ret += sizeof({BeautifulLongTypeName(mt)});\n"); } - sb.Append($" Nino.Serialization.Serializer.SetFixedSize<{BeautifulLongTypeName(type)}>(ret);"); + + sb.Append( + $" Nino.Serialization.Serializer.SetFixedSize<{BeautifulLongTypeName(type)}>(ret);"); } //replace template fields @@ -517,6 +624,14 @@ private static string GetSerializeBasicTypeStatement(Type mt, string val, bool i return builder.ToString(); } + if (mt.IsGenericType && mt.GetGenericTypeDefinition() == ConstMgr.NullableDefType) + { + StringBuilder builder = new StringBuilder(); + builder.Append(space).Append(Repeat(" ", indent)) + .Append($"writer.Write({val});\n"); + return builder.ToString(); + } + return $"writer.WriteCommonVal<{BeautifulLongTypeName(mt)}>({val})"; } } diff --git a/Nino_Unity/Assets/Nino/Serialization/Deserializer.cs b/Nino_Unity/Assets/Nino/Serialization/Deserializer.cs index 8273981..9c8fa41 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Deserializer.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Deserializer.cs @@ -92,12 +92,24 @@ internal static T Deserialize(Span data, Reader reader, return ret; } + //enum + if (TryDeserializeEnum(type, reader, returnDispose, out var e)) + { + return e; + } + //code generated type if (TryDeserializeCodeGenType(type, reader, false, returnDispose, out ret)) { return ret; } + //unmanaged type + if (TryDeserializeUnmanagedType(type, reader, returnDispose, out var un)) + { + return un; + } + /* * GC DESERIALIZATION WHILE T IS STRUCT */ @@ -148,10 +160,6 @@ internal static object Deserialize(Type type, object val, Span data, Reade } } -#if ILRuntime - type = type.ResolveRealType(); -#endif - //basic type if (TryDeserializeWrapperType(type, reader, true, returnDispose, out object basicObj)) { @@ -163,13 +171,19 @@ internal static object Deserialize(Type type, object val, Span data, Reade { return e; } - + //code generated type if (TryDeserializeCodeGenType(type, reader, true, returnDispose, out object codeGenRet)) { return codeGenRet; } + //unmanaged type + if (TryDeserializeUnmanagedType(type, reader, returnDispose, out var un)) + { + return un; + } + /* * CUSTOM STRUCT/CLASS SERIALIZATION */ @@ -181,11 +195,7 @@ internal static object Deserialize(Type type, object val, Span data, Reade //create type if (val == null || val == ConstMgr.Null) { -#if ILRuntime - val = ILRuntimeResolver.CreateInstance(type); -#else val = Activator.CreateInstance(type); -#endif } //Get Attribute that indicates a class/struct to be serialized @@ -204,7 +214,7 @@ internal static object Deserialize(Type type, object val, Span data, Reade } //start Deserialize - foreach (var member in model.Members) + foreach (var info in model.Members) { //if end, skip if (reader.EndOfReader) @@ -212,10 +222,10 @@ internal static object Deserialize(Type type, object val, Span data, Reade break; } - type = member is FieldInfo fi ? fi.FieldType : ((PropertyInfo)member).PropertyType; + type = info.Type; //read basic values - SetMember(member, val, Deserialize(type, ConstMgr.Null, Span.Empty, reader, false)); + SetMember(info.Member, val, Deserialize(type, ConstMgr.Null, Span.Empty, reader, false)); } if (returnDispose) @@ -384,6 +394,33 @@ private static bool TryDeserializeDict(Type type, Type genericDefType, Reader re return false; } + /// + /// Try deserialize enum + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryDeserializeEnum(Type type, Reader reader, + [MarshalAs(UnmanagedType.U1)] bool returnDispose, out T obj) + { + obj = default; + if (TypeModel.IsEnum(type)) + { + reader.ReadEnum(ref obj); + if (returnDispose) + { + ObjectPool.Return(reader); + } + + return true; + } + + return false; + } + /// /// Try deserialize enum /// @@ -400,16 +437,6 @@ private static bool TryDeserializeEnum(Type type, Reader reader, { var underlyingType = Enum.GetUnderlyingType(type); var ret = reader.ReadEnum(underlyingType); -#if ILRuntime - if (type is ILRuntime.Reflection.ILRuntimeType) - { - if (underlyingType == ConstMgr.LongType - || underlyingType == ConstMgr.UIntType - || underlyingType == ConstMgr.ULongType) - obj = unchecked((long)ret); - obj = unchecked((int)ret); - } -#endif obj = Enum.ToObject(type, ret); if (returnDispose) { @@ -423,6 +450,58 @@ private static bool TryDeserializeEnum(Type type, Reader reader, return false; } + /// + /// Try deserialize enum + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryDeserializeUnmanagedType(Type type, Reader reader, + [MarshalAs(UnmanagedType.U1)] bool returnDispose, out T obj) + { + obj = default; + if (TypeModel.IsUnmanaged(type)) + { + reader.ReadAsUnmanaged(ref obj, Marshal.SizeOf(type)); + if (returnDispose) + { + ObjectPool.Return(reader); + } + return true; + } + + return false; + } + + /// + /// Try deserialize enum + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryDeserializeUnmanagedType(Type type, Reader reader, + [MarshalAs(UnmanagedType.U1)] bool returnDispose, out object obj) + { + obj = default; + if (TypeModel.IsUnmanaged(type)) + { + reader.ReadAsUnmanaged(ref obj, Marshal.SizeOf(type)); + if (returnDispose) + { + ObjectPool.Return(reader); + } + return true; + } + + return false; + } + /// /// Check for null /// diff --git a/Nino_Unity/Assets/Nino/Serialization/ILRuntimeResolver.cs b/Nino_Unity/Assets/Nino/Serialization/ILRuntimeResolver.cs deleted file mode 100644 index e3c564e..0000000 --- a/Nino_Unity/Assets/Nino/Serialization/ILRuntimeResolver.cs +++ /dev/null @@ -1,365 +0,0 @@ -using System; -using System.Text; -using System.Linq; -using Nino.Shared.Mgr; -using System.Reflection; -using System.Collections.Generic; -#if ILRuntime -#if DEBUG && !DISABLE_ILRUNTIME_DEBUG -using AutoList = System.Collections.Generic.List; -#else -using AutoList = ILRuntime.Other.UncheckedList; -#endif -#endif - -// ReSharper disable CognitiveComplexity -// ReSharper disable RedundantNameQualifier -// ReSharper disable RedundantExplicitArrayCreation - -namespace Nino.Serialization -{ -#if ILRuntime - /// - /// ILRuntime helper - /// - public static class ILRuntimeResolver - { - internal static ILRuntime.Runtime.Enviorment.AppDomain appDomain; - - private static readonly Dictionary IlRuntimeTypes = new Dictionary(); - - /// - /// Get ILType - /// - /// - /// - public static Type FindType(string metaName) - { - IlRuntimeTypes.TryGetValue(metaName, out Type type); - return type; - } - - /// - /// Create ILTypeInstance - /// - /// - /// - public static object CreateInstance(Type type) - { - if (appDomain != null) - { - string typeName = type.FullName; - if (FindType(typeName) != null) - { - return appDomain.Instantiate(typeName); - } - - if (typeName != null && appDomain.LoadedTypes.ContainsKey(typeName)) - { - IlRuntimeTypes[typeName] = type; - return appDomain.Instantiate(typeName); - } - } - - return Activator.CreateInstance(type); - } - - /// - /// Reg ILRuntime - /// - /// - public static unsafe void RegisterILRuntimeClrRedirection(ILRuntime.Runtime.Enviorment.AppDomain domain) - { - appDomain = domain; - //cache types - IlRuntimeTypes.Clear(); - var allTypes = domain.LoadedTypes.Values.Select(x => x.ReflectionType).ToArray(); - foreach (var t in allTypes) - { - if (t.FullName != null) - { - IlRuntimeTypes[t.FullName] = t; - TypeModel.AllTypes[t.GetHashCode()] = t; - } - } - - try - { - appDomain.RegisterCrossBindingAdaptor(new SerializationHelper1ILTypeInstanceAdapter()); - } - catch - { - //ignore - } - - //reg redirections - MethodBase method; - var type = typeof(Nino.Serialization.Serializer); - var genericMethods = new Dictionary>(); - List lst; - foreach (var m in type.GetMethods()) - { - if (m.IsGenericMethodDefinition) - { - if (!genericMethods.TryGetValue(m.Name, out lst)) - { - lst = new List(); - genericMethods[m.Name] = lst; - } - - lst.Add(m); - } - } - - var args = new Type[] { typeof(ILRuntime.Runtime.Intepreter.ILTypeInstance) }; - var ps = new Type[] { args[0], typeof(Nino.Serialization.CompressOption) }; - if (genericMethods.TryGetValue("Serialize", out lst)) - { - foreach (var m in lst) - { - if (ILRuntime.Runtime.Extensions.MatchGenericParameters(m, args, typeof(System.Byte[]), - ps)) - { - method = m.MakeGenericMethod(args); - appDomain.RegisterCLRMethodRedirection(method, Serialize_0); - - break; - } - } - } - - type = typeof(Nino.Serialization.Deserializer); - genericMethods.Clear(); - lst?.Clear(); - foreach (var m in type.GetMethods()) - { - if (m.IsGenericMethodDefinition) - { - if (!genericMethods.TryGetValue(m.Name, out lst)) - { - lst = new List(); - genericMethods[m.Name] = lst; - } - - lst.Add(m); - } - } - - //Deserialize - if (genericMethods.TryGetValue("Deserialize", out lst)) - { - foreach (var m in lst) - { - appDomain.RegisterCLRMethodRedirection(m, Deserialize_0); - } - } - } - - /// - /// Deserialize reg - /// - /// - /// - /// - /// - /// - /// - private static unsafe ILRuntime.Runtime.Stack.StackObject* Deserialize_0( - ILRuntime.Runtime.Intepreter.ILIntepreter intp, ILRuntime.Runtime.Stack.StackObject* esp, - AutoList mStack, - ILRuntime.CLR.Method.CLRMethod method, bool isNewObj) - { - var domain = intp.AppDomain; - var ret = ILRuntime.Runtime.Intepreter.ILIntepreter.Minus(esp, 2); - - var ptrOfThisMethod = ILRuntime.Runtime.Intepreter.ILIntepreter.Minus(esp, 1); - var @option = (Nino.Serialization.CompressOption)ILRuntime.CLR.Utils.Extensions.CheckCLRTypes( - typeof(Nino.Serialization.CompressOption), - ILRuntime.Runtime.Stack.StackObject.ToObject(ptrOfThisMethod, domain, mStack), - (ILRuntime.CLR.Utils.Extensions.TypeFlags)20); - intp.Free(ptrOfThisMethod); - - ptrOfThisMethod = ILRuntime.Runtime.Intepreter.ILIntepreter.Minus(esp, 2); - var @data = ILRuntime.Runtime.Stack.StackObject.ToObject(ptrOfThisMethod, domain, mStack); - intp.Free(ptrOfThisMethod); - - //获取泛型参数的实际类型 - var genericArguments = method.GenericArguments; - var t = genericArguments[0]; - - object resultOfThisMethod = null; - if (@data is byte[] buf) - { - resultOfThisMethod = - Nino.Serialization.Deserializer.Deserialize(t.ReflectionType, buf, option); - } - else if (@data is ArraySegment seg) - { - resultOfThisMethod = - Nino.Serialization.Deserializer.Deserialize(t.ReflectionType, seg, option); - } - - return ILRuntime.Runtime.Intepreter.ILIntepreter.PushObject(ret, mStack, resultOfThisMethod); - } - - /// - /// Serialize reg - /// - /// - /// - /// - /// - /// - /// - private static unsafe ILRuntime.Runtime.Stack.StackObject* Serialize_0( - ILRuntime.Runtime.Intepreter.ILIntepreter intp, ILRuntime.Runtime.Stack.StackObject* esp, - AutoList mStack, - ILRuntime.CLR.Method.CLRMethod method, bool isNewObj) - { - var domain = intp.AppDomain; - var ret = ILRuntime.Runtime.Intepreter.ILIntepreter.Minus(esp, 2); - - var ptrOfThisMethod = ILRuntime.Runtime.Intepreter.ILIntepreter.Minus(esp, 1); - var @option = (Nino.Serialization.CompressOption)ILRuntime.CLR.Utils.Extensions.CheckCLRTypes( - typeof(Nino.Serialization.CompressOption), - ILRuntime.Runtime.Stack.StackObject.ToObject(ptrOfThisMethod, domain, mStack), - (ILRuntime.CLR.Utils.Extensions.TypeFlags)20); - intp.Free(ptrOfThisMethod); - - //获取泛型参数的实际类型 - var genericArguments = method.GenericArguments; - var t = genericArguments[0]; - ptrOfThisMethod = ILRuntime.Runtime.Intepreter.ILIntepreter.Minus(esp, 2); - var val = ILRuntime.CLR.Utils.Extensions.CheckCLRTypes( - t.ReflectionType, - ILRuntime.Runtime.Stack.StackObject.ToObject(ptrOfThisMethod, domain, mStack), - 0); - intp.Free(ptrOfThisMethod); - - var resultOfThisMethod = - Nino.Serialization.Serializer.Serialize(val, option); - - return ILRuntime.Runtime.Intepreter.ILIntepreter.PushObject(ret, mStack, resultOfThisMethod); - } - - /// - /// Resolve real type - /// - /// - /// - public static Type ResolveRealType(this Type type) - { - if (type is ILRuntime.Reflection.ILRuntimeWrapperType wt) - { - return wt.RealType; - } - - return type; - } - } - - public class SerializationHelper1ILTypeInstanceAdapter : ILRuntime.Runtime.Enviorment.CrossBindingAdaptor - { - public override Type BaseCLRType - { - get { return typeof(Nino.Serialization.NinoWrapperBase); } - } - - public override Type AdaptorType - { - get { return typeof(Adapter); } - } - - public override object CreateCLRInstance(ILRuntime.Runtime.Enviorment.AppDomain appdomain, - ILRuntime.Runtime.Intepreter.ILTypeInstance instance) - { - return new Adapter(appdomain, instance); - } - - public class Adapter : Nino.Serialization.NinoWrapperBase, - ILRuntime.Runtime.Enviorment.CrossBindingAdaptorType - { - bool isInvokingToString; - ILRuntime.Runtime.Intepreter.ILTypeInstance instance; - ILRuntime.Runtime.Enviorment.AppDomain appdomain; - - private ILRuntime.CLR.Method.IMethod write; - private ILRuntime.CLR.Method.IMethod read; - - public Adapter() - { - - } - - public Adapter(ILRuntime.Runtime.Enviorment.AppDomain appdomain, - ILRuntime.Runtime.Intepreter.ILTypeInstance instance) - { - this.appdomain = appdomain; - this.instance = instance; - } - - public ILRuntime.Runtime.Intepreter.ILTypeInstance ILInstance - { - get { return instance; } - } - - public override void Serialize(ILRuntime.Runtime.Intepreter.ILTypeInstance val, - Nino.Serialization.Writer writer) - { - if (write == null) - { - string Name = nameof(Serialize); - var ilType = instance.Type; - write = ilType.GetMethod(Name, 2); - } - - using (var ctx = appdomain.BeginInvoke(write)) - { - ctx.PushObject(instance); - ctx.PushObject(val); - ctx.PushObject(writer); - ctx.Invoke(); - } - } - - public override ILRuntime.Runtime.Intepreter.ILTypeInstance Deserialize(Nino.Serialization.Reader reader) - { - if (read == null) - { - string Name = nameof(Deserialize); - var ilType = instance.Type; - read = ilType.GetMethod(Name, 1); - } - - using (var ctx = appdomain.BeginInvoke(read)) - { - ctx.PushObject(instance); - ctx.PushObject(reader); - ctx.Invoke(); - return ctx.ReadObject(); - } - } - - public override string ToString() - { - ILRuntime.CLR.Method.IMethod m = appdomain.ObjectType.GetMethod("ToString", 0); - m = instance.Type.GetVirtualMethod(m); - if (m == null || m is ILRuntime.CLR.Method.ILMethod) - { - if (!isInvokingToString) - { - isInvokingToString = true; - string res = instance.ToString(); - isInvokingToString = false; - return res; - } - else - return instance.Type.FullName; - } - else - return instance.Type.FullName; - } - } - } -#endif -} \ 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 fa1a1fc..03f8fac 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Reader.Generic.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Reader.Generic.cs @@ -84,6 +84,27 @@ public T Read(int len) where T : unmanaged return ret; } + /// + /// Read unmanaged type + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + // ReSharper disable UnusedMember.Local + internal void ReadAsUnmanaged(ref T val, int len) + // ReSharper restore UnusedMember.Local + { + if (EndOfReader) + { + return; + } + + Span span = buffer.AsSpan(position, len); + var first = span[0]; + val = Unsafe.ReadUnaligned(ref first); + position += len; + } + /// /// Read unmanaged type /// @@ -103,6 +124,197 @@ public void Read(ref T val, int len) where T : unmanaged position += len; } + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2) where T1 : unmanaged where T2 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + } + + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3) + where T1 : unmanaged where T2 : unmanaged where T3 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + val3 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T3))); + position += len3; + } + + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3, + ref T4 val4, int len4) where T1 : unmanaged where T2 : unmanaged where T3 : unmanaged where T4 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + val3 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T3))); + position += len3; + val4 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T4))); + position += len4; + } + + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3, + ref T4 val4, int len4, ref T5 val5, int len5) where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + val3 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T3))); + position += len3; + val4 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T4))); + position += len4; + val5 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T5))); + position += len5; + } + + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3, + ref T4 val4, int len4, ref T5 val5, int len5, ref T6 val6, int len6) where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + where T6 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + val3 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T3))); + position += len3; + val4 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T4))); + position += len4; + val5 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T5))); + position += len5; + val6 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T6))); + position += len6; + } + + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, + int len3, ref T4 val4, int len4, ref T5 val5, int len5, ref T6 val6, int len6, ref T7 val7, int len7) + where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + where T6 : unmanaged + where T7 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + val3 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T3))); + position += len3; + val4 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T4))); + position += len4; + val5 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T5))); + position += len5; + val6 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T6))); + position += len6; + val7 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T7))); + position += len7; + } + + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, + int len3, ref T4 val4, int len4, ref T5 val5, int len5, ref T6 val6, int len6, ref T7 val7, int len7, + ref T8 val8, int len8) where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + where T6 : unmanaged + where T7 : unmanaged + where T8 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + val3 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T3))); + position += len3; + val4 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T4))); + position += len4; + val5 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T5))); + position += len5; + val6 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T6))); + position += len6; + val7 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T7))); + position += len7; + val8 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T8))); + position += len8; + } + /// /// Read nullable /// diff --git a/Nino_Unity/Assets/Nino/Serialization/Reader.cs b/Nino_Unity/Assets/Nino/Serialization/Reader.cs index 5109e8b..a22f87f 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Reader.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Reader.cs @@ -360,12 +360,7 @@ public Array ReadArray(Type type) while (i < len) { var obj = ReadCommonVal(elemType); -#if ILRuntime - arr.SetValue(ILRuntime.CLR.Utils.Extensions.CheckCLRTypes(elemType, obj), i++); - continue; -#else arr.SetValue(obj, i++); -#endif } return arr; @@ -392,17 +387,6 @@ public IList ReadList(Type type) //check null if (!ReadBool()) return null; var elemType = type.GenericTypeArguments[0]; -#if ILRuntime - if (type is ILRuntime.Reflection.ILRuntimeWrapperType wt) - { - elemType = wt?.CLRType.GenericArguments[0].Value.ReflectionType; - } - - if(!elemType.IsGenericType) - { - elemType = elemType.ResolveRealType(); - } -#endif //read len int len = ReadLength(); @@ -413,12 +397,7 @@ public IList ReadList(Type type) while (i++ < len) { var obj = ReadCommonVal(elemType); -#if ILRuntime - arr?.Add(ILRuntime.CLR.Utils.Extensions.CheckCLRTypes(elemType, obj)); - continue; -#else arr?.Add(obj); -#endif } return arr; @@ -438,29 +417,7 @@ public IDictionary ReadDictionary(Type type) //parse dict type var args = type.GetGenericArguments(); Type keyType = args[0]; -#if ILRuntime - if (type is ILRuntime.Reflection.ILRuntimeWrapperType wt) - { - keyType = wt?.CLRType.GenericArguments[0].Value.ReflectionType; - } - - if(!keyType.IsGenericType) - { - keyType = keyType.ResolveRealType(); - } -#endif Type valueType = args[1]; -#if ILRuntime - if (type is ILRuntime.Reflection.ILRuntimeWrapperType wt2) - { - valueType = wt2?.CLRType.GenericArguments[1].Value.ReflectionType; - } - - if(!valueType.IsGenericType) - { - valueType = valueType.ResolveRealType(); - } -#endif var dict = Activator.CreateInstance(type) as IDictionary; @@ -477,13 +434,7 @@ public IDictionary ReadDictionary(Type type) var val = ReadCommonVal(valueType); //add -#if ILRuntime - dict?.Add(ILRuntime.CLR.Utils.Extensions.CheckCLRTypes(keyType, key), - ILRuntime.CLR.Utils.Extensions.CheckCLRTypes(valueType, val)); - continue; -#else dict?.Add(key, val); -#endif } return dict; diff --git a/Nino_Unity/Assets/Nino/Serialization/Serializer.Generic.cs b/Nino_Unity/Assets/Nino/Serialization/Serializer.Generic.cs index 7c60631..65dad70 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Serializer.Generic.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Serializer.Generic.cs @@ -2,6 +2,7 @@ using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace Nino.Serialization { @@ -57,6 +58,27 @@ private static bool TrySerializeEnumType(Type type, ref T value, ref Writer w return true; } + /// + /// Attempt to serialize unmanaged type + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TrySerializeUnmanagedType(Type type, ref T value, ref Writer writer) + { + //enum + if (!TypeModel.IsUnmanaged(type)) + { + return false; + } + + writer.WriteAsUnmanaged(ref value, Marshal.SizeOf()); + return true; + } + /// /// Attempt to serialize code gen type (first time only) /// diff --git a/Nino_Unity/Assets/Nino/Serialization/Serializer.Helper.cs b/Nino_Unity/Assets/Nino/Serialization/Serializer.Helper.cs index 3f64695..ef9f858 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Serializer.Helper.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Serializer.Helper.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Reflection; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using Nino.Shared.Mgr; namespace Nino.Serialization @@ -48,7 +49,7 @@ public static int GetFixedSize() return -1; } - + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void SetFixedSize(int size) { @@ -60,7 +61,7 @@ public static int GetSize(in T[] val = default, Dictionary(in T[] val = default, Dictionary() * length + 1 + 4; + } + if (FixedSizeCache.TryGetValue(type, out var size)) { return 1 + 4 + length * size; @@ -82,7 +88,7 @@ public static int GetSize(in List val = default, Dictionary(in List val = default, Dictionary() * length + 1 + 4; + } + if (FixedSizeCache.TryGetValue(type, out var size)) { return 1 + 4 + length * size; } - + return GetSize(typeof(List), val, members); } @@ -113,6 +124,11 @@ public static int GetSize(in T? val = default, Dictionary } } + if (TypeModel.IsUnmanaged(type)) + { + return Unsafe.SizeOf() + 1; + } + if (FixedSizeCache.TryGetValue(type, out var size)) { return 1 + size; @@ -126,7 +142,7 @@ public static int GetSize(in T val = default, Dictionary var type = typeof(T); int size = 0; if (TypeModel.IsEnum(type)) type = type.GetEnumUnderlyingType(); - + //nullable if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) { @@ -140,7 +156,7 @@ public static int GetSize(in T val = default, Dictionary { return size + size2; } - + if (!WrapperManifest.TryGetWrapper(type, out var wrapper)) { //code generated type @@ -161,13 +177,18 @@ public static int GetSize(in T val = default, Dictionary return size + wrapper.GetSize(val); } + if (TypeModel.IsUnmanaged(type)) + { + return Unsafe.SizeOf(); + } + 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; @@ -207,8 +228,13 @@ public static int GetSize(Type type, object obj, Dictionary return size + wrapper.GetSize(obj); } + if (TypeModel.IsUnmanaged(type)) + { + return Marshal.SizeOf(type); + } + size = 1; //null indicator - + if (type == ConstMgr.ObjectType) { type = obj.GetType(); @@ -377,31 +403,16 @@ public static int GetSize(Type type, object obj, Dictionary } var isFixed = true; - foreach (var member in model.Members) + foreach (var info 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"); - } - + object memberObj = info.GetValue(obj); if (members != null) { - members[member] = memberObj; + members[info.Member] = memberObj; } - size += GetSize(memberType, memberObj); - if (!FixedSizeCache.ContainsKey(memberType)) + size += GetSize(info.Type, memberObj); + if (!FixedSizeCache.ContainsKey(info.Type)) { isFixed = false; } diff --git a/Nino_Unity/Assets/Nino/Serialization/Serializer.cs b/Nino_Unity/Assets/Nino/Serialization/Serializer.cs index 8b6b4a2..5b2f0b7 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Serializer.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Serializer.cs @@ -26,7 +26,13 @@ public static byte[] Serialize(in T val) } byte[] ret = new byte[length]; - Serialize(ret.AsSpan(), in val, fields); + if (val == null) + { + ObjectPool>.Return(fields); + return ret; + } + + Serialize(typeof(T), val, fields, ret.AsSpan(), 0); ObjectPool>.Return(fields); return ret; } @@ -73,6 +79,7 @@ public static byte[] Serialize(object val) ObjectPool>.Return(fields); return ret; } + Serialize(val.GetType(), val, fields, ret.AsSpan(), 0); ObjectPool>.Return(fields); return ret; @@ -96,18 +103,9 @@ public static int Serialize(Span buffer, object val) return Serialize(val.GetType(), val, null, buffer, 0); } - internal static int Serialize(Type type, T value, Dictionary fields ,Span buffer, int pos) + 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) - { - type = ins.Type.ReflectionType; - } - - type = type.ResolveRealType(); -#endif - Writer writer = new Writer(buffer, pos); //null check @@ -136,6 +134,11 @@ internal static int Serialize(Type type, T value, Dictionary(Type type, T value, Dictionary Members; + + public struct NinoMember + { + public MemberInfo Member; + public Type Type; + public Func GetValue; + + public NinoMember(MemberInfo member, Type type, Func getValue) + { + Member = member; + Type = type; + GetValue = getValue; + } + } - public HashSet Members; public bool Valid; public bool IncludeAll; @@ -95,12 +111,6 @@ internal class TypeModel /// internal static TypeCode GetTypeCode(Type type) { -#if ILRuntime - if (IsEnum(type) && type is ILRuntime.Reflection.ILRuntimeType) - { - type = Enum.GetUnderlyingType(type); - } -#endif var hash = type.GetTypeHashCode(); if (TypeCodes.TryGetValue(hash, out var ret)) { @@ -155,10 +165,9 @@ public static bool IsFixedSizeType(Type type) } // otherwise check recursively - foreach (var member in model.Members) + foreach (var info in model.Members) { - var mt = member is FieldInfo fi ? fi.FieldType : ((PropertyInfo)member).PropertyType; - if (!IsFixedSizeType(mt)) + if (!IsFixedSizeType(info.Type)) { ret = false; break; @@ -187,7 +196,8 @@ public static bool IsUnmanaged(Type type) .GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); foreach (var field in fields) { - if (!IsUnmanaged(field.FieldType)) + if (field.GetCustomAttributes(CompilerGeneratedType, true).Length > 0 || + !IsUnmanaged(field.FieldType)) { ret = false; break; @@ -278,7 +288,7 @@ internal static TypeModel CreateModel(Type type) { Valid = true, //fetch members - Members = new HashSet(), + Members = new List(), }; //include all or not @@ -296,6 +306,11 @@ internal static TypeModel CreateModel(Type type) //iterate fields foreach (var f in fs) { + if (f.GetCustomAttributes(CompilerGeneratedType, true).Length > 0) + { + continue; + } + if (model.IncludeAll) { //skip nino ignore @@ -354,7 +369,14 @@ internal static TypeModel CreateModel(Type type) //add members to model foreach (var pair in dict) { - model.Members.Add(pair.Value); + if (pair.Value is FieldInfo fi) + { + model.Members.Add(new NinoMember(fi, fi.FieldType, fi.GetValue)); + } + else if (pair.Value is PropertyInfo pi) + { + model.Members.Add(new NinoMember(pi, pi.PropertyType, pi.GetValue)); + } } //release dict diff --git a/Nino_Unity/Assets/Nino/Serialization/Writer.Generic.cs b/Nino_Unity/Assets/Nino/Serialization/Writer.Generic.cs index 047f17b..5adbdcd 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Writer.Generic.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Writer.Generic.cs @@ -27,6 +27,18 @@ public ref partial struct Writer public void WriteCommonVal(Type type, T val) => Position = Serializer.Serialize(type, val, null, buffer, Position); + /// + /// Write unmanaged type + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void WriteAsUnmanaged(ref T val, int len) + { + Unsafe.WriteUnaligned(ref buffer[Position], val); + Position += len; + } + /// /// Write unmanaged type /// @@ -39,6 +51,163 @@ public void Write(ref T val, int len) where T : unmanaged Position += len; } + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2) + where T1 : unmanaged where T2 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + } + + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3) + where T1 : unmanaged where T2 : unmanaged where T3 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + Unsafe.WriteUnaligned(ref buffer[Position], val3); + Position += len3; + } + + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3, + ref T4 val4, int len4) where T1 : unmanaged where T2 : unmanaged where T3 : unmanaged where T4 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + Unsafe.WriteUnaligned(ref buffer[Position], val3); + Position += len3; + Unsafe.WriteUnaligned(ref buffer[Position], val4); + Position += len4; + } + + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3, + ref T4 val4, int len4, ref T5 val5, int len5) where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + Unsafe.WriteUnaligned(ref buffer[Position], val3); + Position += len3; + Unsafe.WriteUnaligned(ref buffer[Position], val4); + Position += len4; + Unsafe.WriteUnaligned(ref buffer[Position], val5); + Position += len5; + } + + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3, + ref T4 val4, int len4, ref T5 val5, int len5, ref T6 val6, int len6) where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + where T6 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + Unsafe.WriteUnaligned(ref buffer[Position], val3); + Position += len3; + Unsafe.WriteUnaligned(ref buffer[Position], val4); + Position += len4; + Unsafe.WriteUnaligned(ref buffer[Position], val5); + Position += len5; + Unsafe.WriteUnaligned(ref buffer[Position], val6); + Position += len6; + } + + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, + int len3, ref T4 val4, int len4, ref T5 val5, int len5, ref T6 val6, int len6, ref T7 val7, int len7) + where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + where T6 : unmanaged + where T7 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + Unsafe.WriteUnaligned(ref buffer[Position], val3); + Position += len3; + Unsafe.WriteUnaligned(ref buffer[Position], val4); + Position += len4; + Unsafe.WriteUnaligned(ref buffer[Position], val5); + Position += len5; + Unsafe.WriteUnaligned(ref buffer[Position], val6); + Position += len6; + Unsafe.WriteUnaligned(ref buffer[Position], val7); + Position += len7; + } + + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, + int len3, ref T4 val4, int len4, ref T5 val5, int len5, ref T6 val6, int len6, ref T7 val7, int len7, + ref T8 val8, int len8) where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + where T6 : unmanaged + where T7 : unmanaged + where T8 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + Unsafe.WriteUnaligned(ref buffer[Position], val3); + Position += len3; + Unsafe.WriteUnaligned(ref buffer[Position], val4); + Position += len4; + Unsafe.WriteUnaligned(ref buffer[Position], val5); + Position += len5; + Unsafe.WriteUnaligned(ref buffer[Position], val6); + Position += len6; + Unsafe.WriteUnaligned(ref buffer[Position], val7); + Position += len7; + Unsafe.WriteUnaligned(ref buffer[Position], val8); + Position += len8; + } + /// /// Write byte[] /// @@ -171,13 +340,7 @@ public void Write(T[] arr) while (i < len) { var obj = arr[i++]; -#if ILRuntime - var eType = obj is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : obj.GetType(); -#else var eType = obj.GetType(); -#endif WriteCommonVal(eType, obj); } } @@ -228,14 +391,7 @@ public void Write(List lst) //write item foreach (var c in lst) { -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); - WriteCommonVal(eType, c); -#else WriteCommonVal(c); -#endif } } @@ -268,14 +424,7 @@ public void Write(HashSet lst) //write item foreach (var c in lst) { -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); - WriteCommonVal(eType, c); -#else WriteCommonVal(c); -#endif } } @@ -308,14 +457,7 @@ public void Write(Queue lst) //write item foreach (var c in lst) { -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); - WriteCommonVal(eType, c); -#else WriteCommonVal(c); -#endif } } @@ -348,14 +490,7 @@ public void Write(Stack lst) //write item foreach (var c in lst) { -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); - WriteCommonVal(eType, c); -#else WriteCommonVal(c); -#endif } } @@ -392,24 +527,10 @@ public void Write(Dictionary dictionary) foreach (var c in keys) { //write key -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); - WriteCommonVal(eType, c); -#else WriteCommonVal(c); -#endif //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 WriteCommonVal(val); -#endif } } } diff --git a/Nino_Unity/Assets/Nino/Serialization/Writer.cs b/Nino_Unity/Assets/Nino/Serialization/Writer.cs index 20c3b68..3325915 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Writer.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Writer.cs @@ -259,13 +259,7 @@ public void Write(Array arr) while (i < len) { var obj = arr.GetValue(i++); -#if ILRuntime - var eType = obj is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : obj.GetType(); -#else var eType = obj.GetType(); -#endif WriteCommonVal(eType, obj); } } @@ -297,13 +291,7 @@ public void Write(IList arr) //write item foreach (var c in arr) { -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); -#else var eType = c.GetType(); -#endif WriteCommonVal(eType, c); } } @@ -338,23 +326,11 @@ public void Write(IDictionary dictionary) foreach (var c in keys) { //write key -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); -#else var eType = c.GetType(); -#endif WriteCommonVal(eType, c); //write val var val = dictionary[c]; -#if ILRuntime - eType = val is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns2 - ? ilIns2.Type.ReflectionType - : val.GetType(); -#else eType = val.GetType(); -#endif WriteCommonVal(eType, val); } } diff --git a/Nino_Unity/Assets/Nino/Test/BuildTest.cs b/Nino_Unity/Assets/Nino/Test/BuildTest.cs index d09ca22..ed13cd1 100644 --- a/Nino_Unity/Assets/Nino/Test/BuildTest.cs +++ b/Nino_Unity/Assets/Nino/Test/BuildTest.cs @@ -1,4 +1,5 @@ using System; +using System.Buffers; using System.IO; using System.Linq; using UnityEngine; @@ -217,16 +218,24 @@ private void Start() //serialize else { + if(ninoBuffer.Length == 0) + { + ninoBuffer = new byte[Nino.Serialization.Serializer.GetSize(d2)]; + } sw.Reset(); sw.Start(); - ninoBuffer = Nino.Serialization.Serializer.Serialize(d2); + Span arr = stackalloc byte[Nino.Serialization.Serializer.GetSize(d2)]; + Nino.Serialization.Serializer.Serialize(arr, d2); sw.Stop(); + arr.CopyTo(ninoBuffer); var m1 = sw.ElapsedTicks; sw.Reset(); sw.Start(); //as everything are same, buffer has same length - ninoBuffer = Nino.Serialization.Serializer.Serialize(d1); + arr = stackalloc byte[Nino.Serialization.Serializer.GetSize(d1)]; + Nino.Serialization.Serializer.Serialize(arr, d1); sw.Stop(); + arr.CopyTo(ninoBuffer); var m2 = sw.ElapsedTicks; ninoResultText.text = $"Serialized BuildTestDataCodeGen as {ninoBuffer.Length} bytes in {((float)m1 / Stopwatch.Frequency) * 1000} ms,\n" + @@ -501,7 +510,8 @@ private void Start() { sw.Reset(); sw.Start(); - msgPackBuffer = MessagePackSerializer.Serialize(d2); + var lz4Options = MessagePackSerializerOptions.Standard.WithCompression(MessagePackCompression.None); + msgPackBuffer = MessagePackSerializer.Serialize(d2, lz4Options); sw.Stop(); var m1 = sw.ElapsedTicks; diff --git a/Nino_Unity/Assets/Nino/Test/BuildTest2.cs b/Nino_Unity/Assets/Nino/Test/BuildTest2.cs index 962d954..099e8fa 100644 --- a/Nino_Unity/Assets/Nino/Test/BuildTest2.cs +++ b/Nino_Unity/Assets/Nino/Test/BuildTest2.cs @@ -1,4 +1,5 @@ using System; +using System.Buffers; using System.IO; using System.Linq; using UnityEngine; @@ -122,10 +123,17 @@ private void Start() //serialize else { + if(ninoBuffer.Length == 0) + { + ninoBuffer = new byte[Nino.Serialization.Serializer.GetSize(nd)]; + } sw.Reset(); sw.Start(); - ninoBuffer = Nino.Serialization.Serializer.Serialize(nd); + var arr = ArrayPool.Shared.Rent(Nino.Serialization.Serializer.GetSize(nd)); + Nino.Serialization.Serializer.Serialize(arr, nd); sw.Stop(); + Array.Copy(arr, ninoBuffer, ninoBuffer.Length); + ArrayPool.Shared.Return(arr); var m1 = sw.ElapsedTicks; ninoResultText.text = $"Serialized NestedData as {ninoBuffer.Length} bytes in {((float)m1 / Stopwatch.Frequency) * 1000} ms,\n{string.Join(",", ninoBuffer.Take(200))}"; @@ -311,7 +319,9 @@ private void Start() { sw.Reset(); sw.Start(); - msgPackBuffer = MessagePackSerializer.Serialize(nd); + + var lz4Options = MessagePackSerializerOptions.Standard.WithCompression(MessagePackCompression.None); + msgPackBuffer = MessagePackSerializer.Serialize(nd, lz4Options); sw.Stop(); var m1 = sw.ElapsedTicks; diff --git a/Nino_Unity/Assets/Nino/Test/Data.cs b/Nino_Unity/Assets/Nino/Test/Data.cs index 93649d8..706c9da 100644 --- a/Nino_Unity/Assets/Nino/Test/Data.cs +++ b/Nino_Unity/Assets/Nino/Test/Data.cs @@ -144,7 +144,7 @@ public override string ToString() } } - [NinoSerialize] + [NinoSerialize(false)] public partial class CustomTypeTest { [NinoMember(1)] public Vector3 v3; diff --git a/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test11.bytes b/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test11.bytes deleted file mode 100644 index 2b498cd..0000000 Binary files a/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test11.bytes and /dev/null differ diff --git a/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test11.cs b/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test11.cs deleted file mode 100644 index 2d5776a..0000000 --- a/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test11.cs +++ /dev/null @@ -1,31 +0,0 @@ -#if ILRuntime -using System.IO; -using Nino.Shared.Util; -using Nino.Serialization; -using ILRuntime.Runtime.Enviorment; - -// ReSharper disable RedundantTypeArgumentsOfMethod -namespace Nino.Test.Editor.Serialization -{ - public class Test11 - { - private const string SerializationTest11 = "Nino/Test/Serialization/Test11 - ILRuntime"; - -#if UNITY_2017_1_OR_NEWER - [UnityEditor.MenuItem(SerializationTest11, priority=11)] -#endif - public static void Main() - { - var buf = File.ReadAllBytes("Assets/Nino/Test/Editor/Serialization/Test11.bytes"); - AppDomain domain = new AppDomain(); - domain.LoadAssembly(new MemoryStream(buf)); - ILRuntimeResolver.RegisterILRuntimeClrRedirection(domain); - var ret = (byte[])domain.Invoke("Test.Test11", "TestSerialize", null); - Logger.D($"Serialized as {ret.Length} bytes, {string.Join(",",ret)}"); - var dd = (string)domain.Invoke("Test.Test11", "TestDeserialize", null, ret); - Logger.D($"Deserialized as: {dd}"); - } - } -} -// ReSharper restore RedundantTypeArgumentsOfMethod -#endif \ 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 be84ed5..910998f 100644 --- a/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test7.cs +++ b/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test7.cs @@ -6,83 +6,40 @@ // ReSharper disable RedundantTypeArgumentsOfMethod namespace Nino.Test.Editor.Serialization { - public class Vector3Wrapper : NinoWrapperBase + public class CustomTypeTestWrapper : NinoWrapperBase { - public override void Serialize(Vector3 val, ref Writer writer) + public override void Serialize(CustomTypeTest val, ref Writer writer) { - writer.Write(val.x); - writer.Write(val.y); - writer.Write(val.z); + writer.Write(ref val.v3, sizeof(float) * 3); + writer.Write(ref val.m, sizeof(float) * 16); + writer.Write(val.ni); + writer.Write(val.qs); + writer.Write(val.dict); + writer.Write(val.dict2); } - public override Vector3 Deserialize(Reader reader) + public override CustomTypeTest Deserialize(Reader reader) { - return new Vector3(reader.Read(4), reader.Read(4), reader.Read(4)); + var ret = new CustomTypeTest(); + reader.Read(ref ret.v3, sizeof(float) * 3); + reader.Read(ref ret.m, sizeof(float) * 16); + ret.ni = reader.ReadNullable(); + ret.qs = reader.ReadList(); + ret.dict = reader.ReadDictionary(); + ret.dict2 = reader.ReadDictionary(); + return ret; } - public override int GetSize(Vector3 val) + public override int GetSize(CustomTypeTest 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; + int ret = 1; + ret += sizeof(float) * 3; + ret += sizeof(float) * 16; + ret += Serializer.GetSize(val.ni); + ret += Serializer.GetSize(val.qs); + ret += Serializer.GetSize(val.dict); + ret += Serializer.GetSize(val.dict2); + return ret; } } @@ -96,9 +53,7 @@ public class Test7 public static void Main() { //register wrappers - WrapperManifest.AddWrapper(typeof(Vector3), new Vector3Wrapper()); - WrapperManifest.AddWrapper(typeof(Quaternion), new QuaternionWrapper()); - WrapperManifest.AddWrapper(typeof(Matrix4x4), new Matrix4x4Wrapper()); + WrapperManifest.AddWrapper(typeof(CustomTypeTest), new CustomTypeTestWrapper()); //custom type CustomTypeTest c = new CustomTypeTest() { diff --git a/README.md b/README.md index 9206fa5..d8f9dc5 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ Definite useful and high performance modules for C# projects, especially for Uni ``` ```bash - PM> Install-Package Nino.Serialization -Version 1.2.1 + PM> Install-Package Nino.Serialization -Version 1.2.2 ``` - 使用src下的代码(复制进自己项目即可) diff --git a/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_Data_Serialize.cs b/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_Data_Serialize.cs index bf745a2..160f4f9 100644 --- a/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_Data_Serialize.cs +++ b/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_Data_Serialize.cs @@ -28,14 +28,7 @@ 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); + writer.Write(ref value.X, sizeof(System.Int32),ref value.Y, sizeof(System.Int16),ref value.Z, sizeof(System.Int64),ref value.F, sizeof(System.Single),ref value.D, sizeof(System.Decimal),ref value.Db, sizeof(System.Double),ref value.Bo, sizeof(System.Boolean),ref value.En, sizeof(Nino.Benchmark.Models.TestEnum)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -44,14 +37,7 @@ 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); + reader.Read(ref value.X, sizeof(System.Int32),ref value.Y, sizeof(System.Int16),ref value.Z, sizeof(System.Int64),ref value.F, sizeof(System.Single),ref value.D, sizeof(System.Decimal),ref value.Db, sizeof(System.Double),ref value.Bo, sizeof(System.Boolean),ref value.En, sizeof(Nino.Benchmark.Models.TestEnum)); return value; } diff --git a/src/Nino.Serialization/CodeGenerator.cs b/src/Nino.Serialization/CodeGenerator.cs index 1c83bdf..d3ef3e7 100644 --- a/src/Nino.Serialization/CodeGenerator.cs +++ b/src/Nino.Serialization/CodeGenerator.cs @@ -1,12 +1,11 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using Nino.Shared.Mgr; using Nino.Shared.Util; using System.Reflection; -using System.Collections.Generic; -using System.Runtime.CompilerServices; namespace Nino.Serialization { @@ -194,15 +193,60 @@ public override int GetSize({type} value) model = TypeModel.CreateModel(type); } - HashSet members = model.Members; + var members = model.Members; #region serialize //build params StringBuilder sb = new StringBuilder(); - foreach (var member in members) + List unmanagedMembers = new List(); + for (int i = 0; i < members.Count; i++) { - var mt = member is FieldInfo fi ? fi.FieldType : ((PropertyInfo)member).PropertyType; + var info = members[i]; + var member = info.Member; + var mt = info.Type; + + //try optimize + if (TypeModel.IsUnmanaged(mt) && member is FieldInfo) + { + unmanagedMembers.Clear(); + unmanagedMembers.Add(info); + for (int j = i + 1; j < members.Count; j++) + { + var info2 = members[j]; + var member2 = info2.Member; + var mt2 = info2.Type; + if (TypeModel.IsUnmanaged(mt2) && member2 is FieldInfo) + { + unmanagedMembers.Add(info2); + } + else + { + break; + } + } + + i += unmanagedMembers.Count - 1; + //batch write with batch size 8 + while (unmanagedMembers.Count > 0) + { + if (unmanagedMembers.Count <= 8) + { + sb.Append( + $" writer.Write({string.Join(",", unmanagedMembers.Select(x => $"ref value.{x.Member.Name}, sizeof({BeautifulLongTypeName(x.Type)})"))});\n"); + unmanagedMembers.Clear(); + } + else + { + sb.Append( + $" writer.Write({string.Join(",", unmanagedMembers.Take(8).Select(x => $"ref value.{x.Member.Name}, sizeof({BeautifulLongTypeName(x.Type)})"))});\n"); + unmanagedMembers.RemoveRange(0, 8); + } + } + + continue; + } + //enum if (mt.IsEnum) { @@ -219,6 +263,11 @@ public override int GetSize({type} value) { sb.Append($" writer.Write(value.{member.Name});\n"); } + //nullable + else if (mt.IsGenericType && mt.GetGenericTypeDefinition() == ConstMgr.NullableDefType) + { + sb.Append($" writer.Write(value.{member.Name});\n"); + } //basic type else { @@ -241,9 +290,53 @@ public override int GetSize({type} value) #region deserialize sb.Clear(); - foreach (var member in members) + for (int i = 0; i < members.Count; i++) { - var mt = member is FieldInfo fi ? fi.FieldType : ((PropertyInfo)member).PropertyType; + var info = members[i]; + var member = info.Member; + var mt = info.Type; + + //try optimize + if (TypeModel.IsUnmanaged(mt) && member is FieldInfo) + { + unmanagedMembers.Clear(); + unmanagedMembers.Add(info); + for (int j = i + 1; j < members.Count; j++) + { + var info2 = members[j]; + var member2 = info2.Member; + var mt2 = info2.Type; + if (TypeModel.IsUnmanaged(mt2) && member2 is FieldInfo) + { + unmanagedMembers.Add(info2); + } + else + { + break; + } + } + + i += unmanagedMembers.Count - 1; + //batch write with batch size 8 + while (unmanagedMembers.Count > 0) + { + if (unmanagedMembers.Count <= 8) + { + sb.Append( + $" reader.Read({string.Join(",", unmanagedMembers.Select(x => $"ref value.{x.Member.Name}, sizeof({BeautifulLongTypeName(x.Type)})"))});\n"); + unmanagedMembers.Clear(); + } + else + { + sb.Append( + $" reader.Read({string.Join(",", unmanagedMembers.Take(8).Select(x => $"ref value.{x.Member.Name}, sizeof({BeautifulLongTypeName(x.Type)})"))});\n"); + unmanagedMembers.RemoveRange(0, 8); + } + } + + continue; + } + //enum if (mt.IsEnum) { @@ -292,6 +385,15 @@ public override int GetSize({type} value) sb.Append( $" value.{member.Name} = reader.ReadDictionary<{BeautifulLongTypeName(keyType)},{BeautifulLongTypeName(valueType)}>();\n"); } + //nullable + else if (mt.IsGenericType && mt.GetGenericTypeDefinition() == ConstMgr.NullableDefType) + { + var args = mt.GetGenericArguments(); + Type keyType = args[0]; + + sb.Append( + $" value.{member.Name} = reader.ReadNullable<{BeautifulLongTypeName(keyType)}>();\n"); + } //not enum -> basic type else { @@ -315,16 +417,19 @@ public override int GetSize({type} value) sb.Clear(); if (TypeModel.IsFixedSizeType(type)) { - sb.Append($" return Nino.Serialization.Serializer.GetFixedSize<{BeautifulLongTypeName(type)}>();"); + sb.Append( + $" return Nino.Serialization.Serializer.GetFixedSize<{BeautifulLongTypeName(type)}>();"); } else { sb.Append(" int ret = 1;\n"); - foreach (var member in members) + foreach (var info in members) { + var member = info.Member; sb.Append( $" ret += Nino.Serialization.Serializer.GetSize(value.{member.Name});\n"); } + sb.Append(" return ret;"); } @@ -339,13 +444,15 @@ public override int GetSize({type} value) if (TypeModel.IsFixedSizeType(type)) { sb.Append(" int ret = 1;\n"); - foreach (var member in members) + foreach (var info in members) { - var mt = member is FieldInfo fi ? fi.FieldType : ((PropertyInfo)member).PropertyType; + var mt = info.Type; sb.Append( $" ret += sizeof({BeautifulLongTypeName(mt)});\n"); } - sb.Append($" Nino.Serialization.Serializer.SetFixedSize<{BeautifulLongTypeName(type)}>(ret);"); + + sb.Append( + $" Nino.Serialization.Serializer.SetFixedSize<{BeautifulLongTypeName(type)}>(ret);"); } //replace template fields @@ -517,6 +624,14 @@ private static string GetSerializeBasicTypeStatement(Type mt, string val, bool i return builder.ToString(); } + if (mt.IsGenericType && mt.GetGenericTypeDefinition() == ConstMgr.NullableDefType) + { + StringBuilder builder = new StringBuilder(); + builder.Append(space).Append(Repeat(" ", indent)) + .Append($"writer.Write({val});\n"); + return builder.ToString(); + } + return $"writer.WriteCommonVal<{BeautifulLongTypeName(mt)}>({val})"; } } diff --git a/src/Nino.Serialization/Deserializer.cs b/src/Nino.Serialization/Deserializer.cs index 8273981..9c8fa41 100644 --- a/src/Nino.Serialization/Deserializer.cs +++ b/src/Nino.Serialization/Deserializer.cs @@ -92,12 +92,24 @@ internal static T Deserialize(Span data, Reader reader, return ret; } + //enum + if (TryDeserializeEnum(type, reader, returnDispose, out var e)) + { + return e; + } + //code generated type if (TryDeserializeCodeGenType(type, reader, false, returnDispose, out ret)) { return ret; } + //unmanaged type + if (TryDeserializeUnmanagedType(type, reader, returnDispose, out var un)) + { + return un; + } + /* * GC DESERIALIZATION WHILE T IS STRUCT */ @@ -148,10 +160,6 @@ internal static object Deserialize(Type type, object val, Span data, Reade } } -#if ILRuntime - type = type.ResolveRealType(); -#endif - //basic type if (TryDeserializeWrapperType(type, reader, true, returnDispose, out object basicObj)) { @@ -163,13 +171,19 @@ internal static object Deserialize(Type type, object val, Span data, Reade { return e; } - + //code generated type if (TryDeserializeCodeGenType(type, reader, true, returnDispose, out object codeGenRet)) { return codeGenRet; } + //unmanaged type + if (TryDeserializeUnmanagedType(type, reader, returnDispose, out var un)) + { + return un; + } + /* * CUSTOM STRUCT/CLASS SERIALIZATION */ @@ -181,11 +195,7 @@ internal static object Deserialize(Type type, object val, Span data, Reade //create type if (val == null || val == ConstMgr.Null) { -#if ILRuntime - val = ILRuntimeResolver.CreateInstance(type); -#else val = Activator.CreateInstance(type); -#endif } //Get Attribute that indicates a class/struct to be serialized @@ -204,7 +214,7 @@ internal static object Deserialize(Type type, object val, Span data, Reade } //start Deserialize - foreach (var member in model.Members) + foreach (var info in model.Members) { //if end, skip if (reader.EndOfReader) @@ -212,10 +222,10 @@ internal static object Deserialize(Type type, object val, Span data, Reade break; } - type = member is FieldInfo fi ? fi.FieldType : ((PropertyInfo)member).PropertyType; + type = info.Type; //read basic values - SetMember(member, val, Deserialize(type, ConstMgr.Null, Span.Empty, reader, false)); + SetMember(info.Member, val, Deserialize(type, ConstMgr.Null, Span.Empty, reader, false)); } if (returnDispose) @@ -384,6 +394,33 @@ private static bool TryDeserializeDict(Type type, Type genericDefType, Reader re return false; } + /// + /// Try deserialize enum + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryDeserializeEnum(Type type, Reader reader, + [MarshalAs(UnmanagedType.U1)] bool returnDispose, out T obj) + { + obj = default; + if (TypeModel.IsEnum(type)) + { + reader.ReadEnum(ref obj); + if (returnDispose) + { + ObjectPool.Return(reader); + } + + return true; + } + + return false; + } + /// /// Try deserialize enum /// @@ -400,16 +437,6 @@ private static bool TryDeserializeEnum(Type type, Reader reader, { var underlyingType = Enum.GetUnderlyingType(type); var ret = reader.ReadEnum(underlyingType); -#if ILRuntime - if (type is ILRuntime.Reflection.ILRuntimeType) - { - if (underlyingType == ConstMgr.LongType - || underlyingType == ConstMgr.UIntType - || underlyingType == ConstMgr.ULongType) - obj = unchecked((long)ret); - obj = unchecked((int)ret); - } -#endif obj = Enum.ToObject(type, ret); if (returnDispose) { @@ -423,6 +450,58 @@ private static bool TryDeserializeEnum(Type type, Reader reader, return false; } + /// + /// Try deserialize enum + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryDeserializeUnmanagedType(Type type, Reader reader, + [MarshalAs(UnmanagedType.U1)] bool returnDispose, out T obj) + { + obj = default; + if (TypeModel.IsUnmanaged(type)) + { + reader.ReadAsUnmanaged(ref obj, Marshal.SizeOf(type)); + if (returnDispose) + { + ObjectPool.Return(reader); + } + return true; + } + + return false; + } + + /// + /// Try deserialize enum + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryDeserializeUnmanagedType(Type type, Reader reader, + [MarshalAs(UnmanagedType.U1)] bool returnDispose, out object obj) + { + obj = default; + if (TypeModel.IsUnmanaged(type)) + { + reader.ReadAsUnmanaged(ref obj, Marshal.SizeOf(type)); + if (returnDispose) + { + ObjectPool.Return(reader); + } + return true; + } + + return false; + } + /// /// Check for null /// diff --git a/src/Nino.Serialization/ILRuntimeResolver.cs b/src/Nino.Serialization/ILRuntimeResolver.cs deleted file mode 100644 index e3c564e..0000000 --- a/src/Nino.Serialization/ILRuntimeResolver.cs +++ /dev/null @@ -1,365 +0,0 @@ -using System; -using System.Text; -using System.Linq; -using Nino.Shared.Mgr; -using System.Reflection; -using System.Collections.Generic; -#if ILRuntime -#if DEBUG && !DISABLE_ILRUNTIME_DEBUG -using AutoList = System.Collections.Generic.List; -#else -using AutoList = ILRuntime.Other.UncheckedList; -#endif -#endif - -// ReSharper disable CognitiveComplexity -// ReSharper disable RedundantNameQualifier -// ReSharper disable RedundantExplicitArrayCreation - -namespace Nino.Serialization -{ -#if ILRuntime - /// - /// ILRuntime helper - /// - public static class ILRuntimeResolver - { - internal static ILRuntime.Runtime.Enviorment.AppDomain appDomain; - - private static readonly Dictionary IlRuntimeTypes = new Dictionary(); - - /// - /// Get ILType - /// - /// - /// - public static Type FindType(string metaName) - { - IlRuntimeTypes.TryGetValue(metaName, out Type type); - return type; - } - - /// - /// Create ILTypeInstance - /// - /// - /// - public static object CreateInstance(Type type) - { - if (appDomain != null) - { - string typeName = type.FullName; - if (FindType(typeName) != null) - { - return appDomain.Instantiate(typeName); - } - - if (typeName != null && appDomain.LoadedTypes.ContainsKey(typeName)) - { - IlRuntimeTypes[typeName] = type; - return appDomain.Instantiate(typeName); - } - } - - return Activator.CreateInstance(type); - } - - /// - /// Reg ILRuntime - /// - /// - public static unsafe void RegisterILRuntimeClrRedirection(ILRuntime.Runtime.Enviorment.AppDomain domain) - { - appDomain = domain; - //cache types - IlRuntimeTypes.Clear(); - var allTypes = domain.LoadedTypes.Values.Select(x => x.ReflectionType).ToArray(); - foreach (var t in allTypes) - { - if (t.FullName != null) - { - IlRuntimeTypes[t.FullName] = t; - TypeModel.AllTypes[t.GetHashCode()] = t; - } - } - - try - { - appDomain.RegisterCrossBindingAdaptor(new SerializationHelper1ILTypeInstanceAdapter()); - } - catch - { - //ignore - } - - //reg redirections - MethodBase method; - var type = typeof(Nino.Serialization.Serializer); - var genericMethods = new Dictionary>(); - List lst; - foreach (var m in type.GetMethods()) - { - if (m.IsGenericMethodDefinition) - { - if (!genericMethods.TryGetValue(m.Name, out lst)) - { - lst = new List(); - genericMethods[m.Name] = lst; - } - - lst.Add(m); - } - } - - var args = new Type[] { typeof(ILRuntime.Runtime.Intepreter.ILTypeInstance) }; - var ps = new Type[] { args[0], typeof(Nino.Serialization.CompressOption) }; - if (genericMethods.TryGetValue("Serialize", out lst)) - { - foreach (var m in lst) - { - if (ILRuntime.Runtime.Extensions.MatchGenericParameters(m, args, typeof(System.Byte[]), - ps)) - { - method = m.MakeGenericMethod(args); - appDomain.RegisterCLRMethodRedirection(method, Serialize_0); - - break; - } - } - } - - type = typeof(Nino.Serialization.Deserializer); - genericMethods.Clear(); - lst?.Clear(); - foreach (var m in type.GetMethods()) - { - if (m.IsGenericMethodDefinition) - { - if (!genericMethods.TryGetValue(m.Name, out lst)) - { - lst = new List(); - genericMethods[m.Name] = lst; - } - - lst.Add(m); - } - } - - //Deserialize - if (genericMethods.TryGetValue("Deserialize", out lst)) - { - foreach (var m in lst) - { - appDomain.RegisterCLRMethodRedirection(m, Deserialize_0); - } - } - } - - /// - /// Deserialize reg - /// - /// - /// - /// - /// - /// - /// - private static unsafe ILRuntime.Runtime.Stack.StackObject* Deserialize_0( - ILRuntime.Runtime.Intepreter.ILIntepreter intp, ILRuntime.Runtime.Stack.StackObject* esp, - AutoList mStack, - ILRuntime.CLR.Method.CLRMethod method, bool isNewObj) - { - var domain = intp.AppDomain; - var ret = ILRuntime.Runtime.Intepreter.ILIntepreter.Minus(esp, 2); - - var ptrOfThisMethod = ILRuntime.Runtime.Intepreter.ILIntepreter.Minus(esp, 1); - var @option = (Nino.Serialization.CompressOption)ILRuntime.CLR.Utils.Extensions.CheckCLRTypes( - typeof(Nino.Serialization.CompressOption), - ILRuntime.Runtime.Stack.StackObject.ToObject(ptrOfThisMethod, domain, mStack), - (ILRuntime.CLR.Utils.Extensions.TypeFlags)20); - intp.Free(ptrOfThisMethod); - - ptrOfThisMethod = ILRuntime.Runtime.Intepreter.ILIntepreter.Minus(esp, 2); - var @data = ILRuntime.Runtime.Stack.StackObject.ToObject(ptrOfThisMethod, domain, mStack); - intp.Free(ptrOfThisMethod); - - //获取泛型参数的实际类型 - var genericArguments = method.GenericArguments; - var t = genericArguments[0]; - - object resultOfThisMethod = null; - if (@data is byte[] buf) - { - resultOfThisMethod = - Nino.Serialization.Deserializer.Deserialize(t.ReflectionType, buf, option); - } - else if (@data is ArraySegment seg) - { - resultOfThisMethod = - Nino.Serialization.Deserializer.Deserialize(t.ReflectionType, seg, option); - } - - return ILRuntime.Runtime.Intepreter.ILIntepreter.PushObject(ret, mStack, resultOfThisMethod); - } - - /// - /// Serialize reg - /// - /// - /// - /// - /// - /// - /// - private static unsafe ILRuntime.Runtime.Stack.StackObject* Serialize_0( - ILRuntime.Runtime.Intepreter.ILIntepreter intp, ILRuntime.Runtime.Stack.StackObject* esp, - AutoList mStack, - ILRuntime.CLR.Method.CLRMethod method, bool isNewObj) - { - var domain = intp.AppDomain; - var ret = ILRuntime.Runtime.Intepreter.ILIntepreter.Minus(esp, 2); - - var ptrOfThisMethod = ILRuntime.Runtime.Intepreter.ILIntepreter.Minus(esp, 1); - var @option = (Nino.Serialization.CompressOption)ILRuntime.CLR.Utils.Extensions.CheckCLRTypes( - typeof(Nino.Serialization.CompressOption), - ILRuntime.Runtime.Stack.StackObject.ToObject(ptrOfThisMethod, domain, mStack), - (ILRuntime.CLR.Utils.Extensions.TypeFlags)20); - intp.Free(ptrOfThisMethod); - - //获取泛型参数的实际类型 - var genericArguments = method.GenericArguments; - var t = genericArguments[0]; - ptrOfThisMethod = ILRuntime.Runtime.Intepreter.ILIntepreter.Minus(esp, 2); - var val = ILRuntime.CLR.Utils.Extensions.CheckCLRTypes( - t.ReflectionType, - ILRuntime.Runtime.Stack.StackObject.ToObject(ptrOfThisMethod, domain, mStack), - 0); - intp.Free(ptrOfThisMethod); - - var resultOfThisMethod = - Nino.Serialization.Serializer.Serialize(val, option); - - return ILRuntime.Runtime.Intepreter.ILIntepreter.PushObject(ret, mStack, resultOfThisMethod); - } - - /// - /// Resolve real type - /// - /// - /// - public static Type ResolveRealType(this Type type) - { - if (type is ILRuntime.Reflection.ILRuntimeWrapperType wt) - { - return wt.RealType; - } - - return type; - } - } - - public class SerializationHelper1ILTypeInstanceAdapter : ILRuntime.Runtime.Enviorment.CrossBindingAdaptor - { - public override Type BaseCLRType - { - get { return typeof(Nino.Serialization.NinoWrapperBase); } - } - - public override Type AdaptorType - { - get { return typeof(Adapter); } - } - - public override object CreateCLRInstance(ILRuntime.Runtime.Enviorment.AppDomain appdomain, - ILRuntime.Runtime.Intepreter.ILTypeInstance instance) - { - return new Adapter(appdomain, instance); - } - - public class Adapter : Nino.Serialization.NinoWrapperBase, - ILRuntime.Runtime.Enviorment.CrossBindingAdaptorType - { - bool isInvokingToString; - ILRuntime.Runtime.Intepreter.ILTypeInstance instance; - ILRuntime.Runtime.Enviorment.AppDomain appdomain; - - private ILRuntime.CLR.Method.IMethod write; - private ILRuntime.CLR.Method.IMethod read; - - public Adapter() - { - - } - - public Adapter(ILRuntime.Runtime.Enviorment.AppDomain appdomain, - ILRuntime.Runtime.Intepreter.ILTypeInstance instance) - { - this.appdomain = appdomain; - this.instance = instance; - } - - public ILRuntime.Runtime.Intepreter.ILTypeInstance ILInstance - { - get { return instance; } - } - - public override void Serialize(ILRuntime.Runtime.Intepreter.ILTypeInstance val, - Nino.Serialization.Writer writer) - { - if (write == null) - { - string Name = nameof(Serialize); - var ilType = instance.Type; - write = ilType.GetMethod(Name, 2); - } - - using (var ctx = appdomain.BeginInvoke(write)) - { - ctx.PushObject(instance); - ctx.PushObject(val); - ctx.PushObject(writer); - ctx.Invoke(); - } - } - - public override ILRuntime.Runtime.Intepreter.ILTypeInstance Deserialize(Nino.Serialization.Reader reader) - { - if (read == null) - { - string Name = nameof(Deserialize); - var ilType = instance.Type; - read = ilType.GetMethod(Name, 1); - } - - using (var ctx = appdomain.BeginInvoke(read)) - { - ctx.PushObject(instance); - ctx.PushObject(reader); - ctx.Invoke(); - return ctx.ReadObject(); - } - } - - public override string ToString() - { - ILRuntime.CLR.Method.IMethod m = appdomain.ObjectType.GetMethod("ToString", 0); - m = instance.Type.GetVirtualMethod(m); - if (m == null || m is ILRuntime.CLR.Method.ILMethod) - { - if (!isInvokingToString) - { - isInvokingToString = true; - string res = instance.ToString(); - isInvokingToString = false; - return res; - } - else - return instance.Type.FullName; - } - else - return instance.Type.FullName; - } - } - } -#endif -} \ No newline at end of file diff --git a/src/Nino.Serialization/Nino.Serialization.csproj b/src/Nino.Serialization/Nino.Serialization.csproj index 60de09d..a4f4476 100644 --- a/src/Nino.Serialization/Nino.Serialization.csproj +++ b/src/Nino.Serialization/Nino.Serialization.csproj @@ -18,10 +18,13 @@ https://github.com/JasonXuDeveloper/Nino en-001 true - 1.2.1 + 1.2.2 true - Nino.Serialization v1.2.1 -- [optimization] better generator and better size computation + Nino.Serialization v1.2.2 +- [optimization] better generator and better size computation +- [optimization] faster serialization/deserialization +- [optimization] lowerge +- [remove] no longer support ILRuntime git diff --git a/src/Nino.Serialization/Reader.Generic.cs b/src/Nino.Serialization/Reader.Generic.cs index fa1a1fc..03f8fac 100644 --- a/src/Nino.Serialization/Reader.Generic.cs +++ b/src/Nino.Serialization/Reader.Generic.cs @@ -84,6 +84,27 @@ public T Read(int len) where T : unmanaged return ret; } + /// + /// Read unmanaged type + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + // ReSharper disable UnusedMember.Local + internal void ReadAsUnmanaged(ref T val, int len) + // ReSharper restore UnusedMember.Local + { + if (EndOfReader) + { + return; + } + + Span span = buffer.AsSpan(position, len); + var first = span[0]; + val = Unsafe.ReadUnaligned(ref first); + position += len; + } + /// /// Read unmanaged type /// @@ -103,6 +124,197 @@ public void Read(ref T val, int len) where T : unmanaged position += len; } + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2) where T1 : unmanaged where T2 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + } + + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3) + where T1 : unmanaged where T2 : unmanaged where T3 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + val3 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T3))); + position += len3; + } + + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3, + ref T4 val4, int len4) where T1 : unmanaged where T2 : unmanaged where T3 : unmanaged where T4 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + val3 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T3))); + position += len3; + val4 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T4))); + position += len4; + } + + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3, + ref T4 val4, int len4, ref T5 val5, int len5) where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + val3 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T3))); + position += len3; + val4 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T4))); + position += len4; + val5 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T5))); + position += len5; + } + + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3, + ref T4 val4, int len4, ref T5 val5, int len5, ref T6 val6, int len6) where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + where T6 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + val3 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T3))); + position += len3; + val4 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T4))); + position += len4; + val5 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T5))); + position += len5; + val6 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T6))); + position += len6; + } + + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, + int len3, ref T4 val4, int len4, ref T5 val5, int len5, ref T6 val6, int len6, ref T7 val7, int len7) + where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + where T6 : unmanaged + where T7 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + val3 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T3))); + position += len3; + val4 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T4))); + position += len4; + val5 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T5))); + position += len5; + val6 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T6))); + position += len6; + val7 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T7))); + position += len7; + } + + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, + int len3, ref T4 val4, int len4, ref T5 val5, int len5, ref T6 val6, int len6, ref T7 val7, int len7, + ref T8 val8, int len8) where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + where T6 : unmanaged + where T7 : unmanaged + where T8 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + val3 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T3))); + position += len3; + val4 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T4))); + position += len4; + val5 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T5))); + position += len5; + val6 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T6))); + position += len6; + val7 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T7))); + position += len7; + val8 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T8))); + position += len8; + } + /// /// Read nullable /// diff --git a/src/Nino.Serialization/Reader.cs b/src/Nino.Serialization/Reader.cs index 5109e8b..a22f87f 100644 --- a/src/Nino.Serialization/Reader.cs +++ b/src/Nino.Serialization/Reader.cs @@ -360,12 +360,7 @@ public Array ReadArray(Type type) while (i < len) { var obj = ReadCommonVal(elemType); -#if ILRuntime - arr.SetValue(ILRuntime.CLR.Utils.Extensions.CheckCLRTypes(elemType, obj), i++); - continue; -#else arr.SetValue(obj, i++); -#endif } return arr; @@ -392,17 +387,6 @@ public IList ReadList(Type type) //check null if (!ReadBool()) return null; var elemType = type.GenericTypeArguments[0]; -#if ILRuntime - if (type is ILRuntime.Reflection.ILRuntimeWrapperType wt) - { - elemType = wt?.CLRType.GenericArguments[0].Value.ReflectionType; - } - - if(!elemType.IsGenericType) - { - elemType = elemType.ResolveRealType(); - } -#endif //read len int len = ReadLength(); @@ -413,12 +397,7 @@ public IList ReadList(Type type) while (i++ < len) { var obj = ReadCommonVal(elemType); -#if ILRuntime - arr?.Add(ILRuntime.CLR.Utils.Extensions.CheckCLRTypes(elemType, obj)); - continue; -#else arr?.Add(obj); -#endif } return arr; @@ -438,29 +417,7 @@ public IDictionary ReadDictionary(Type type) //parse dict type var args = type.GetGenericArguments(); Type keyType = args[0]; -#if ILRuntime - if (type is ILRuntime.Reflection.ILRuntimeWrapperType wt) - { - keyType = wt?.CLRType.GenericArguments[0].Value.ReflectionType; - } - - if(!keyType.IsGenericType) - { - keyType = keyType.ResolveRealType(); - } -#endif Type valueType = args[1]; -#if ILRuntime - if (type is ILRuntime.Reflection.ILRuntimeWrapperType wt2) - { - valueType = wt2?.CLRType.GenericArguments[1].Value.ReflectionType; - } - - if(!valueType.IsGenericType) - { - valueType = valueType.ResolveRealType(); - } -#endif var dict = Activator.CreateInstance(type) as IDictionary; @@ -477,13 +434,7 @@ public IDictionary ReadDictionary(Type type) var val = ReadCommonVal(valueType); //add -#if ILRuntime - dict?.Add(ILRuntime.CLR.Utils.Extensions.CheckCLRTypes(keyType, key), - ILRuntime.CLR.Utils.Extensions.CheckCLRTypes(valueType, val)); - continue; -#else dict?.Add(key, val); -#endif } return dict; diff --git a/src/Nino.Serialization/Serializer.Generic.cs b/src/Nino.Serialization/Serializer.Generic.cs index 7c60631..65dad70 100644 --- a/src/Nino.Serialization/Serializer.Generic.cs +++ b/src/Nino.Serialization/Serializer.Generic.cs @@ -2,6 +2,7 @@ using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace Nino.Serialization { @@ -57,6 +58,27 @@ private static bool TrySerializeEnumType(Type type, ref T value, ref Writer w return true; } + /// + /// Attempt to serialize unmanaged type + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TrySerializeUnmanagedType(Type type, ref T value, ref Writer writer) + { + //enum + if (!TypeModel.IsUnmanaged(type)) + { + return false; + } + + writer.WriteAsUnmanaged(ref value, Marshal.SizeOf()); + return true; + } + /// /// Attempt to serialize code gen type (first time only) /// diff --git a/src/Nino.Serialization/Serializer.Helper.cs b/src/Nino.Serialization/Serializer.Helper.cs index 3f64695..ef9f858 100644 --- a/src/Nino.Serialization/Serializer.Helper.cs +++ b/src/Nino.Serialization/Serializer.Helper.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Reflection; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using Nino.Shared.Mgr; namespace Nino.Serialization @@ -48,7 +49,7 @@ public static int GetFixedSize() return -1; } - + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void SetFixedSize(int size) { @@ -60,7 +61,7 @@ public static int GetSize(in T[] val = default, Dictionary(in T[] val = default, Dictionary() * length + 1 + 4; + } + if (FixedSizeCache.TryGetValue(type, out var size)) { return 1 + 4 + length * size; @@ -82,7 +88,7 @@ public static int GetSize(in List val = default, Dictionary(in List val = default, Dictionary() * length + 1 + 4; + } + if (FixedSizeCache.TryGetValue(type, out var size)) { return 1 + 4 + length * size; } - + return GetSize(typeof(List), val, members); } @@ -113,6 +124,11 @@ public static int GetSize(in T? val = default, Dictionary } } + if (TypeModel.IsUnmanaged(type)) + { + return Unsafe.SizeOf() + 1; + } + if (FixedSizeCache.TryGetValue(type, out var size)) { return 1 + size; @@ -126,7 +142,7 @@ public static int GetSize(in T val = default, Dictionary var type = typeof(T); int size = 0; if (TypeModel.IsEnum(type)) type = type.GetEnumUnderlyingType(); - + //nullable if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) { @@ -140,7 +156,7 @@ public static int GetSize(in T val = default, Dictionary { return size + size2; } - + if (!WrapperManifest.TryGetWrapper(type, out var wrapper)) { //code generated type @@ -161,13 +177,18 @@ public static int GetSize(in T val = default, Dictionary return size + wrapper.GetSize(val); } + if (TypeModel.IsUnmanaged(type)) + { + return Unsafe.SizeOf(); + } + 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; @@ -207,8 +228,13 @@ public static int GetSize(Type type, object obj, Dictionary return size + wrapper.GetSize(obj); } + if (TypeModel.IsUnmanaged(type)) + { + return Marshal.SizeOf(type); + } + size = 1; //null indicator - + if (type == ConstMgr.ObjectType) { type = obj.GetType(); @@ -377,31 +403,16 @@ public static int GetSize(Type type, object obj, Dictionary } var isFixed = true; - foreach (var member in model.Members) + foreach (var info 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"); - } - + object memberObj = info.GetValue(obj); if (members != null) { - members[member] = memberObj; + members[info.Member] = memberObj; } - size += GetSize(memberType, memberObj); - if (!FixedSizeCache.ContainsKey(memberType)) + size += GetSize(info.Type, memberObj); + if (!FixedSizeCache.ContainsKey(info.Type)) { isFixed = false; } diff --git a/src/Nino.Serialization/Serializer.cs b/src/Nino.Serialization/Serializer.cs index 8b6b4a2..5b2f0b7 100644 --- a/src/Nino.Serialization/Serializer.cs +++ b/src/Nino.Serialization/Serializer.cs @@ -26,7 +26,13 @@ public static byte[] Serialize(in T val) } byte[] ret = new byte[length]; - Serialize(ret.AsSpan(), in val, fields); + if (val == null) + { + ObjectPool>.Return(fields); + return ret; + } + + Serialize(typeof(T), val, fields, ret.AsSpan(), 0); ObjectPool>.Return(fields); return ret; } @@ -73,6 +79,7 @@ public static byte[] Serialize(object val) ObjectPool>.Return(fields); return ret; } + Serialize(val.GetType(), val, fields, ret.AsSpan(), 0); ObjectPool>.Return(fields); return ret; @@ -96,18 +103,9 @@ public static int Serialize(Span buffer, object val) return Serialize(val.GetType(), val, null, buffer, 0); } - internal static int Serialize(Type type, T value, Dictionary fields ,Span buffer, int pos) + 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) - { - type = ins.Type.ReflectionType; - } - - type = type.ResolveRealType(); -#endif - Writer writer = new Writer(buffer, pos); //null check @@ -136,6 +134,11 @@ internal static int Serialize(Type type, T value, Dictionary(Type type, T value, Dictionary Members; + + public struct NinoMember + { + public MemberInfo Member; + public Type Type; + public Func GetValue; + + public NinoMember(MemberInfo member, Type type, Func getValue) + { + Member = member; + Type = type; + GetValue = getValue; + } + } - public HashSet Members; public bool Valid; public bool IncludeAll; @@ -95,12 +111,6 @@ internal class TypeModel /// internal static TypeCode GetTypeCode(Type type) { -#if ILRuntime - if (IsEnum(type) && type is ILRuntime.Reflection.ILRuntimeType) - { - type = Enum.GetUnderlyingType(type); - } -#endif var hash = type.GetTypeHashCode(); if (TypeCodes.TryGetValue(hash, out var ret)) { @@ -155,10 +165,9 @@ public static bool IsFixedSizeType(Type type) } // otherwise check recursively - foreach (var member in model.Members) + foreach (var info in model.Members) { - var mt = member is FieldInfo fi ? fi.FieldType : ((PropertyInfo)member).PropertyType; - if (!IsFixedSizeType(mt)) + if (!IsFixedSizeType(info.Type)) { ret = false; break; @@ -187,7 +196,8 @@ public static bool IsUnmanaged(Type type) .GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); foreach (var field in fields) { - if (!IsUnmanaged(field.FieldType)) + if (field.GetCustomAttributes(CompilerGeneratedType, true).Length > 0 || + !IsUnmanaged(field.FieldType)) { ret = false; break; @@ -278,7 +288,7 @@ internal static TypeModel CreateModel(Type type) { Valid = true, //fetch members - Members = new HashSet(), + Members = new List(), }; //include all or not @@ -296,6 +306,11 @@ internal static TypeModel CreateModel(Type type) //iterate fields foreach (var f in fs) { + if (f.GetCustomAttributes(CompilerGeneratedType, true).Length > 0) + { + continue; + } + if (model.IncludeAll) { //skip nino ignore @@ -354,7 +369,14 @@ internal static TypeModel CreateModel(Type type) //add members to model foreach (var pair in dict) { - model.Members.Add(pair.Value); + if (pair.Value is FieldInfo fi) + { + model.Members.Add(new NinoMember(fi, fi.FieldType, fi.GetValue)); + } + else if (pair.Value is PropertyInfo pi) + { + model.Members.Add(new NinoMember(pi, pi.PropertyType, pi.GetValue)); + } } //release dict diff --git a/src/Nino.Serialization/Writer.Generic.cs b/src/Nino.Serialization/Writer.Generic.cs index 047f17b..5adbdcd 100644 --- a/src/Nino.Serialization/Writer.Generic.cs +++ b/src/Nino.Serialization/Writer.Generic.cs @@ -27,6 +27,18 @@ public ref partial struct Writer public void WriteCommonVal(Type type, T val) => Position = Serializer.Serialize(type, val, null, buffer, Position); + /// + /// Write unmanaged type + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void WriteAsUnmanaged(ref T val, int len) + { + Unsafe.WriteUnaligned(ref buffer[Position], val); + Position += len; + } + /// /// Write unmanaged type /// @@ -39,6 +51,163 @@ public void Write(ref T val, int len) where T : unmanaged Position += len; } + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2) + where T1 : unmanaged where T2 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + } + + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3) + where T1 : unmanaged where T2 : unmanaged where T3 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + Unsafe.WriteUnaligned(ref buffer[Position], val3); + Position += len3; + } + + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3, + ref T4 val4, int len4) where T1 : unmanaged where T2 : unmanaged where T3 : unmanaged where T4 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + Unsafe.WriteUnaligned(ref buffer[Position], val3); + Position += len3; + Unsafe.WriteUnaligned(ref buffer[Position], val4); + Position += len4; + } + + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3, + ref T4 val4, int len4, ref T5 val5, int len5) where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + Unsafe.WriteUnaligned(ref buffer[Position], val3); + Position += len3; + Unsafe.WriteUnaligned(ref buffer[Position], val4); + Position += len4; + Unsafe.WriteUnaligned(ref buffer[Position], val5); + Position += len5; + } + + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3, + ref T4 val4, int len4, ref T5 val5, int len5, ref T6 val6, int len6) where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + where T6 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + Unsafe.WriteUnaligned(ref buffer[Position], val3); + Position += len3; + Unsafe.WriteUnaligned(ref buffer[Position], val4); + Position += len4; + Unsafe.WriteUnaligned(ref buffer[Position], val5); + Position += len5; + Unsafe.WriteUnaligned(ref buffer[Position], val6); + Position += len6; + } + + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, + int len3, ref T4 val4, int len4, ref T5 val5, int len5, ref T6 val6, int len6, ref T7 val7, int len7) + where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + where T6 : unmanaged + where T7 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + Unsafe.WriteUnaligned(ref buffer[Position], val3); + Position += len3; + Unsafe.WriteUnaligned(ref buffer[Position], val4); + Position += len4; + Unsafe.WriteUnaligned(ref buffer[Position], val5); + Position += len5; + Unsafe.WriteUnaligned(ref buffer[Position], val6); + Position += len6; + Unsafe.WriteUnaligned(ref buffer[Position], val7); + Position += len7; + } + + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, + int len3, ref T4 val4, int len4, ref T5 val5, int len5, ref T6 val6, int len6, ref T7 val7, int len7, + ref T8 val8, int len8) where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + where T6 : unmanaged + where T7 : unmanaged + where T8 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + Unsafe.WriteUnaligned(ref buffer[Position], val3); + Position += len3; + Unsafe.WriteUnaligned(ref buffer[Position], val4); + Position += len4; + Unsafe.WriteUnaligned(ref buffer[Position], val5); + Position += len5; + Unsafe.WriteUnaligned(ref buffer[Position], val6); + Position += len6; + Unsafe.WriteUnaligned(ref buffer[Position], val7); + Position += len7; + Unsafe.WriteUnaligned(ref buffer[Position], val8); + Position += len8; + } + /// /// Write byte[] /// @@ -171,13 +340,7 @@ public void Write(T[] arr) while (i < len) { var obj = arr[i++]; -#if ILRuntime - var eType = obj is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : obj.GetType(); -#else var eType = obj.GetType(); -#endif WriteCommonVal(eType, obj); } } @@ -228,14 +391,7 @@ public void Write(List lst) //write item foreach (var c in lst) { -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); - WriteCommonVal(eType, c); -#else WriteCommonVal(c); -#endif } } @@ -268,14 +424,7 @@ public void Write(HashSet lst) //write item foreach (var c in lst) { -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); - WriteCommonVal(eType, c); -#else WriteCommonVal(c); -#endif } } @@ -308,14 +457,7 @@ public void Write(Queue lst) //write item foreach (var c in lst) { -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); - WriteCommonVal(eType, c); -#else WriteCommonVal(c); -#endif } } @@ -348,14 +490,7 @@ public void Write(Stack lst) //write item foreach (var c in lst) { -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); - WriteCommonVal(eType, c); -#else WriteCommonVal(c); -#endif } } @@ -392,24 +527,10 @@ public void Write(Dictionary dictionary) foreach (var c in keys) { //write key -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); - WriteCommonVal(eType, c); -#else WriteCommonVal(c); -#endif //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 WriteCommonVal(val); -#endif } } } diff --git a/src/Nino.Serialization/Writer.cs b/src/Nino.Serialization/Writer.cs index 20c3b68..3325915 100644 --- a/src/Nino.Serialization/Writer.cs +++ b/src/Nino.Serialization/Writer.cs @@ -259,13 +259,7 @@ public void Write(Array arr) while (i < len) { var obj = arr.GetValue(i++); -#if ILRuntime - var eType = obj is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : obj.GetType(); -#else var eType = obj.GetType(); -#endif WriteCommonVal(eType, obj); } } @@ -297,13 +291,7 @@ public void Write(IList arr) //write item foreach (var c in arr) { -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); -#else var eType = c.GetType(); -#endif WriteCommonVal(eType, c); } } @@ -338,23 +326,11 @@ public void Write(IDictionary dictionary) foreach (var c in keys) { //write key -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); -#else var eType = c.GetType(); -#endif WriteCommonVal(eType, c); //write val var val = dictionary[c]; -#if ILRuntime - eType = val is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns2 - ? ilIns2.Type.ReflectionType - : val.GetType(); -#else eType = val.GetType(); -#endif WriteCommonVal(eType, val); } }