complete dynamic serialization

This commit is contained in:
neuecc 2017-02-21 20:39:01 +09:00
Родитель 0069b12de2
Коммит 05c4d1dd33
15 изменённых файлов: 1225 добавлений и 800 удалений

Просмотреть файл

@ -30,6 +30,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MessagePack.CodeGenerator",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharedData", "SharedData\SharedData.csproj", "{3ABC5C4C-2CE4-459E-8666-F2B181C3DEF3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamicCodeDumper", "sandbox\DynamicCodeDumper\DynamicCodeDumper.csproj", "{8E511130-F838-4B47-842B-0FB27AD175B5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -136,6 +138,18 @@ Global
{3ABC5C4C-2CE4-459E-8666-F2B181C3DEF3}.Release|x64.Build.0 = Release|Any CPU
{3ABC5C4C-2CE4-459E-8666-F2B181C3DEF3}.Release|x86.ActiveCfg = Release|Any CPU
{3ABC5C4C-2CE4-459E-8666-F2B181C3DEF3}.Release|x86.Build.0 = Release|Any CPU
{8E511130-F838-4B47-842B-0FB27AD175B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8E511130-F838-4B47-842B-0FB27AD175B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8E511130-F838-4B47-842B-0FB27AD175B5}.Debug|x64.ActiveCfg = Debug|Any CPU
{8E511130-F838-4B47-842B-0FB27AD175B5}.Debug|x64.Build.0 = Debug|Any CPU
{8E511130-F838-4B47-842B-0FB27AD175B5}.Debug|x86.ActiveCfg = Debug|Any CPU
{8E511130-F838-4B47-842B-0FB27AD175B5}.Debug|x86.Build.0 = Debug|Any CPU
{8E511130-F838-4B47-842B-0FB27AD175B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8E511130-F838-4B47-842B-0FB27AD175B5}.Release|Any CPU.Build.0 = Release|Any CPU
{8E511130-F838-4B47-842B-0FB27AD175B5}.Release|x64.ActiveCfg = Release|Any CPU
{8E511130-F838-4B47-842B-0FB27AD175B5}.Release|x64.Build.0 = Release|Any CPU
{8E511130-F838-4B47-842B-0FB27AD175B5}.Release|x86.ActiveCfg = Release|Any CPU
{8E511130-F838-4B47-842B-0FB27AD175B5}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -149,5 +163,6 @@ Global
{ED43BDA5-947C-4769-A47A-F07D3C6142AE} = {BF4C4202-5015-4FBD-80E6-D0F36A06F700}
{D8B195AC-9E93-438E-8331-EF3A1F613D0B} = {86309CF6-0054-4CE3-BFD3-CA0AA7DB17BC}
{3ABC5C4C-2CE4-459E-8666-F2B181C3DEF3} = {BF4C4202-5015-4FBD-80E6-D0F36A06F700}
{8E511130-F838-4B47-842B-0FB27AD175B5} = {BF4C4202-5015-4FBD-80E6-D0F36A06F700}
EndGlobalSection
EndGlobal

Просмотреть файл

