365 lines
23 KiB
C#
365 lines
23 KiB
C#
// Copyright (c) All contributors. All rights reserved.
|
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
|
|
using System;
|
|
using System.Buffers;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Linq.Expressions;
|
|
using System.Reflection;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace MessagePack
|
|
{
|
|
public partial class MessagePackSerializer
|
|
{
|
|
private static readonly Func<Type, CompiledMethods> CreateCompiledMethods;
|
|
private static readonly MessagePack.Internal.ThreadsafeTypeKeyHashTable<CompiledMethods> Serializes = new MessagePack.Internal.ThreadsafeTypeKeyHashTable<CompiledMethods>(capacity: 64);
|
|
|
|
static MessagePackSerializer()
|
|
{
|
|
CreateCompiledMethods = t => new CompiledMethods(t);
|
|
}
|
|
|
|
/// <seealso cref="Serialize{T}(ref MessagePackWriter, T, MessagePackSerializerOptions)"/>
|
|
public static void Serialize(Type type, ref MessagePackWriter writer, object obj, MessagePackSerializerOptions options = null)
|
|
{
|
|
GetOrAdd(type).Serialize_MessagePackWriter_T_Options.Invoke(ref writer, obj, options);
|
|
}
|
|
|
|
/// <seealso cref="Serialize{T}(IBufferWriter{byte}, T, MessagePackSerializerOptions, CancellationToken)"/>
|
|
public static void Serialize(Type type, IBufferWriter<byte> writer, object obj, MessagePackSerializerOptions options = null, CancellationToken cancellationToken = default)
|
|
{
|
|
GetOrAdd(type).Serialize_IBufferWriter_T_Options_CancellationToken.Invoke(writer, obj, options, cancellationToken);
|
|
}
|
|
|
|
/// <seealso cref="Serialize{T}(T, MessagePackSerializerOptions, CancellationToken)"/>
|
|
public static byte[] Serialize(Type type, object obj, MessagePackSerializerOptions options = null, CancellationToken cancellationToken = default)
|
|
{
|
|
return GetOrAdd(type).Serialize_T_Options.Invoke(obj, options, cancellationToken);
|
|
}
|
|
|
|
/// <seealso cref="Serialize{T}(Stream, T, MessagePackSerializerOptions, CancellationToken)"/>
|
|
public static void Serialize(Type type, Stream stream, object obj, MessagePackSerializerOptions options = null, CancellationToken cancellationToken = default)
|
|
{
|
|
GetOrAdd(type).Serialize_Stream_T_Options_CancellationToken.Invoke(stream, obj, options, cancellationToken);
|
|
}
|
|
|
|
/// <seealso cref="SerializeAsync{T}(Stream, T, MessagePackSerializerOptions, CancellationToken)"/>
|
|
public static Task SerializeAsync(Type type, Stream stream, object obj, MessagePackSerializerOptions options = null, CancellationToken cancellationToken = default)
|
|
{
|
|
return GetOrAdd(type).SerializeAsync_Stream_T_Options_CancellationToken.Invoke(stream, obj, options, cancellationToken);
|
|
}
|
|
|
|
/// <seealso cref="Deserialize{T}(ref MessagePackReader, MessagePackSerializerOptions)"/>
|
|
public static object Deserialize(Type type, ref MessagePackReader reader, MessagePackSerializerOptions options = null)
|
|
{
|
|
return GetOrAdd(type).Deserialize_MessagePackReader_Options.Invoke(ref reader, options);
|
|
}
|
|
|
|
/// <seealso cref="Deserialize{T}(Stream, MessagePackSerializerOptions, CancellationToken)"/>
|
|
public static object Deserialize(Type type, Stream stream, MessagePackSerializerOptions options = null, CancellationToken cancellationToken = default)
|
|
{
|
|
return GetOrAdd(type).Deserialize_Stream_Options_CancellationToken.Invoke(stream, options, cancellationToken);
|
|
}
|
|
|
|
/// <seealso cref="DeserializeAsync{T}(Stream, MessagePackSerializerOptions, CancellationToken)"/>
|
|
public static ValueTask<object> DeserializeAsync(Type type, Stream stream, MessagePackSerializerOptions options = null, CancellationToken cancellationToken = default)
|
|
{
|
|
return GetOrAdd(type).DeserializeAsync_Stream_Options_CancellationToken.Invoke(stream, options, cancellationToken);
|
|
}
|
|
|
|
/// <seealso cref="Deserialize{T}(ReadOnlyMemory{byte}, MessagePackSerializerOptions, CancellationToken)"/>
|
|
public static object Deserialize(Type type, ReadOnlyMemory<byte> bytes, MessagePackSerializerOptions options = null, CancellationToken cancellationToken = default)
|
|
{
|
|
return GetOrAdd(type).Deserialize_ReadOnlyMemory_Options.Invoke(bytes, options, cancellationToken);
|
|
}
|
|
|
|
/// <seealso cref="Deserialize{T}(in ReadOnlySequence{byte}, MessagePackSerializerOptions, CancellationToken)"/>
|
|
public static object Deserialize(Type type, ReadOnlySequence<byte> bytes, MessagePackSerializerOptions options = null, CancellationToken cancellationToken = default)
|
|
{
|
|
return GetOrAdd(type).Deserialize_ReadOnlySequence_Options_CancellationToken.Invoke(bytes, options, cancellationToken);
|
|
}
|
|
|
|
private static async ValueTask<object> DeserializeObjectAsync<T>(Stream stream, MessagePackSerializerOptions options, CancellationToken cancellationToken) => await DeserializeAsync<T>(stream, options, cancellationToken).ConfigureAwait(false);
|
|
|
|
private static CompiledMethods GetOrAdd(Type type)
|
|
{
|
|
return Serializes.GetOrAdd(type, CreateCompiledMethods);
|
|
}
|
|
|
|
private class CompiledMethods
|
|
{
|
|
internal delegate void MessagePackWriterSerialize(ref MessagePackWriter writer, object value, MessagePackSerializerOptions options);
|
|
|
|
internal delegate object MessagePackReaderDeserialize(ref MessagePackReader reader, MessagePackSerializerOptions options);
|
|
|
|
private const bool PreferInterpretation =
|
|
#if ENABLE_IL2CPP
|
|
true;
|
|
#else
|
|
false;
|
|
#endif
|
|
|
|
#pragma warning disable SA1310 // Field names should not contain underscore
|
|
#pragma warning disable SA1307 // Accessible fields should begin with upper-case letter
|
|
#pragma warning disable SA1401 // Fields should be private
|
|
internal readonly Func<object, MessagePackSerializerOptions, CancellationToken, byte[]> Serialize_T_Options;
|
|
internal readonly Action<Stream, object, MessagePackSerializerOptions, CancellationToken> Serialize_Stream_T_Options_CancellationToken;
|
|
internal readonly Func<Stream, object, MessagePackSerializerOptions, CancellationToken, Task> SerializeAsync_Stream_T_Options_CancellationToken;
|
|
internal readonly MessagePackWriterSerialize Serialize_MessagePackWriter_T_Options;
|
|
internal readonly Action<IBufferWriter<byte>, object, MessagePackSerializerOptions, CancellationToken> Serialize_IBufferWriter_T_Options_CancellationToken;
|
|
|
|
internal readonly MessagePackReaderDeserialize Deserialize_MessagePackReader_Options;
|
|
internal readonly Func<Stream, MessagePackSerializerOptions, CancellationToken, object> Deserialize_Stream_Options_CancellationToken;
|
|
internal readonly Func<Stream, MessagePackSerializerOptions, CancellationToken, ValueTask<object>> DeserializeAsync_Stream_Options_CancellationToken;
|
|
|
|
internal readonly Func<ReadOnlyMemory<byte>, MessagePackSerializerOptions, CancellationToken, object> Deserialize_ReadOnlyMemory_Options;
|
|
internal readonly Func<ReadOnlySequence<byte>, MessagePackSerializerOptions, CancellationToken, object> Deserialize_ReadOnlySequence_Options_CancellationToken;
|
|
#pragma warning restore SA1401 // Fields should be private
|
|
#pragma warning restore SA1307 // Accessible fields should begin with upper-case letter
|
|
#pragma warning restore SA1310 // Field names should not contain underscore
|
|
|
|
internal CompiledMethods(Type type)
|
|
{
|
|
TypeInfo ti = type.GetTypeInfo();
|
|
{
|
|
// public static byte[] Serialize<T>(T obj, MessagePackSerializerOptions options, CancellationToken cancellationToken)
|
|
MethodInfo serialize = GetMethod(nameof(Serialize), type, new Type[] { null, typeof(MessagePackSerializerOptions), typeof(CancellationToken) });
|
|
#if ENABLE_IL2CPP
|
|
this.Serialize_T_Options = (x, y, z) => (byte[])serialize.Invoke(null, new object[] { x, y, z });
|
|
#else
|
|
ParameterExpression param1 = Expression.Parameter(typeof(object), "obj");
|
|
ParameterExpression param2 = Expression.Parameter(typeof(MessagePackSerializerOptions), "options");
|
|
ParameterExpression param3 = Expression.Parameter(typeof(CancellationToken), "cancellationToken");
|
|
|
|
MethodCallExpression body = Expression.Call(
|
|
null,
|
|
serialize,
|
|
ti.IsValueType ? Expression.Unbox(param1, type) : Expression.Convert(param1, type),
|
|
param2,
|
|
param3);
|
|
Func<object, MessagePackSerializerOptions, CancellationToken, byte[]> lambda = Expression.Lambda<Func<object, MessagePackSerializerOptions, CancellationToken, byte[]>>(body, param1, param2, param3).Compile(PreferInterpretation);
|
|
|
|
this.Serialize_T_Options = lambda;
|
|
#endif
|
|
}
|
|
|
|
{
|
|
// public static void Serialize<T>(Stream stream, T obj, MessagePackSerializerOptions options, CancellationToken cancellationToken)
|
|
MethodInfo serialize = GetMethod(nameof(Serialize), type, new Type[] { typeof(Stream), null, typeof(MessagePackSerializerOptions), typeof(CancellationToken) });
|
|
#if ENABLE_IL2CPP
|
|
this.Serialize_Stream_T_Options_CancellationToken = (x, y, z, a) => serialize.Invoke(null, new object[] { x, y, z, a });
|
|
#else
|
|
ParameterExpression param1 = Expression.Parameter(typeof(Stream), "stream");
|
|
ParameterExpression param2 = Expression.Parameter(typeof(object), "obj");
|
|
ParameterExpression param3 = Expression.Parameter(typeof(MessagePackSerializerOptions), "options");
|
|
ParameterExpression param4 = Expression.Parameter(typeof(CancellationToken), "cancellationToken");
|
|
|
|
MethodCallExpression body = Expression.Call(
|
|
null,
|
|
serialize,
|
|
param1,
|
|
ti.IsValueType ? Expression.Unbox(param2, type) : Expression.Convert(param2, type),
|
|
param3,
|
|
param4);
|
|
Action<Stream, object, MessagePackSerializerOptions, CancellationToken> lambda = Expression.Lambda<Action<Stream, object, MessagePackSerializerOptions, CancellationToken>>(body, param1, param2, param3, param4).Compile(PreferInterpretation);
|
|
|
|
this.Serialize_Stream_T_Options_CancellationToken = lambda;
|
|
#endif
|
|
}
|
|
|
|
{
|
|
// public static Task SerializeAsync<T>(Stream stream, T obj, MessagePackSerializerOptions options, CancellationToken cancellationToken)
|
|
MethodInfo serialize = GetMethod(nameof(SerializeAsync), type, new Type[] { typeof(Stream), null, typeof(MessagePackSerializerOptions), typeof(CancellationToken) });
|
|
#if ENABLE_IL2CPP
|
|
this.SerializeAsync_Stream_T_Options_CancellationToken = (x, y, z, a) => (Task)serialize.Invoke(null, new object[] { x, y, z, a });
|
|
#else
|
|
ParameterExpression param1 = Expression.Parameter(typeof(Stream), "stream");
|
|
ParameterExpression param2 = Expression.Parameter(typeof(object), "obj");
|
|
ParameterExpression param3 = Expression.Parameter(typeof(MessagePackSerializerOptions), "options");
|
|
ParameterExpression param4 = Expression.Parameter(typeof(CancellationToken), "cancellationToken");
|
|
|
|
MethodCallExpression body = Expression.Call(
|
|
null,
|
|
serialize,
|
|
param1,
|
|
ti.IsValueType ? Expression.Unbox(param2, type) : Expression.Convert(param2, type),
|
|
param3,
|
|
param4);
|
|
Func<Stream, object, MessagePackSerializerOptions, CancellationToken, Task> lambda = Expression.Lambda<Func<Stream, object, MessagePackSerializerOptions, CancellationToken, Task>>(body, param1, param2, param3, param4).Compile(PreferInterpretation);
|
|
|
|
this.SerializeAsync_Stream_T_Options_CancellationToken = lambda;
|
|
#endif
|
|
}
|
|
|
|
{
|
|
// public static Task Serialize<T>(IBufferWriter<byte> writer, T obj, MessagePackSerializerOptions options, CancellationToken cancellationToken)
|
|
MethodInfo serialize = GetMethod(nameof(Serialize), type, new Type[] { typeof(IBufferWriter<byte>), null, typeof(MessagePackSerializerOptions), typeof(CancellationToken) });
|
|
#if ENABLE_IL2CPP
|
|
this.Serialize_IBufferWriter_T_Options_CancellationToken = (x, y, z, a) => serialize.Invoke(null, new object[] { x, y, z, a });
|
|
#else
|
|
ParameterExpression param1 = Expression.Parameter(typeof(IBufferWriter<byte>), "writer");
|
|
ParameterExpression param2 = Expression.Parameter(typeof(object), "obj");
|
|
ParameterExpression param3 = Expression.Parameter(typeof(MessagePackSerializerOptions), "options");
|
|
ParameterExpression param4 = Expression.Parameter(typeof(CancellationToken), "cancellationToken");
|
|
|
|
MethodCallExpression body = Expression.Call(
|
|
null,
|
|
serialize,
|
|
param1,
|
|
ti.IsValueType ? Expression.Unbox(param2, type) : Expression.Convert(param2, type),
|
|
param3,
|
|
param4);
|
|
Action<IBufferWriter<byte>, object, MessagePackSerializerOptions, CancellationToken> lambda = Expression.Lambda<Action<IBufferWriter<byte>, object, MessagePackSerializerOptions, CancellationToken>>(body, param1, param2, param3, param4).Compile(PreferInterpretation);
|
|
|
|
this.Serialize_IBufferWriter_T_Options_CancellationToken = lambda;
|
|
#endif
|
|
}
|
|
|
|
{
|
|
// public static void Serialize<T>(ref MessagePackWriter writer, T obj, MessagePackSerializerOptions options)
|
|
MethodInfo serialize = GetMethod(nameof(Serialize), type, new Type[] { typeof(MessagePackWriter).MakeByRefType(), null, typeof(MessagePackSerializerOptions) });
|
|
#if ENABLE_IL2CPP
|
|
this.Serialize_MessagePackWriter_T_Options = (ref MessagePackWriter x, object y, MessagePackSerializerOptions z) => ThrowRefStructNotSupported();
|
|
#else
|
|
ParameterExpression param1 = Expression.Parameter(typeof(MessagePackWriter).MakeByRefType(), "writer");
|
|
ParameterExpression param2 = Expression.Parameter(typeof(object), "obj");
|
|
ParameterExpression param3 = Expression.Parameter(typeof(MessagePackSerializerOptions), "options");
|
|
|
|
MethodCallExpression body = Expression.Call(
|
|
null,
|
|
serialize,
|
|
param1,
|
|
ti.IsValueType ? Expression.Unbox(param2, type) : Expression.Convert(param2, type),
|
|
param3);
|
|
MessagePackWriterSerialize lambda = Expression.Lambda<MessagePackWriterSerialize>(body, param1, param2, param3).Compile(PreferInterpretation);
|
|
|
|
this.Serialize_MessagePackWriter_T_Options = lambda;
|
|
#endif
|
|
}
|
|
|
|
{
|
|
// public static T Deserialize<T>(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
|
MethodInfo deserialize = GetMethod(nameof(Deserialize), type, new Type[] { typeof(MessagePackReader).MakeByRefType(), typeof(MessagePackSerializerOptions) });
|
|
#if ENABLE_IL2CPP
|
|
this.Deserialize_MessagePackReader_Options = (ref MessagePackReader reader, MessagePackSerializerOptions options) => { ThrowRefStructNotSupported(); return null; };
|
|
#else
|
|
ParameterExpression param1 = Expression.Parameter(typeof(MessagePackReader).MakeByRefType(), "reader");
|
|
ParameterExpression param2 = Expression.Parameter(typeof(MessagePackSerializerOptions), "options");
|
|
UnaryExpression body = Expression.Convert(Expression.Call(null, deserialize, param1, param2), typeof(object));
|
|
MessagePackReaderDeserialize lambda = Expression.Lambda<MessagePackReaderDeserialize>(body, param1, param2).Compile();
|
|
|
|
this.Deserialize_MessagePackReader_Options = lambda;
|
|
#endif
|
|
}
|
|
|
|
{
|
|
// public static T Deserialize<T>(Stream stream, MessagePackSerializerOptions options, CancellationToken cancellationToken)
|
|
MethodInfo deserialize = GetMethod(nameof(Deserialize), type, new Type[] { typeof(Stream), typeof(MessagePackSerializerOptions), typeof(CancellationToken) });
|
|
#if ENABLE_IL2CPP
|
|
this.Deserialize_Stream_Options_CancellationToken = (x, y, z) => deserialize.Invoke(null, new object[] { x, y, z });
|
|
#else
|
|
ParameterExpression param1 = Expression.Parameter(typeof(Stream), "stream");
|
|
ParameterExpression param2 = Expression.Parameter(typeof(MessagePackSerializerOptions), "options");
|
|
ParameterExpression param3 = Expression.Parameter(typeof(CancellationToken), "cancellationToken");
|
|
UnaryExpression body = Expression.Convert(Expression.Call(null, deserialize, param1, param2, param3), typeof(object));
|
|
Func<Stream, MessagePackSerializerOptions, CancellationToken, object> lambda = Expression.Lambda<Func<Stream, MessagePackSerializerOptions, CancellationToken, object>>(body, param1, param2, param3).Compile(PreferInterpretation);
|
|
|
|
this.Deserialize_Stream_Options_CancellationToken = lambda;
|
|
#endif
|
|
}
|
|
|
|
{
|
|
// public static ValueTask<object> DeserializeObjectAsync<T>(Stream stream, MessagePackSerializerOptions options, CancellationToken cancellationToken)
|
|
MethodInfo deserialize = GetMethod(nameof(DeserializeObjectAsync), type, new Type[] { typeof(Stream), typeof(MessagePackSerializerOptions), typeof(CancellationToken) });
|
|
#if ENABLE_IL2CPP
|
|
this.DeserializeAsync_Stream_Options_CancellationToken = (x, y, z) => (ValueTask<object>)deserialize.Invoke(null, new object[] { x, y, z });
|
|
#else
|
|
ParameterExpression param1 = Expression.Parameter(typeof(Stream), "stream");
|
|
ParameterExpression param2 = Expression.Parameter(typeof(MessagePackSerializerOptions), "options");
|
|
ParameterExpression param3 = Expression.Parameter(typeof(CancellationToken), "cancellationToken");
|
|
UnaryExpression body = Expression.Convert(Expression.Call(null, deserialize, param1, param2, param3), typeof(ValueTask<object>));
|
|
Func<Stream, MessagePackSerializerOptions, CancellationToken, ValueTask<object>> lambda = Expression.Lambda<Func<Stream, MessagePackSerializerOptions, CancellationToken, ValueTask<object>>>(body, param1, param2, param3).Compile(PreferInterpretation);
|
|
|
|
this.DeserializeAsync_Stream_Options_CancellationToken = lambda;
|
|
#endif
|
|
}
|
|
|
|
{
|
|
// public static T Deserialize<T>(ReadOnlyMemory<byte> bytes, MessagePackSerializerOptions options, CancellationToken cancellationToken)
|
|
MethodInfo deserialize = GetMethod(nameof(Deserialize), type, new Type[] { typeof(ReadOnlyMemory<byte>), typeof(MessagePackSerializerOptions), typeof(CancellationToken) });
|
|
#if ENABLE_IL2CPP
|
|
this.Deserialize_ReadOnlyMemory_Options = (x, y, z) => deserialize.Invoke(null, new object[] { x, y, z });
|
|
#else
|
|
ParameterExpression param1 = Expression.Parameter(typeof(ReadOnlyMemory<byte>), "bytes");
|
|
ParameterExpression param2 = Expression.Parameter(typeof(MessagePackSerializerOptions), "options");
|
|
ParameterExpression param3 = Expression.Parameter(typeof(CancellationToken), "cancellationToken");
|
|
UnaryExpression body = Expression.Convert(Expression.Call(null, deserialize, param1, param2, param3), typeof(object));
|
|
Func<ReadOnlyMemory<byte>, MessagePackSerializerOptions, CancellationToken, object> lambda = Expression.Lambda<Func<ReadOnlyMemory<byte>, MessagePackSerializerOptions, CancellationToken, object>>(body, param1, param2, param3).Compile(PreferInterpretation);
|
|
|
|
this.Deserialize_ReadOnlyMemory_Options = lambda;
|
|
#endif
|
|
}
|
|
|
|
{
|
|
// public static T Deserialize<T>(ReadOnlySequence<byte> bytes, MessagePackSerializerOptions options, CancellationToken cancellationToken)
|
|
MethodInfo deserialize = GetMethod(nameof(Deserialize), type, new Type[] { typeof(ReadOnlySequence<byte>).MakeByRefType(), typeof(MessagePackSerializerOptions), typeof(CancellationToken) });
|
|
#if ENABLE_IL2CPP
|
|
this.Deserialize_ReadOnlySequence_Options_CancellationToken = (x, y, z) => deserialize.Invoke(null, new object[] { x, y, z });
|
|
#else
|
|
ParameterExpression param1 = Expression.Parameter(typeof(ReadOnlySequence<byte>), "bytes");
|
|
ParameterExpression param2 = Expression.Parameter(typeof(MessagePackSerializerOptions), "options");
|
|
ParameterExpression param3 = Expression.Parameter(typeof(CancellationToken), "cancellationToken");
|
|
UnaryExpression body = Expression.Convert(Expression.Call(null, deserialize, param1, param2, param3), typeof(object));
|
|
Func<ReadOnlySequence<byte>, MessagePackSerializerOptions, CancellationToken, object> lambda = Expression.Lambda<Func<ReadOnlySequence<byte>, MessagePackSerializerOptions, CancellationToken, object>>(body, param1, param2, param3).Compile(PreferInterpretation);
|
|
|
|
this.Deserialize_ReadOnlySequence_Options_CancellationToken = lambda;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
private static void ThrowRefStructNotSupported()
|
|
{
|
|
// C# 8.0 is not supported call `ref struct` via reflection. (It is milestoned at .NET 6)
|
|
throw new NotSupportedException("MessagePackWriter/Reader overload is not supported in MessagePackSerializer.NonGenerics.");
|
|
}
|
|
|
|
// null is generic type marker.
|
|
private static MethodInfo GetMethod(string methodName, Type type, Type[] parameters)
|
|
{
|
|
return typeof(MessagePackSerializer).GetRuntimeMethods().Single(x =>
|
|
{
|
|
if (methodName != x.Name)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
ParameterInfo[] ps = x.GetParameters();
|
|
if (ps.Length != parameters.Length)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (int i = 0; i < ps.Length; i++)
|
|
{
|
|
if (parameters[i] == null && ps[i].ParameterType.IsGenericParameter)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (ps[i].ParameterType != parameters[i])
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
})
|
|
.MakeGenericMethod(type);
|
|
}
|
|
}
|
|
}
|
|
}
|