#if !UNITY_WSA
#if !NET_STANDARD_2_0
using System;
using System.Linq;
using MessagePack.Formatters;
using MessagePack.Internal;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Runtime.Serialization;
using System.Text;
using System.Threading;
namespace MessagePack.Resolvers
{
///
/// ObjectResolver by dynamic code generation.
///
public sealed class DynamicObjectResolver : IFormatterResolver
{
public static readonly DynamicObjectResolver Instance = new DynamicObjectResolver();
const string ModuleName = "MessagePack.Resolvers.DynamicObjectResolver";
internal static readonly DynamicAssembly assembly;
DynamicObjectResolver()
{
}
static DynamicObjectResolver()
{
assembly = new DynamicAssembly(ModuleName);
}
#if NET_35
public AssemblyBuilder Save()
{
return assembly.Save();
}
#endif
public IMessagePackFormatter GetFormatter()
{
return FormatterCache.formatter;
}
static class FormatterCache
{
public static readonly IMessagePackFormatter formatter;
static FormatterCache()
{
var ti = typeof(T).GetTypeInfo();
if (ti.IsInterface)
{
return;
}
if (ti.IsNullable())
{
ti = ti.GenericTypeArguments[0].GetTypeInfo();
var innerFormatter = DynamicObjectResolver.Instance.GetFormatterDynamic(ti.AsType());
if (innerFormatter == null)
{
return;
}
formatter = (IMessagePackFormatter)Activator.CreateInstance(typeof(StaticNullableFormatter<>).MakeGenericType(ti.AsType()), new object[] { innerFormatter });
return;
}
if (ti.IsAnonymous())
{
formatter = (IMessagePackFormatter)DynamicObjectTypeBuilder.BuildFormatterToDynamicMethod(typeof(T), true, true, false);
return;
}
var formatterTypeInfo = DynamicObjectTypeBuilder.BuildType(assembly, typeof(T), false, false);
if (formatterTypeInfo == null) return;
formatter = (IMessagePackFormatter)Activator.CreateInstance(formatterTypeInfo.AsType());
}
}
}
///
/// ObjectResolver by dynamic code generation, allow private member.
///
public sealed class DynamicObjectResolverAllowPrivate : IFormatterResolver
{
public static readonly DynamicObjectResolverAllowPrivate Instance = new DynamicObjectResolverAllowPrivate();
DynamicObjectResolverAllowPrivate()
{
}
public IMessagePackFormatter GetFormatter()
{
return FormatterCache.formatter;
}
static class FormatterCache
{
public static readonly IMessagePackFormatter formatter;
static FormatterCache()
{
var ti = typeof(T).GetTypeInfo();
if (ti.IsInterface)
{
return;
}
if (ti.IsNullable())
{
ti = ti.GenericTypeArguments[0].GetTypeInfo();
var innerFormatter = DynamicObjectResolverAllowPrivate.Instance.GetFormatterDynamic(ti.AsType());
if (innerFormatter == null)
{
return;
}
formatter = (IMessagePackFormatter)Activator.CreateInstance(typeof(StaticNullableFormatter<>).MakeGenericType(ti.AsType()), new object[] { innerFormatter });
return;
}
if (ti.IsAnonymous())
{
formatter = (IMessagePackFormatter)DynamicObjectTypeBuilder.BuildFormatterToDynamicMethod(typeof(T), true, true, false);
}
else
{
formatter = (IMessagePackFormatter)DynamicObjectTypeBuilder.BuildFormatterToDynamicMethod(typeof(T), false, false, true);
}
}
}
}
///
/// ObjectResolver by dynamic code generation, no needs MessagePackObject attribute and serialized key as string.
///
public sealed class DynamicContractlessObjectResolver : IFormatterResolver
{
public static readonly DynamicContractlessObjectResolver Instance = new DynamicContractlessObjectResolver();
const string ModuleName = "MessagePack.Resolvers.DynamicContractlessObjectResolver";
static readonly DynamicAssembly assembly;
DynamicContractlessObjectResolver()
{
}
static DynamicContractlessObjectResolver()
{
assembly = new DynamicAssembly(ModuleName);
}
#if NET_35
public AssemblyBuilder Save()
{
return assembly.Save();
}
#endif
public IMessagePackFormatter GetFormatter()
{
return FormatterCache.formatter;
}
static class FormatterCache
{
public static readonly IMessagePackFormatter formatter;
static FormatterCache()
{
if (typeof(T) == typeof(object))
{
return;
}
var ti = typeof(T).GetTypeInfo();
if (ti.IsInterface)
{
return;
}
if (ti.IsNullable())
{
ti = ti.GenericTypeArguments[0].GetTypeInfo();
var innerFormatter = DynamicContractlessObjectResolver.Instance.GetFormatterDynamic(ti.AsType());
if (innerFormatter == null)
{
return;
}
formatter = (IMessagePackFormatter)Activator.CreateInstance(typeof(StaticNullableFormatter<>).MakeGenericType(ti.AsType()), new object[] { innerFormatter });
return;
}
if (ti.IsAnonymous())
{
formatter = (IMessagePackFormatter)DynamicObjectTypeBuilder.BuildFormatterToDynamicMethod(typeof(T), true, true, false);
return;
}
var formatterTypeInfo = DynamicObjectTypeBuilder.BuildType(assembly, typeof(T), true, true);
if (formatterTypeInfo == null) return;
formatter = (IMessagePackFormatter)Activator.CreateInstance(formatterTypeInfo.AsType());
}
}
}
///
/// ObjectResolver by dynamic code generation, no needs MessagePackObject attribute and serialized key as string, allow private member.
///
public sealed class DynamicContractlessObjectResolverAllowPrivate : IFormatterResolver
{
public static readonly DynamicContractlessObjectResolverAllowPrivate Instance = new DynamicContractlessObjectResolverAllowPrivate();
public IMessagePackFormatter GetFormatter()
{
return FormatterCache.formatter;
}
static class FormatterCache
{
public static readonly IMessagePackFormatter formatter;
static FormatterCache()
{
if (typeof(T) == typeof(object))
{
return;
}
var ti = typeof(T).GetTypeInfo();
if (ti.IsInterface)
{
return;
}
if (ti.IsNullable())
{
ti = ti.GenericTypeArguments[0].GetTypeInfo();
var innerFormatter = DynamicContractlessObjectResolverAllowPrivate.Instance.GetFormatterDynamic(ti.AsType());
if (innerFormatter == null)
{
return;
}
formatter = (IMessagePackFormatter)Activator.CreateInstance(typeof(StaticNullableFormatter<>).MakeGenericType(ti.AsType()), new object[] { innerFormatter });
return;
}
if (ti.IsAnonymous())
{
formatter = (IMessagePackFormatter)DynamicObjectTypeBuilder.BuildFormatterToDynamicMethod(typeof(T), true, true, false);
}
else
{
formatter = (IMessagePackFormatter)DynamicObjectTypeBuilder.BuildFormatterToDynamicMethod(typeof(T), true, true, true);
}
}
}
}
}
namespace MessagePack.Internal
{
internal static class DynamicObjectTypeBuilder
{
#if NETSTANDARD
static readonly Regex SubtractFullNameRegex = new Regex(@", Version=\d+.\d+.\d+.\d+, Culture=\w+, PublicKeyToken=\w+", RegexOptions.Compiled);
#else
static readonly Regex SubtractFullNameRegex = new Regex(@", Version=\d+.\d+.\d+.\d+, Culture=\w+, PublicKeyToken=\w+");
#endif
static int nameSequence = 0;
static HashSet ignoreTypes = new HashSet
{
{typeof(object)},
{typeof(short)},
{typeof(int)},
{typeof(long)},
{typeof(ushort)},
{typeof(uint)},
{typeof(ulong)},
{typeof(float)},
{typeof(double)},
{typeof(bool)},
{typeof(byte)},
{typeof(sbyte)},
{typeof(decimal)},
{typeof(char)},
{typeof(string)},
{typeof(System.Guid)},
{typeof(System.TimeSpan)},
{typeof(System.DateTime)},
{typeof(System.DateTimeOffset)},
{typeof(MessagePack.Nil)},
};
public static TypeInfo BuildType(DynamicAssembly assembly, Type type, bool forceStringKey, bool contractless)
{
if (ignoreTypes.Contains(type)) return null;
var serializationInfo = MessagePack.Internal.ObjectSerializationInfo.CreateOrNull(type, forceStringKey, contractless, false);
if (serializationInfo == null) return null;
var formatterType = typeof(IMessagePackFormatter<>).MakeGenericType(type);
var typeBuilder = assembly.DefineType("MessagePack.Formatters." + SubtractFullNameRegex.Replace(type.FullName, "").Replace(".", "_") + "Formatter" + Interlocked.Increment(ref nameSequence), TypeAttributes.Public | TypeAttributes.Sealed, null, new[] { formatterType });
FieldBuilder stringByteKeysField = null;
Dictionary customFormatterLookup = null;
// string key needs string->int mapper for deserialize switch statement
if (serializationInfo.IsStringKey)
{
var method = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes);
stringByteKeysField = typeBuilder.DefineField("stringByteKeys", typeof(byte[][]), FieldAttributes.Private | FieldAttributes.InitOnly);
var il = method.GetILGenerator();
BuildConstructor(type, serializationInfo, method, stringByteKeysField, il);
customFormatterLookup = BuildCustomFormatterField(typeBuilder, serializationInfo, il);
il.Emit(OpCodes.Ret);
}
else
{
var method = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes);
var il = method.GetILGenerator();
il.EmitLoadThis();
il.Emit(OpCodes.Call, objectCtor);
customFormatterLookup = BuildCustomFormatterField(typeBuilder, serializationInfo, il);
il.Emit(OpCodes.Ret);
}
{
var method = typeBuilder.DefineMethod("Serialize", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual,
typeof(int),
new Type[] { typeof(byte[]).MakeByRefType(), typeof(int), type, typeof(IFormatterResolver) });
var il = method.GetILGenerator();
BuildSerialize(type, serializationInfo, il, () =>
{
il.EmitLoadThis();
il.EmitLdfld(stringByteKeysField);
}, (index, member) =>
{
FieldInfo fi;
if (!customFormatterLookup.TryGetValue(member, out fi)) return null;
return () =>
{
il.EmitLoadThis();
il.EmitLdfld(fi);
};
}, 1);
}
{
var method = typeBuilder.DefineMethod("Deserialize", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual,
type,
new Type[] { typeof(byte[]), typeof(int), typeof(IFormatterResolver), typeof(int).MakeByRefType() });
var il = method.GetILGenerator();
BuildDeserialize(type, serializationInfo, il, (index, member) =>
{
FieldInfo fi;
if (!customFormatterLookup.TryGetValue(member, out fi)) return null;
return () =>
{
il.EmitLoadThis();
il.EmitLdfld(fi);
};
}, 1); // firstArgIndex:0 is this.
}
return typeBuilder.CreateTypeInfo();
}
public static object BuildFormatterToDynamicMethod(Type type, bool forceStringKey, bool contractless, bool allowPrivate)
{
var serializationInfo = ObjectSerializationInfo.CreateOrNull(type, forceStringKey, contractless, allowPrivate);
if (serializationInfo == null) return null;
// internal delegate int AnonymousSerializeFunc(byte[][] stringByteKeysField, object[] customFormatters, ref byte[] bytes, int offset, T value, IFormatterResolver resolver);
// internal delegate T AnonymousDeserializeFunc(object[] customFormatters, byte[] bytes, int offset, IFormatterResolver resolver, out int readSize);
var serialize = new DynamicMethod("Serialize", typeof(int), new[] { typeof(byte[][]), typeof(object[]), typeof(byte[]).MakeByRefType(), typeof(int), type, typeof(IFormatterResolver) }, type, true);
DynamicMethod deserialize = null;
List stringByteKeysField = new List();
List