@ -3,9 +3,19 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SharedData
{
public enum ByteEnum : byte { A, B, C, D, E }
public enum SByteEnum : sbyte { A, B, C, D, E }
public enum ShortEnum : short { A, B, C, D, E }
public enum UShortEnum : ushort { A, B, C, D, E }
public enum IntEnum : int { A, B, C, D, E }
public enum UIntEnum : uint { A, B, C, D, E }
public enum LongEnum : long { A, B, C, D, E }
public enum ULongEnum : ulong { A, B, C, D, E }
[MessagePackObject]
public class FirstSimpleData
{
@ -17,15 +27,91 @@ namespace SharedData
public int Prop3 { get; set; }
}
[MessagePackObject]
public class SimpleIntKeyData
{
[Key(0)]
public int Prop1 { get; set; }
[Key(1)]
public ByteEnum Prop2 { get; set; }
[Key(2)]
public string Prop3 { get; set; }
[Key(3)]
public SimlpeStringKeyData Prop4 { get; set; }
[Key(4)]
public SimpleStructIntKeyData Prop5 { get; set; }
[Key(5)]
public SimpleStructStringKeyData Prop6 { get; set; }
[Key(6)]
public byte[] BytesSpecial { get; set; }
}
[MessagePackObject(true)]
public class SimlpeStringKeyData
{
public int Prop1 { get; set; }
public ByteEnum Prop2 { get; set; }
public int Prop3 { get; set; }
}
[MessagePackObject]
public struct SimpleStructIntKeyData
{
[Key(0)]
public int X { get; set; }
[Key(1)]
public int Y { get; set; }
[Key(2)]
public byte[] BytesSpecial { get; set; }
}
[MessagePackObject]
public struct SimpleStructStringKeyData
{
[Key("key-X")]
public int X { get; set; }
[Key("key-Y")]
public int[] Y { get; set; }
}
[MessagePackObject]
public struct Vector2
{
[Key(0)]
public readonly float X;
[Key(1)]
public readonly float Y;
public Vector2(float x, float y)
{
X = x;
Y = y;
}
}
[MessagePackObject]
public class EmptyClass
{
}
[MessagePackObject]
public struct EmptyStruct
{
}
[MessagePackObject]
public class Version1
{
[Key(340)]
[Key(3)]
public int MyProperty1 { get; set; }
[Key(101)]
[Key(4)]
public int MyProperty2 { get; set; }
[Key(252)]
[Key(5)]
public int MyProperty3 { get; set; }
}
@ -33,15 +119,15 @@ namespace SharedData
[MessagePackObject]
public class Version2
{
[Key(340)]
[Key(3)]
public int MyProperty1 { get; set; }
[Key(101)]
[Key(4)]
public int MyProperty2 { get; set; }
[Key(252)]
[Key(5)]
public int MyProperty3 { get; set; }
[Key(3009)]
public int MyProperty4 { get; set; }
[Key(201)]
// [Key(6)]
// public int MyProperty4 { get; set; }
[Key(7)]
public int MyProperty5 { get; set; }
}
@ -49,7 +135,7 @@ namespace SharedData
[MessagePackObject]
public class Version0
{
[Key(340)]
[Key(3)]
public int MyProperty1 { get; set; }
}
@ -79,4 +165,124 @@ namespace SharedData
[Key(1)]
public int After { get; set; }
}
}
[MessagePackObject]
public class Callback1 : IMessagePackSerializationCallbackReceiver
{
[Key(0)]
public int X { get; set; }
public bool CalledBefore { get; private set; }
public bool CalledAfter { get; private set; }
public Callback1(int x)
{
}
public void OnBeforeSerialize()
{
CalledBefore = true;
}
public void OnAfterDeserialize()
{
CalledAfter = true;
}
}
[MessagePackObject]
public class Callback1_2 : IMessagePackSerializationCallbackReceiver
{
[Key(0)]
public int X { get; set; }
public bool CalledBefore { get; private set; }
public bool CalledAfter { get; private set; }
public Callback1_2(int x)
{
this.X = x;
}
void IMessagePackSerializationCallbackReceiver.OnBeforeSerialize()
{
CalledBefore = true;
}
void IMessagePackSerializationCallbackReceiver.OnAfterDeserialize()
{
CalledAfter = true;
}
}
[MessagePackObject(true)]
public struct Callback2 : IMessagePackSerializationCallbackReceiver
{
[Key(0)]
public int X { get; set; }
Action onBefore;
Action onAfter;
public static bool CalledAfter = false;
public Callback2(int x)
: this(x, () => { }, () => { })
{
}
public Callback2(int x, Action onBefore, Action onAfter)
{
this.X = x;
this.onBefore = onBefore;
this.onAfter = onAfter;
}
public void OnBeforeSerialize()
{
onBefore();
}
public void OnAfterDeserialize()
{
CalledAfter = true;
}
}
[MessagePackObject(true)]
public struct Callback2_2 : IMessagePackSerializationCallbackReceiver
{
[Key(0)]
public int X { get; set; }
public static bool CalledAfter = false;
public Callback2_2(int x)
: this(x, () => { }, () => { })
{
}
Action onBefore;
Action onAfter;
public Callback2_2(int x, Action onBefore, Action onAfter)
{
this.X = x;
this.onBefore = onBefore;
this.onAfter = onAfter;
}
void IMessagePackSerializationCallbackReceiver.OnBeforeSerialize()
{
onBefore();
}
void IMessagePackSerializationCallbackReceiver.OnAfterDeserialize()
{
CalledAfter = true;
}
}
}

Просмотреть файл

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{8E511130-F838-4B47-842B-0FB27AD175B5}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>DynamicCodeDumper</RootNamespace>
<AssemblyName>DynamicCodeDumper</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;NET_35</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;NET_35</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\src\MessagePack\FloatBits.cs">
<Link>Code\FloatBits.cs</Link>
</Compile>
<Compile Include="..\..\src\MessagePack\Formatters\IMessagePackFormatter.cs">
<Link>Code\IMessagePackFormatter.cs</Link>
</Compile>
<Compile Include="..\..\src\MessagePack\Formatters\NullableFormatter.cs">
<Link>Code\NullableFormatter.cs</Link>
</Compile>
<Compile Include="..\..\src\MessagePack\IFormatterResolver.cs">
<Link>Code\IFormatterResolver.cs</Link>
</Compile>
<Compile Include="..\..\src\MessagePack\Internal\DynamicAssembly.cs">
<Link>Code\DynamicAssembly.cs</Link>
</Compile>
<Compile Include="..\..\src\MessagePack\Internal\ILGeneratorExtensions.cs">
<Link>Code\ILGeneratorExtensions.cs</Link>
</Compile>
<Compile Include="..\..\src\MessagePack\Internal\ReflectionExtensions.cs">
<Link>Code\ReflectionExtensions.cs</Link>
</Compile>
<Compile Include="..\..\src\MessagePack\MessagePackBinary.cs">
<Link>Code\MessagePackBinary.cs</Link>
</Compile>
<Compile Include="..\..\src\MessagePack\MessagePackCode.cs">
<Link>Code\MessagePackCode.cs</Link>
</Compile>
<Compile Include="..\..\src\MessagePack\Nil.cs">
<Link>Code\Nil.cs</Link>
</Compile>
<Compile Include="..\..\src\MessagePack\Resolvers\DynamicObjectResolver.cs">
<Link>Code\DynamicObjectResolver.cs</Link>
</Compile>
<Compile Include="..\..\src\MessagePack\StringEncoding.cs">
<Link>Code\StringEncoding.cs</Link>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\SharedData\SharedData.csproj">
<Project>{3abc5c4c-2ce4-459e-8666-f2b181c3def3}</Project>
<Name>SharedData</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\MessagePack.Interfaces\MessagePack.Interfaces.csproj">
<Project>{7beb73dc-9106-4507-a5cc-8cd850a24109}</Project>
<Name>MessagePack.Interfaces</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

Просмотреть файл

@ -0,0 +1,30 @@
using MessagePack.Resolvers;
using SharedData;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DynamicCodeDumper
{
public class Program
{
static void Main(string[] args)
{
DynamicObjectResolver.Instance.GetFormatter<FirstSimpleData>();
DynamicObjectResolver.Instance.GetFormatter<Version0>();
DynamicObjectResolver.Instance.GetFormatter<Version1>();
DynamicObjectResolver.Instance.GetFormatter<Version2>();
DynamicObjectResolver.Instance.GetFormatter<Vector2>();
// DynamicObjectResolver.Instance.GetFormatter<Vector2_String>();
DynamicObjectResolver.Instance.GetFormatter<Callback1>();
DynamicObjectResolver.Instance.GetFormatter<Callback1_2>();
DynamicObjectResolver.Instance.GetFormatter<Callback2>();
DynamicObjectResolver.Instance.GetFormatter<Callback2_2>();
DynamicObjectResolver.Instance.Save();
Console.WriteLine("Saved");
}
}
}

Просмотреть файл

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// アセンブリに関する一般情報は以下の属性セットをとおして制御されます。
// アセンブリに関連付けられている情報を変更するには、
// これらの属性値を変更してください。
[assembly: AssemblyTitle("DynamicCodeDumper")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("DynamicCodeDumper")]
[assembly: AssemblyCopyright("Copyright © 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// ComVisible を false に設定すると、このアセンブリ内の型は COM コンポーネントから
// 参照できなくなります。COM からこのアセンブリ内の型にアクセスする必要がある場合は、
// その型の ComVisible 属性を true に設定してください。
[assembly: ComVisible(false)]
// このプロジェクトが COM に公開される場合、次の GUID が typelib の ID になります
[assembly: Guid("8e511130-f838-4b47-842b-0fb27ad175b5")]
// アセンブリのバージョン情報は次の 4 つの値で構成されています:
//
// メジャー バージョン
// マイナー バージョン
// ビルド番号
// Revision
//
// すべての値を指定するか、次を使用してビルド番号とリビジョン番号を既定に設定できます
// 以下のように '*' を使用します:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -10,7 +10,6 @@ using System.Collections.Generic;
using MessagePack.Internal;
using ProtoBuf;
using SharedData;
using Test;
namespace Sandbox
{
@ -68,7 +67,7 @@ namespace Sandbox
}
}
[MessagePackObject(true)]
[MessagePackObject]
public struct Vector2
{
[Key(0)]
@ -139,61 +138,30 @@ namespace Sandbox
//Console.WriteLine();
//Benchmark(l);
var test = MessagePack.MessagePackSerializer.Serialize(new FirstSimpleData { Prop1 = 9, Prop3 = 300, Prop2 = "fdasfa" });
Console.WriteLine(MessagePack.MessagePackSerializer.ToJson(test));
MessagePackSerializer.SetDefaultResolver(ComposittedResolver.Instance);
var v1 = new Version1
{
MyProperty1 = 100,
MyProperty2 = 200,
MyProperty3 = 300
};
var v2 = new Version2
var c1 = new Callback1(0);
var d = MessagePackSerializer.Serialize(c1);
MessagePackSerializer.Deserialize<Callback1>(d);
}
{
MyProperty1 = 100,
MyProperty2 = 200,
MyProperty3 = 300,
MyProperty4 = 400,
MyProperty5 = 500,
};
var v0 = new Version0
var before = false;
var after = false;
var c1 = new Callback2(0, () => before = true, () => after = true);
var d = MessagePackSerializer.Serialize(c1);
MessagePackSerializer.Deserialize<Callback2>(d);
}
{
MyProperty1 = 100,
};
var v1Bytes = MessagePackSerializer.Serialize(v1);
var v2Bytes = MessagePackSerializer.Serialize(v2);
var v0Bytes = MessagePackSerializer.Serialize(v0);
var a = MessagePackSerializer.ToJson(v1Bytes);
var b = MessagePackSerializer.ToJson(v2Bytes);
var c = MessagePackSerializer.ToJson(v0Bytes);
// smaller than schema
var v2_ = MessagePackSerializer.Deserialize<Version2>(v1Bytes);
// larger than schema
var v0_ = MessagePackSerializer.Deserialize<Version0>(v1Bytes);
// smaller than schema
var v2_default = MessagePackSerializer.Deserialize<Version2>(v1Bytes, DefaultResolver.Instance);
// larger than schema
var v0_default = MessagePackSerializer.Deserialize<Version0>(v1Bytes, DefaultResolver.Instance);
var c1 = new Callback1_2(0);
var d = MessagePackSerializer.Serialize(c1);
//MessagePackSerializer.Deserialize<Callback1_2>(d);
}
{
var before = false;
var after = false;
var c1 = new Callback2(0, () => before = true, () => after = true);
var d = MessagePackSerializer.Serialize(c1);
// MessagePackSerializer.Deserialize<Callback2_2>(d);
}
}
static void Benchmark<T>(T target)

Просмотреть файл

@ -15,8 +15,22 @@ namespace MessagePack.Internal
public DynamicAssembly(string moduleName)
{
this.moduleName = moduleName;
#if NET_35
this.assemblyBuilder = System.AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(moduleName), AssemblyBuilderAccess.RunAndSave);
this.moduleBuilder = assemblyBuilder.DefineDynamicModule(moduleName, moduleName + ".dll");
#else
this.assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(moduleName), AssemblyBuilderAccess.Run);
this.moduleBuilder = assemblyBuilder.DefineDynamicModule(moduleName);
#endif
}
#if NET_35
public void Save()
{
assemblyBuilder.Save(moduleName + ".dll");
}
#endif
}
}

Просмотреть файл

@ -414,6 +414,17 @@ namespace MessagePack
}
}
/// <summary>
/// Unsafe. If value is guranteed 0 ~ MessagePackRange.MaxFixArrayCount(15), can use this method.
/// </summary>
/// <returns></returns>
public static int WriteFixedArrayHeaderUnsafe(ref byte[] bytes, int offset, int count)
{
EnsureCapacity(ref bytes, offset, 1);
bytes[offset] = (byte)(MessagePackCode.MinFixArray | count);
return 1;
}
/// <summary>
/// Write array count.
/// </summary>

Просмотреть файл

@ -65,6 +65,11 @@ namespace MessagePack
readSize = ToJsonCore(bytes, offset, builder);
offset += readSize;
totalReadSize += readSize;
if (i != length - 1)
{
builder.Append(",");
}
}
builder.Append("]");

Просмотреть файл

@ -13,7 +13,7 @@ namespace MessagePack.Resolvers
/// </summary>
public class DynamicObjectResolver : IFormatterResolver
{
public static IFormatterResolver Instance = new DynamicObjectResolver();
public static DynamicObjectResolver Instance = new DynamicObjectResolver();
const string ModuleName = "MessagePack.Resolvers.DynamicObjectResolver";
@ -29,7 +29,14 @@ namespace MessagePack.Resolvers
assembly = new DynamicAssembly(ModuleName);
}
IMessagePackFormatter<T> IFormatterResolver.GetFormatter<T>()
#if NET_35
public void Save()
{
assembly.Save();
}
#endif
public IMessagePackFormatter<T> GetFormatter<T>()
{
return FormatterCache<T>.formatter;
}
@ -139,55 +146,112 @@ namespace MessagePack.Resolvers
il.MarkLabel(elseBody);
}
var writeCount = info.Members.Count(x => x.IsReadable);
// IMessagePackSerializationCallbackReceiver.OnBeforeSerialize()
if (type.GetTypeInfo().ImplementedInterfaces.Any(x => x == typeof(IMessagePackSerializationCallbackReceiver)))
{
// call directly
var runtimeMethods = type.GetRuntimeMethods().Where(x => x.Name == "OnBeforeSerialize").ToArray();
if (runtimeMethods.Length == 1)
{
if (info.IsStruct)
{
il.EmitLdarga(3);
}
else
{
il.EmitLdarg(3);
}
il.EmitCall(runtimeMethods[0]);
}
else
{
il.EmitLdarg(3);
if (info.IsStruct)
{
il.Emit(OpCodes.Box, type);
}
il.EmitCallvirt(onBeforeSerialize);
}
}
// var startOffset = offset;
var startOffsetLocal = il.DeclareLocal(typeof(int)); // [loc:0]
il.EmitLdarg(2);
il.EmitStloc(startOffsetLocal);
// offset += writeHeader
EmitOffsetPlusEqual(il, null, () =>
{
il.EmitLdc_I4(writeCount);
if (writeCount <= MessagePackRange.MaxFixMapCount)
{
il.EmitCall(MessagePackBinaryTypeInfo.WriteFixedMapHeaderUnsafe);
}
else
{
il.EmitCall(MessagePackBinaryTypeInfo.WriteMapHeader);
}
});
foreach (var item in info.Members.Where(x => x.IsReadable))
if (info.IsIntKey)
{
// offset += writekey
EmitOffsetPlusEqual(il, null, () =>
{
if (info.IsIntKey)
{
il.EmitLdc_I4(item.IntKey);
if (0 <= item.IntKey && item.IntKey <= MessagePackRange.MaxFixPositiveInt)
{
il.EmitCall(MessagePackBinaryTypeInfo.WritePositiveFixedIntUnsafe);
}
else
{
il.EmitCall(MessagePackBinaryTypeInfo.WriteInt32);
}
}
else
{
// embed string and bytesize
il.Emit(OpCodes.Ldstr, item.StringKey);
il.EmitLdc_I4(StringEncoding.UTF8.GetByteCount(item.StringKey));
il.EmitCall(MessagePackBinaryTypeInfo.WriteStringUnsafe);
}
});
// use Array
var maxKey = info.Members.Where(x => x.IsReadable).Select(x => x.IntKey).DefaultIfEmpty(0).Max();
var intKeyMap = info.Members.Where(x => x.IsReadable).ToDictionary(x => x.IntKey);
// offset += serializeValue
EmitSerializeValue(il, type.GetTypeInfo(), item);
EmitOffsetPlusEqual(il, null, () =>
{
var len = maxKey + 1;
il.EmitLdc_I4(len);
if (len <= MessagePackRange.MaxFixArrayCount)
{
il.EmitCall(MessagePackBinaryTypeInfo.WriteFixedArrayHeaderUnsafe);
}
else
{
il.EmitCall(MessagePackBinaryTypeInfo.WriteArrayHeader);
}
});
for (int i = 0; i <= maxKey; i++)
{
ObjectSerializationInfo.EmittableMember member;
if (intKeyMap.TryGetValue(i, out member))
{
// offset += serialzie
EmitSerializeValue(il, type.GetTypeInfo(), member);
}
else
{
// Write Nil as Blanc
EmitOffsetPlusEqual(il, null, () =>
{
il.EmitCall(MessagePackBinaryTypeInfo.WriteNil);
});
}
}
}
else
{
// use Map
var writeCount = info.Members.Count(x => x.IsReadable);
EmitOffsetPlusEqual(il, null, () =>
{
il.EmitLdc_I4(writeCount);
if (writeCount <= MessagePackRange.MaxFixMapCount)
{
il.EmitCall(MessagePackBinaryTypeInfo.WriteFixedMapHeaderUnsafe);
}
else
{
il.EmitCall(MessagePackBinaryTypeInfo.WriteMapHeader);
}
});
foreach (var item in info.Members.Where(x => x.IsReadable))
{
// offset += writekey
if (info.IsStringKey)
{
EmitOffsetPlusEqual(il, null, () =>
{
// embed string and bytesize
il.Emit(OpCodes.Ldstr, item.StringKey);
il.EmitLdc_I4(StringEncoding.UTF8.GetByteCount(item.StringKey));
il.EmitCall(MessagePackBinaryTypeInfo.WriteStringUnsafe);
});
}
// offset += serialzie
EmitSerializeValue(il, type.GetTypeInfo(), item);
}
}
// return startOffset- offset;
@ -267,8 +331,6 @@ namespace MessagePack.Resolvers
}
else
{
typeof(System.InvalidOperationException).GetTypeInfo().DeclaredConstructors.First(x => { var p = x.GetParameters(); return p.Length == 1 && p[0].ParameterType == typeof(string); });
il.Emit(OpCodes.Ldstr, "typecode is null, struct not supported");
il.Emit(OpCodes.Newobj, invalidOperationExceptionConstructor);
il.Emit(OpCodes.Throw);
@ -285,43 +347,79 @@ namespace MessagePack.Resolvers
il.EmitLdarg(1);
il.EmitLdarg(2);
il.EmitLdarg(4);
il.EmitCall(MessagePackBinaryTypeInfo.ReadMapHeader);
if (info.IsIntKey)
{
il.EmitCall(MessagePackBinaryTypeInfo.ReadArrayHeader);
}
else
{
il.EmitCall(MessagePackBinaryTypeInfo.ReadMapHeader);
}
il.EmitStloc(length);
EmitOffsetPlusReadSize(il);
// make local fields
DeserializeInfo[] intList = null;
var temp = new List<DeserializeInfo>();
foreach (var item in info.Members)
Label? gotoDefault = null;
DeserializeInfo[] infoList;
if (info.IsIntKey)
{
temp.Add(new DeserializeInfo
{
MemberInfo = item,
LocalField = il.DeclareLocal(item.Type),
SwitchLabel = il.DefineLabel()
});
var maxKey = info.Members.Select(x => x.IntKey).DefaultIfEmpty(0).Max();
var len = maxKey + 1;
var intKeyMap = info.Members.ToDictionary(x => x.IntKey);
infoList = Enumerable.Range(0, len)
.Select(x =>
{
ObjectSerializationInfo.EmittableMember member;
if (intKeyMap.TryGetValue(x, out member))
{
return new DeserializeInfo
{
MemberInfo = member,
LocalField = il.DeclareLocal(member.Type),
SwitchLabel = il.DefineLabel()
};
}
else
{
// return null MemberInfo, should filter null
if (gotoDefault == null)
{
gotoDefault = il.DefineLabel();
}
return new DeserializeInfo
{
MemberInfo = null,
LocalField = null,
SwitchLabel = gotoDefault.Value,
};
}
})
.ToArray();
}
intList = temp.ToArray();
else
{
infoList = info.Members
.Select(item => new DeserializeInfo
{
MemberInfo = item,
LocalField = il.DeclareLocal(item.Type),
SwitchLabel = il.DefineLabel()
})
.ToArray();
}
// Read Loop(for var i = 0; i< length; i++)
{
var key = il.DeclareLocal(typeof(int));
var loopEnd = il.DefineLabel();
var switchDefault = il.DefineLabel();
var loopEnd = il.DefineLabel();
var stringKeyTrue = il.DefineLabel();
il.EmitIncrementFor(length, forILocal =>
{
if (info.IsIntKey)
{
// key = Deserialize, offset += readSize;
il.EmitLdarg(1);
il.EmitLdarg(2);
il.EmitLdarg(4);
il.EmitCall(MessagePackBinaryTypeInfo.ReadInt32);
il.EmitStloc(key);
EmitOffsetPlusReadSize(il);
}
else
if (info.IsStringKey)
{
// get string key -> dictionary lookup
il.EmitLdarg(0);
@ -344,18 +442,17 @@ namespace MessagePack.Resolvers
il.MarkLabel(stringKeyTrue);
}
else
{
il.EmitLdloc(forILocal);
il.EmitStloc(key);
}
// switch... local = Deserialize
il.EmitLdloc(key);
// TODO:Jump-Table only supports sequential IntKey, currently buggy, should fix.
il.Emit(OpCodes.Switch, intList.Select(x => x.SwitchLabel).ToArray());
foreach (var item in intList)
{
il.MarkLabel(item.SwitchLabel);
EmitDeserializeValue(il, item);
il.Emit(OpCodes.Br, loopEnd);
}
il.Emit(OpCodes.Switch, infoList.Select(x => x.SwitchLabel).ToArray());
il.MarkLabel(switchDefault);
// default, only read. readSize = MessagePackBinary.ReadNext(bytes, offset);
il.EmitLdarg(4);
@ -365,6 +462,22 @@ namespace MessagePack.Resolvers
il.Emit(OpCodes.Stind_I4);
il.Emit(OpCodes.Br, loopEnd);
if (gotoDefault != null)
{
il.MarkLabel(gotoDefault.Value);
il.Emit(OpCodes.Br, switchDefault);
}
foreach (var item in infoList)
{
if (item.MemberInfo != null)
{
il.MarkLabel(item.SwitchLabel);
EmitDeserializeValue(il, item);
il.Emit(OpCodes.Br, loopEnd);
}
}
// offset += readSize
il.MarkLabel(loopEnd);
EmitOffsetPlusReadSize(il);
@ -379,7 +492,45 @@ namespace MessagePack.Resolvers
il.Emit(OpCodes.Stind_I4);
// create result object
EmitNewObject(il, type, info, intList);
var structLocal = EmitNewObject(il, type, info, infoList);
// IMessagePackSerializationCallbackReceiver.OnAfterDeserialize()
if (type.GetTypeInfo().ImplementedInterfaces.Any(x => x == typeof(IMessagePackSerializationCallbackReceiver)))
{
// call directly
var runtimeMethods = type.GetRuntimeMethods().Where(x => x.Name == "OnAfterDeserialize").ToArray();
if (runtimeMethods.Length == 1)
{
if (info.IsClass)
{
il.Emit(OpCodes.Dup);
}
else
{
il.EmitLdloca(structLocal);
}
il.EmitCall(runtimeMethods[0]);
}
else
{
if (info.IsStruct)
{
il.EmitLdloc(structLocal);
il.Emit(OpCodes.Box, type);
}
else
{
il.Emit(OpCodes.Dup);
}
il.EmitCallvirt(onAfterDeserialize);
}
}
if (info.IsStruct)
{
il.Emit(OpCodes.Ldloc, structLocal);
}
il.Emit(OpCodes.Ret);
}
@ -425,7 +576,7 @@ namespace MessagePack.Resolvers
il.EmitStloc(info.LocalField);
}
static void EmitNewObject(ILGenerator il, Type type, ObjectSerializationInfo info, DeserializeInfo[] members)
static LocalBuilder EmitNewObject(ILGenerator il, Type type, ObjectSerializationInfo info, DeserializeInfo[] members)
{
if (info.IsClass)
{
@ -436,12 +587,14 @@ namespace MessagePack.Resolvers
}
il.Emit(OpCodes.Newobj, info.BestmatchConstructor);
foreach (var item in members.Where(x => x.MemberInfo.IsWritable))
foreach (var item in members.Where(x => x.MemberInfo != null && x.MemberInfo.IsWritable))
{
il.Emit(OpCodes.Dup);
il.EmitLdloc(item.LocalField);
item.MemberInfo.EmitStoreValue(il);
}
return null;
}
else
{
@ -462,14 +615,14 @@ namespace MessagePack.Resolvers
il.Emit(OpCodes.Stloc, result);
}
foreach (var item in members.Where(x => x.MemberInfo.IsWritable))
foreach (var item in members.Where(x => x.MemberInfo != null && x.MemberInfo.IsWritable))
{
il.EmitLdloca(result);
il.EmitLdloc(item.LocalField);
item.MemberInfo.EmitStoreValue(il);
}
il.Emit(OpCodes.Ldloc, result);
return result; // struct returns local result field
}
}
@ -485,12 +638,17 @@ namespace MessagePack.Resolvers
static readonly MethodInfo dictionaryTryGetValue = typeof(Dictionary<string, int>).GetRuntimeMethod("TryGetValue", new[] { typeof(string), refInt });
static readonly ConstructorInfo invalidOperationExceptionConstructor = typeof(System.InvalidOperationException).GetTypeInfo().DeclaredConstructors.First(x => { var p = x.GetParameters(); return p.Length == 1 && p[0].ParameterType == typeof(string); });
static readonly MethodInfo onBeforeSerialize = typeof(IMessagePackSerializationCallbackReceiver).GetRuntimeMethod("OnBeforeSerialize", Type.EmptyTypes);
static readonly MethodInfo onAfterDeserialize = typeof(IMessagePackSerializationCallbackReceiver).GetRuntimeMethod("OnAfterDeserialize", Type.EmptyTypes);
static class MessagePackBinaryTypeInfo
{
public static TypeInfo TypeInfo = typeof(MessagePackBinary).GetTypeInfo();
public static MethodInfo WriteFixedMapHeaderUnsafe = typeof(MessagePackBinary).GetRuntimeMethod("WriteFixedMapHeaderUnsafe", new[] { refByte, typeof(int), typeof(int) });
public static MethodInfo WriteFixedArrayHeaderUnsafe = typeof(MessagePackBinary).GetRuntimeMethod("WriteFixedArrayHeaderUnsafe", new[] { refByte, typeof(int), typeof(int) });
public static MethodInfo WriteMapHeader = typeof(MessagePackBinary).GetRuntimeMethod("WriteMapHeader", new[] { refByte, typeof(int), typeof(int) });
public static MethodInfo WriteArrayHeader = typeof(MessagePackBinary).GetRuntimeMethod("WriteArrayHeader", new[] { refByte, typeof(int), typeof(int) });
public static MethodInfo WritePositiveFixedIntUnsafe = typeof(MessagePackBinary).GetRuntimeMethod("WritePositiveFixedIntUnsafe", new[] { refByte, typeof(int), typeof(int) });
public static MethodInfo WriteInt32 = typeof(MessagePackBinary).GetRuntimeMethod("WriteInt32", new[] { refByte, typeof(int), typeof(int) });
public static MethodInfo WriteBytes = typeof(MessagePackBinary).GetRuntimeMethod("WriteBytes", new[] { refByte, typeof(int), typeof(byte[]) });
@ -502,6 +660,7 @@ namespace MessagePack.Resolvers
public static MethodInfo ReadNext = typeof(MessagePackBinary).GetRuntimeMethod("ReadNext", new[] { typeof(byte[]), typeof(int) });
public static MethodInfo WriteStringUnsafe = typeof(MessagePackBinary).GetRuntimeMethod("WriteStringUnsafe", new[] { refByte, typeof(int), typeof(string), typeof(int) });
public static MethodInfo ReadArrayHeader = typeof(MessagePackBinary).GetRuntimeMethod("ReadArrayHeader", new[] { typeof(byte[]), typeof(int), refInt });
public static MethodInfo ReadMapHeader = typeof(MessagePackBinary).GetRuntimeMethod("ReadMapHeader", new[] { typeof(byte[]), typeof(int), refInt });
static MessagePackBinaryTypeInfo()

Просмотреть файл

@ -1,4 +1,5 @@
using System;
using SharedData;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

Просмотреть файл

@ -68,12 +68,15 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Utils\ChainingAssertion.Ext.cs" />
<Compile Include="Utils\ChainingAssertion.Xunit.cs" />
<Compile Include="_Data.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\SharedData\SharedData.csproj">
<Project>{3abc5c4c-2ce4-459e-8666-f2b181c3def3}</Project>
<Name>SharedData</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\MessagePack.Interfaces\MessagePack.Interfaces.csproj">
<Project>{7beb73dc-9106-4507-a5cc-8cd850a24109}</Project>
<Name>MessagePack.Interfaces</Name>

Просмотреть файл

@ -1,4 +1,5 @@
using System;
using SharedData;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -111,7 +112,6 @@ namespace MessagePack.Tests
MyProperty1 = 100,
MyProperty2 = 200,
MyProperty3 = 300,
MyProperty4 = 400,
MyProperty5 = 500,
};
@ -136,7 +136,6 @@ namespace MessagePack.Tests
v2_.MyProperty1.Is(v1.MyProperty1);
v2_.MyProperty2.Is(v1.MyProperty2);
v2_.MyProperty3.Is(v1.MyProperty3);
v2_.MyProperty4.Is(0);
v2_.MyProperty5.Is(0);
// larger than schema
@ -166,7 +165,6 @@ namespace MessagePack.Tests
MyProperty1 = 100,
MyProperty2 = 200,
MyProperty3 = 300,
MyProperty4 = 400,
MyProperty5 = 500
},
After = 99999999
@ -190,14 +188,52 @@ namespace MessagePack.Tests
v2_.MyProperty1.MyProperty1.Is(v1.MyProperty1.MyProperty1);
v2_.MyProperty1.MyProperty2.Is(v1.MyProperty1.MyProperty2);
v2_.MyProperty1.MyProperty3.Is(v1.MyProperty1.MyProperty3);
v2_.MyProperty1.MyProperty4.Is(0);
v2_.MyProperty1.MyProperty5.Is(0);
v2_.After.Is(9999);
// larger than schema
var v1Json = MessagePackSerializer.ToJson(v1Bytes);
var v0_ = MessagePackSerializer.Deserialize<HolderV0>(v1Bytes);
v0_.MyProperty1.MyProperty1.Is(v1.MyProperty1.MyProperty1);
v0.After.Is(9999);
v0_.After.Is(9999);
}
[Fact]
public void SerializationCallback()
{
{
var c1 = new Callback1(0);
var d = MessagePackSerializer.Serialize(c1);
c1.CalledBefore.IsTrue();
MessagePackSerializer.Deserialize<Callback1>(d).CalledAfter.IsTrue();
}
{
var before = false;
var c1 = new Callback2(0, () => before = true, () => { });
var d = MessagePackSerializer.Serialize(c1);
before.IsTrue();
Callback2.CalledAfter.IsFalse();
MessagePackSerializer.Deserialize<Callback2>(d);
Callback2.CalledAfter.IsTrue();
}
{
var c1 = new Callback1_2(0);
var d = MessagePackSerializer.Serialize(c1);
c1.CalledBefore.IsTrue();
MessagePackSerializer.Deserialize<Callback1_2>(d).CalledAfter.IsTrue();
}
{
var before = false;
var c1 = new Callback2_2(0, () => before = true, () => { });
var d = MessagePackSerializer.Serialize(c1);
before.IsTrue();
Callback2_2.CalledAfter.IsFalse();
MessagePackSerializer.Deserialize<Callback2_2>(d);
Callback2_2.CalledAfter.IsTrue();
}
}
}
}

Просмотреть файл

@ -1,156 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MessagePack.Tests
{
public enum ByteEnum : byte { A, B, C, D, E }
public enum SByteEnum : sbyte { A, B, C, D, E }
public enum ShortEnum : short { A, B, C, D, E }
public enum UShortEnum : ushort { A, B, C, D, E }
public enum IntEnum : int { A, B, C, D, E }
public enum UIntEnum : uint { A, B, C, D, E }
public enum LongEnum : long { A, B, C, D, E }
public enum ULongEnum : ulong { A, B, C, D, E }
[MessagePackObject]
public class SimpleIntKeyData
{
[Key(0)]
public int Prop1 { get; set; }
[Key(1)]
public ByteEnum Prop2 { get; set; }
[Key(2)]
public string Prop3 { get; set; }
[Key(3)]
public SimlpeStringKeyData Prop4 { get; set; }
[Key(4)]
public SimpleStructIntKeyData Prop5 { get; set; }
[Key(5)]
public SimpleStructStringKeyData Prop6 { get; set; }
[Key(6)]
public byte[] BytesSpecial { get; set; }
}
[MessagePackObject(true)]
public class SimlpeStringKeyData
{
public int Prop1 { get; set; }
public ByteEnum Prop2 { get; set; }
public int Prop3 { get; set; }
}
[MessagePackObject]
public struct SimpleStructIntKeyData
{
[Key(0)]
public int X { get; set; }
[Key(1)]
public int Y { get; set; }
[Key(2)]
public byte[] BytesSpecial { get; set; }
}
[MessagePackObject]
public struct SimpleStructStringKeyData
{
[Key("key-X")]
public int X { get; set; }
[Key("key-Y")]
public int[] Y { get; set; }
}
[MessagePackObject]
public struct Vector2
{
[Key(0)]
public readonly float X;
[Key(1)]
public readonly float Y;
public Vector2(float x, float y)
{
X = x;
Y = y;
}
}
[MessagePackObject]
public class EmptyClass
{
}
[MessagePackObject]
public struct EmptyStruct
{
}
[MessagePackObject]
public class Version1
{
[Key(340)]
public int MyProperty1 { get; set; }
[Key(101)]
public int MyProperty2 { get; set; }
[Key(252)]
public int MyProperty3 { get; set; }
}
[MessagePackObject]
public class Version2
{
[Key(340)]
public int MyProperty1 { get; set; }
[Key(101)]
public int MyProperty2 { get; set; }
[Key(252)]
public int MyProperty3 { get; set; }
[Key(3009)]
public int MyProperty4 { get; set; }
[Key(201)]
public int MyProperty5 { get; set; }
}
[MessagePackObject]
public class Version0
{
[Key(340)]
public int MyProperty1 { get; set; }
}
[MessagePackObject]
public class HolderV1
{
[Key(0)]
public Version1 MyProperty1 { get; set; }
[Key(1)]
public int After { get; set; }
}
[MessagePackObject]
public class HolderV2
{
[Key(0)]
public Version2 MyProperty1 { get; set; }
[Key(1)]
public int After { get; set; }
}
[MessagePackObject]
public class HolderV0
{
[Key(0)]
public Version0 MyProperty1 { get; set; }
[Key(1)]
public int After { get; set; }
}
}