Initial Client/Server Communication
#1 Followed the MagicOnion quickstart guide, borrowing code from the chat sample app to get something working
This commit is contained in:
parent
52b0d4d8ff
commit
a0c8dbee72
493 changed files with 57790 additions and 3 deletions
|
|
@ -0,0 +1,57 @@
|
|||
// 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.Linq; // require UNITY_2018_3_OR_NEWER
|
||||
using System.Reflection;
|
||||
using MessagePack.Formatters;
|
||||
|
||||
namespace MessagePack.Resolvers
|
||||
{
|
||||
/// <summary>
|
||||
/// Get formatter from <see cref="MessagePackFormatterAttribute"/>.
|
||||
/// </summary>
|
||||
public sealed class AttributeFormatterResolver : IFormatterResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// The singleton instance that can be used.
|
||||
/// </summary>
|
||||
public static readonly AttributeFormatterResolver Instance = new AttributeFormatterResolver();
|
||||
|
||||
private AttributeFormatterResolver()
|
||||
{
|
||||
}
|
||||
|
||||
public IMessagePackFormatter<T> GetFormatter<T>()
|
||||
{
|
||||
return FormatterCache<T>.Formatter;
|
||||
}
|
||||
|
||||
private static class FormatterCache<T>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<T> Formatter;
|
||||
|
||||
static FormatterCache()
|
||||
{
|
||||
#if UNITY_2018_3_OR_NEWER && !NETFX_CORE
|
||||
var attr = (MessagePackFormatterAttribute)typeof(T).GetCustomAttributes(typeof(MessagePackFormatterAttribute), true).FirstOrDefault();
|
||||
#else
|
||||
MessagePackFormatterAttribute attr = typeof(T).GetTypeInfo().GetCustomAttribute<MessagePackFormatterAttribute>();
|
||||
#endif
|
||||
if (attr == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (attr.Arguments == null)
|
||||
{
|
||||
Formatter = (IMessagePackFormatter<T>)Activator.CreateInstance(attr.FormatterType);
|
||||
}
|
||||
else
|
||||
{
|
||||
Formatter = (IMessagePackFormatter<T>)Activator.CreateInstance(attr.FormatterType, attr.Arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f1da7b0fb18e1d4e79aeb7ac56ba9607
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
159
Assets/Scripts/MessagePack/Resolvers/BuiltinResolver.cs
Normal file
159
Assets/Scripts/MessagePack/Resolvers/BuiltinResolver.cs
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
// 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.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using MessagePack.Formatters;
|
||||
using MessagePack.Internal;
|
||||
using MessagePack.Resolvers;
|
||||
|
||||
#pragma warning disable SA1403 // File may only contain a single namespace
|
||||
#pragma warning disable SA1509 // Opening braces should not be preceded by blank line
|
||||
|
||||
namespace MessagePack.Resolvers
|
||||
{
|
||||
public sealed class BuiltinResolver : IFormatterResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// The singleton instance that can be used.
|
||||
/// </summary>
|
||||
public static readonly BuiltinResolver Instance = new BuiltinResolver();
|
||||
|
||||
private BuiltinResolver()
|
||||
{
|
||||
}
|
||||
|
||||
public IMessagePackFormatter<T> GetFormatter<T>()
|
||||
{
|
||||
return FormatterCache<T>.Formatter;
|
||||
}
|
||||
|
||||
private static class FormatterCache<T>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<T> Formatter;
|
||||
|
||||
static FormatterCache()
|
||||
{
|
||||
// Reduce IL2CPP code generate size(don't write long code in <T>)
|
||||
Formatter = (IMessagePackFormatter<T>)BuiltinResolverGetFormatterHelper.GetFormatter(typeof(T));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace MessagePack.Internal
|
||||
{
|
||||
internal static class BuiltinResolverGetFormatterHelper
|
||||
{
|
||||
private static readonly Dictionary<Type, object> FormatterMap = new Dictionary<Type, object>()
|
||||
{
|
||||
// Primitive
|
||||
{ typeof(Int16), Int16Formatter.Instance },
|
||||
{ typeof(Int32), Int32Formatter.Instance },
|
||||
{ typeof(Int64), Int64Formatter.Instance },
|
||||
{ typeof(UInt16), UInt16Formatter.Instance },
|
||||
{ typeof(UInt32), UInt32Formatter.Instance },
|
||||
{ typeof(UInt64), UInt64Formatter.Instance },
|
||||
{ typeof(Single), SingleFormatter.Instance },
|
||||
{ typeof(Double), DoubleFormatter.Instance },
|
||||
{ typeof(bool), BooleanFormatter.Instance },
|
||||
{ typeof(byte), ByteFormatter.Instance },
|
||||
{ typeof(sbyte), SByteFormatter.Instance },
|
||||
{ typeof(DateTime), DateTimeFormatter.Instance },
|
||||
{ typeof(char), CharFormatter.Instance },
|
||||
|
||||
// Nulllable Primitive
|
||||
{ typeof(Int16?), NullableInt16Formatter.Instance },
|
||||
{ typeof(Int32?), NullableInt32Formatter.Instance },
|
||||
{ typeof(Int64?), NullableInt64Formatter.Instance },
|
||||
{ typeof(UInt16?), NullableUInt16Formatter.Instance },
|
||||
{ typeof(UInt32?), NullableUInt32Formatter.Instance },
|
||||
{ typeof(UInt64?), NullableUInt64Formatter.Instance },
|
||||
{ typeof(Single?), NullableSingleFormatter.Instance },
|
||||
{ typeof(Double?), NullableDoubleFormatter.Instance },
|
||||
{ typeof(bool?), NullableBooleanFormatter.Instance },
|
||||
{ typeof(byte?), NullableByteFormatter.Instance },
|
||||
{ typeof(sbyte?), NullableSByteFormatter.Instance },
|
||||
{ typeof(DateTime?), NullableDateTimeFormatter.Instance },
|
||||
{ typeof(char?), NullableCharFormatter.Instance },
|
||||
|
||||
// StandardClassLibraryFormatter
|
||||
{ typeof(string), NullableStringFormatter.Instance },
|
||||
{ typeof(decimal), DecimalFormatter.Instance },
|
||||
{ typeof(decimal?), new StaticNullableFormatter<decimal>(DecimalFormatter.Instance) },
|
||||
{ typeof(TimeSpan), TimeSpanFormatter.Instance },
|
||||
{ typeof(TimeSpan?), new StaticNullableFormatter<TimeSpan>(TimeSpanFormatter.Instance) },
|
||||
{ typeof(DateTimeOffset), DateTimeOffsetFormatter.Instance },
|
||||
{ typeof(DateTimeOffset?), new StaticNullableFormatter<DateTimeOffset>(DateTimeOffsetFormatter.Instance) },
|
||||
{ typeof(Guid), GuidFormatter.Instance },
|
||||
{ typeof(Guid?), new StaticNullableFormatter<Guid>(GuidFormatter.Instance) },
|
||||
{ typeof(Uri), UriFormatter.Instance },
|
||||
{ typeof(Version), VersionFormatter.Instance },
|
||||
{ typeof(StringBuilder), StringBuilderFormatter.Instance },
|
||||
{ typeof(BitArray), BitArrayFormatter.Instance },
|
||||
|
||||
// special primitive
|
||||
{ typeof(byte[]), ByteArrayFormatter.Instance },
|
||||
|
||||
// Nil
|
||||
{ typeof(Nil), NilFormatter.Instance },
|
||||
{ typeof(Nil?), NullableNilFormatter.Instance },
|
||||
|
||||
// otpmitized primitive array formatter
|
||||
{ typeof(Int16[]), Int16ArrayFormatter.Instance },
|
||||
{ typeof(Int32[]), Int32ArrayFormatter.Instance },
|
||||
{ typeof(Int64[]), Int64ArrayFormatter.Instance },
|
||||
{ typeof(UInt16[]), UInt16ArrayFormatter.Instance },
|
||||
{ typeof(UInt32[]), UInt32ArrayFormatter.Instance },
|
||||
{ typeof(UInt64[]), UInt64ArrayFormatter.Instance },
|
||||
{ typeof(Single[]), SingleArrayFormatter.Instance },
|
||||
{ typeof(Double[]), DoubleArrayFormatter.Instance },
|
||||
{ typeof(Boolean[]), BooleanArrayFormatter.Instance },
|
||||
{ typeof(SByte[]), SByteArrayFormatter.Instance },
|
||||
{ typeof(DateTime[]), DateTimeArrayFormatter.Instance },
|
||||
{ typeof(Char[]), CharArrayFormatter.Instance },
|
||||
{ typeof(string[]), NullableStringArrayFormatter.Instance },
|
||||
|
||||
// well known collections
|
||||
{ typeof(List<Int16>), new ListFormatter<Int16>() },
|
||||
{ typeof(List<Int32>), new ListFormatter<Int32>() },
|
||||
{ typeof(List<Int64>), new ListFormatter<Int64>() },
|
||||
{ typeof(List<UInt16>), new ListFormatter<UInt16>() },
|
||||
{ typeof(List<UInt32>), new ListFormatter<UInt32>() },
|
||||
{ typeof(List<UInt64>), new ListFormatter<UInt64>() },
|
||||
{ typeof(List<Single>), new ListFormatter<Single>() },
|
||||
{ typeof(List<Double>), new ListFormatter<Double>() },
|
||||
{ typeof(List<Boolean>), new ListFormatter<Boolean>() },
|
||||
{ typeof(List<byte>), new ListFormatter<byte>() },
|
||||
{ typeof(List<SByte>), new ListFormatter<SByte>() },
|
||||
{ typeof(List<DateTime>), new ListFormatter<DateTime>() },
|
||||
{ typeof(List<Char>), new ListFormatter<Char>() },
|
||||
{ typeof(List<string>), new ListFormatter<string>() },
|
||||
|
||||
{ typeof(object[]), new ArrayFormatter<object>() },
|
||||
{ typeof(List<object>), new ListFormatter<object>() },
|
||||
|
||||
{ typeof(ArraySegment<byte>), ByteArraySegmentFormatter.Instance },
|
||||
{ typeof(ArraySegment<byte>?), new StaticNullableFormatter<ArraySegment<byte>>(ByteArraySegmentFormatter.Instance) },
|
||||
|
||||
{ typeof(System.Numerics.BigInteger), BigIntegerFormatter.Instance },
|
||||
{ typeof(System.Numerics.BigInteger?), new StaticNullableFormatter<System.Numerics.BigInteger>(BigIntegerFormatter.Instance) },
|
||||
{ typeof(System.Numerics.Complex), ComplexFormatter.Instance },
|
||||
{ typeof(System.Numerics.Complex?), new StaticNullableFormatter<System.Numerics.Complex>(ComplexFormatter.Instance) },
|
||||
};
|
||||
|
||||
internal static object GetFormatter(Type t)
|
||||
{
|
||||
object formatter;
|
||||
if (FormatterMap.TryGetValue(t, out formatter))
|
||||
{
|
||||
return formatter;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/MessagePack/Resolvers/BuiltinResolver.cs.meta
Normal file
11
Assets/Scripts/MessagePack/Resolvers/BuiltinResolver.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 22f2bfd36b9810653baff3342b3403e7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using MessagePack.Formatters;
|
||||
using MessagePack.Internal;
|
||||
|
||||
namespace MessagePack.Resolvers
|
||||
{
|
||||
/// <summary>
|
||||
/// A base class for <see cref="IFormatterResolver"/> classes that want to cache their responses for perf reasons.
|
||||
/// </summary>
|
||||
internal abstract class CachingFormatterResolver : IFormatterResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// The cache of types to their formatters.
|
||||
/// </summary>
|
||||
private readonly ThreadsafeTypeKeyHashTable<IMessagePackFormatter> formatters = new ThreadsafeTypeKeyHashTable<IMessagePackFormatter>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IMessagePackFormatter<T> GetFormatter<T>()
|
||||
{
|
||||
if (!this.formatters.TryGetValue(typeof(T), out IMessagePackFormatter formatter))
|
||||
{
|
||||
formatter = this.GetFormatterCore<T>();
|
||||
this.formatters.TryAdd(typeof(T), formatter);
|
||||
}
|
||||
|
||||
return (IMessagePackFormatter<T>)formatter;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a formatter for a type that has not been previously cached.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to be formatted.</typeparam>
|
||||
/// <returns>The formatter to use, or <c>null</c> if none found.</returns>
|
||||
protected abstract IMessagePackFormatter<T> GetFormatterCore<T>();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 961f65a9ca79040c5b3021c7612f3c08
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
108
Assets/Scripts/MessagePack/Resolvers/CompositeResolver.cs
Normal file
108
Assets/Scripts/MessagePack/Resolvers/CompositeResolver.cs
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
// 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.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using MessagePack.Formatters;
|
||||
using MessagePack.Internal;
|
||||
|
||||
namespace MessagePack.Resolvers
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a collection of formatters and resolvers acting as one.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class is not thread-safe for mutations. It is thread-safe when not being written to.
|
||||
/// </remarks>
|
||||
public static class CompositeResolver
|
||||
{
|
||||
private static readonly ReadOnlyDictionary<Type, IMessagePackFormatter> EmptyFormattersByType = new ReadOnlyDictionary<Type, IMessagePackFormatter>(new Dictionary<Type, IMessagePackFormatter>());
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of an <see cref="IFormatterResolver"/> with the specified formatters and sub-resolvers.
|
||||
/// </summary>
|
||||
/// <param name="formatters">
|
||||
/// A list of instances of <see cref="IMessagePackFormatter{T}"/> to prefer (above the <paramref name="resolvers"/>).
|
||||
/// The formatters are searched in the order given, so if two formatters support serializing the same type, the first one is used.
|
||||
/// May not be null, but may be <see cref="Array.Empty{T}"/>.
|
||||
/// </param>
|
||||
/// <param name="resolvers">
|
||||
/// A list of resolvers to use for serializing types for which <paramref name="formatters"/> does not include a formatter.
|
||||
/// The resolvers are searched in the order given, so if two resolvers support serializing the same type, the first one is used.
|
||||
/// May not be null, but may be <see cref="Array.Empty{T}"/>.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// An instance of <see cref="IFormatterResolver"/>.
|
||||
/// </returns>
|
||||
public static IFormatterResolver Create(IReadOnlyList<IMessagePackFormatter> formatters, IReadOnlyList<IFormatterResolver> resolvers)
|
||||
{
|
||||
if (formatters is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(formatters));
|
||||
}
|
||||
|
||||
if (resolvers is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(resolvers));
|
||||
}
|
||||
|
||||
// Make a copy of the resolvers list provided by the caller to guard against them changing it later.
|
||||
var immutableFormatters = formatters.ToArray();
|
||||
var immutableResolvers = resolvers.ToArray();
|
||||
|
||||
return new CachingResolver(immutableFormatters, immutableResolvers);
|
||||
}
|
||||
|
||||
public static IFormatterResolver Create(params IFormatterResolver[] resolvers) => Create(Array.Empty<IMessagePackFormatter>(), resolvers);
|
||||
|
||||
public static IFormatterResolver Create(params IMessagePackFormatter[] formatters) => Create(formatters, Array.Empty<IFormatterResolver>());
|
||||
|
||||
private class CachingResolver : IFormatterResolver
|
||||
{
|
||||
private readonly ThreadsafeTypeKeyHashTable<IMessagePackFormatter> formattersCache = new ThreadsafeTypeKeyHashTable<IMessagePackFormatter>();
|
||||
private readonly IMessagePackFormatter[] subFormatters;
|
||||
private readonly IFormatterResolver[] subResolvers;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CachingResolver"/> class.
|
||||
/// </summary>
|
||||
internal CachingResolver(IMessagePackFormatter[] subFormatters, IFormatterResolver[] subResolvers)
|
||||
{
|
||||
this.subFormatters = subFormatters ?? throw new ArgumentNullException(nameof(subFormatters));
|
||||
this.subResolvers = subResolvers ?? throw new ArgumentNullException(nameof(subResolvers));
|
||||
}
|
||||
|
||||
public IMessagePackFormatter<T> GetFormatter<T>()
|
||||
{
|
||||
if (!this.formattersCache.TryGetValue(typeof(T), out IMessagePackFormatter formatter))
|
||||
{
|
||||
foreach (var subFormatter in this.subFormatters)
|
||||
{
|
||||
if (subFormatter is IMessagePackFormatter<T>)
|
||||
{
|
||||
formatter = subFormatter;
|
||||
goto CACHE;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (IFormatterResolver resolver in this.subResolvers)
|
||||
{
|
||||
formatter = resolver.GetFormatter<T>();
|
||||
if (formatter != null)
|
||||
{
|
||||
goto CACHE;
|
||||
}
|
||||
}
|
||||
|
||||
// when not found, cache null.
|
||||
CACHE:
|
||||
this.formattersCache.TryAdd(typeof(T), formatter);
|
||||
}
|
||||
|
||||
return (IMessagePackFormatter<T>)formatter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ed6833da3299a096c923be585b3372a1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,302 @@
|
|||
// 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.Collections.Generic;
|
||||
using System.Text;
|
||||
using MessagePack.Formatters;
|
||||
using MessagePack.Internal;
|
||||
|
||||
namespace MessagePack.Resolvers
|
||||
{
|
||||
// MEMO: Not completely implemented.
|
||||
|
||||
////public static class ContractlessReflectionObjectResolver
|
||||
////{
|
||||
//// // TODO:CamelCase Option? AllowPrivate?
|
||||
//// public static readonly IFormatterResolver Default = new DefaultResolver();
|
||||
//// public static readonly IFormatterResolver Contractless = new ContractlessResolver();
|
||||
//// public static readonly IFormatterResolver ContractlessForceStringKey = new ContractlessForceStringResolver();
|
||||
|
||||
//// class DefaultResolver : IFormatterResolver
|
||||
//// {
|
||||
//// const bool ForceStringKey = false;
|
||||
//// const bool Contractless = false;
|
||||
//// const bool AllowPrivate = false;
|
||||
|
||||
//// public IMessagePackFormatter<T> GetFormatter<T>()
|
||||
//// {
|
||||
//// return Cache<T>.formatter;
|
||||
//// }
|
||||
|
||||
//// static class Cache<T>
|
||||
//// {
|
||||
//// public static readonly IMessagePackFormatter<T> formatter;
|
||||
|
||||
//// static Cache()
|
||||
//// {
|
||||
//// var metaInfo = ObjectSerializationInfo.CreateOrNull(typeof(T), ForceStringKey, Contractless, AllowPrivate);
|
||||
//// if (metaInfo != null)
|
||||
//// {
|
||||
//// formatter = new ReflectionObjectFormatter<T>(metaInfo);
|
||||
//// }
|
||||
//// }
|
||||
//// }
|
||||
//// }
|
||||
|
||||
//// class ContractlessResolver : IFormatterResolver
|
||||
//// {
|
||||
//// const bool ForceStringKey = false;
|
||||
//// const bool Contractless = true;
|
||||
//// const bool AllowPrivate = false;
|
||||
|
||||
//// public IMessagePackFormatter<T> GetFormatter<T>()
|
||||
//// {
|
||||
//// return Cache<T>.formatter;
|
||||
//// }
|
||||
|
||||
//// static class Cache<T>
|
||||
//// {
|
||||
//// public static readonly IMessagePackFormatter<T> formatter;
|
||||
|
||||
//// static Cache()
|
||||
//// {
|
||||
//// var metaInfo = ObjectSerializationInfo.CreateOrNull(typeof(T), ForceStringKey, Contractless, AllowPrivate);
|
||||
//// if (metaInfo != null)
|
||||
//// {
|
||||
//// formatter = new ReflectionObjectFormatter<T>(metaInfo);
|
||||
//// }
|
||||
//// }
|
||||
//// }
|
||||
//// }
|
||||
|
||||
//// class ContractlessForceStringResolver : IFormatterResolver
|
||||
//// {
|
||||
//// const bool ForceStringKey = true;
|
||||
//// const bool Contractless = true;
|
||||
//// const bool AllowPrivate = false;
|
||||
|
||||
//// public IMessagePackFormatter<T> GetFormatter<T>()
|
||||
//// {
|
||||
//// return Cache<T>.formatter;
|
||||
//// }
|
||||
|
||||
//// static class Cache<T>
|
||||
//// {
|
||||
//// public static readonly IMessagePackFormatter<T> formatter;
|
||||
|
||||
//// static Cache()
|
||||
//// {
|
||||
//// var metaInfo = ObjectSerializationInfo.CreateOrNull(typeof(T), ForceStringKey, Contractless, AllowPrivate);
|
||||
//// if (metaInfo != null)
|
||||
//// {
|
||||
//// formatter = new ReflectionObjectFormatter<T>(metaInfo);
|
||||
//// }
|
||||
//// }
|
||||
//// }
|
||||
//// }
|
||||
|
||||
////}
|
||||
|
||||
////public class ReflectionObjectFormatter<T> : IMessagePackFormatter<T>
|
||||
////{
|
||||
//// readonly ObjectSerializationInfo metaInfo;
|
||||
|
||||
//// // for write
|
||||
//// readonly byte[][] writeMemberNames;
|
||||
//// readonly ObjectSerializationInfo.EmittableMember[] writeMembers;
|
||||
|
||||
//// // for read
|
||||
//// readonly int[] constructorParameterIndexes;
|
||||
//// readonly AutomataDictionary mapMemberDictionary;
|
||||
//// readonly ObjectSerializationInfo.EmittableMember[] readMembers;
|
||||
|
||||
//// internal ReflectionObjectFormatter(ObjectSerializationInfo metaInfo)
|
||||
//// {
|
||||
//// this.metaInfo = metaInfo;
|
||||
|
||||
//// // for write
|
||||
//// {
|
||||
//// var memberNameList = new List<byte[]>(metaInfo.Members.Length);
|
||||
//// var emmitableMemberList = new List<ObjectSerializationInfo.EmittableMember>(metaInfo.Members.Length);
|
||||
//// foreach (var item in metaInfo.Members)
|
||||
//// {
|
||||
//// if (item.IsWritable)
|
||||
//// {
|
||||
//// emmitableMemberList.Add(item);
|
||||
//// memberNameList.Add(Encoding.UTF8.GetBytes(item.Name));
|
||||
//// }
|
||||
//// }
|
||||
//// this.writeMemberNames = memberNameList.ToArray();
|
||||
//// this.writeMembers = emmitableMemberList.ToArray();
|
||||
//// }
|
||||
//// // for read
|
||||
//// {
|
||||
//// var automata = new AutomataDictionary();
|
||||
//// var emmitableMemberList = new List<ObjectSerializationInfo.EmittableMember>(metaInfo.Members.Length);
|
||||
//// int index = 0;
|
||||
//// foreach (var item in metaInfo.Members)
|
||||
//// {
|
||||
//// if (item.IsReadable)
|
||||
//// {
|
||||
//// emmitableMemberList.Add(item);
|
||||
//// automata.Add(item.Name, index++);
|
||||
//// }
|
||||
//// }
|
||||
//// this.readMembers = emmitableMemberList.ToArray();
|
||||
//// this.mapMemberDictionary = automata;
|
||||
//// }
|
||||
//// }
|
||||
|
||||
//// public void Serialize(ref MessagePackWriter writer, T value, MessagePackSerializerOptions options)
|
||||
//// {
|
||||
//// // reduce generic method size, avoid write code in <T> type.
|
||||
//// if (metaInfo.IsIntKey)
|
||||
//// {
|
||||
//// return ReflectionObjectFormatterHelper.WriteArraySerialize(metaInfo, writeMembers, ref bytes, offset, value, formatterResolver);
|
||||
//// }
|
||||
//// else
|
||||
//// {
|
||||
//// return ReflectionObjectFormatterHelper.WriteMapSerialize(metaInfo, writeMembers, writeMemberNames, ref bytes, offset, value, formatterResolver);
|
||||
//// }
|
||||
//// }
|
||||
|
||||
//// public T Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
//// {
|
||||
//// return (T)ReflectionObjectFormatterHelper.Deserialize(metaInfo, readMembers, constructorParameterIndexes, mapMemberDictionary, bytes, offset, formatterResolver, out readSize);
|
||||
//// }
|
||||
////}
|
||||
|
||||
////internal static class ReflectionObjectFormatterHelper
|
||||
////{
|
||||
//// internal static int WriteArraySerialize(ObjectSerializationInfo metaInfo, ObjectSerializationInfo.EmittableMember[] writeMembers, ref byte[] bytes, int offset, object value, IFormatterResolver formatterResolver)
|
||||
//// {
|
||||
//// var startOffset = offset;
|
||||
|
||||
//// offset += MessagePackBinary.WriteArrayHeader(ref bytes, offset, writeMembers.Length);
|
||||
//// foreach (var item in metaInfo.Members)
|
||||
//// {
|
||||
//// if (item == null)
|
||||
//// {
|
||||
//// offset += MessagePackBinary.WriteNil(ref bytes, offset);
|
||||
//// }
|
||||
//// else
|
||||
//// {
|
||||
//// var memberValue = item.ReflectionLoadValue(value);
|
||||
//// offset += MessagePackSerializer.NonGeneric.Serialize(item.Type, ref bytes, offset, memberValue, formatterResolver);
|
||||
//// }
|
||||
//// }
|
||||
|
||||
//// return offset - startOffset;
|
||||
//// }
|
||||
|
||||
//// internal static int WriteMapSerialize(ObjectSerializationInfo metaInfo, ObjectSerializationInfo.EmittableMember[] writeMembers, byte[][] memberNames, ref byte[] bytes, int offset, object value, IFormatterResolver formatterResolver)
|
||||
//// {
|
||||
//// var startOffset = offset;
|
||||
|
||||
//// offset += MessagePackBinary.WriteMapHeader(ref bytes, offset, writeMembers.Length);
|
||||
|
||||
//// for (int i = 0; i < writeMembers.Length; i++)
|
||||
//// {
|
||||
//// offset += MessagePackBinary.WriteStringBytes(ref bytes, offset, memberNames[i]);
|
||||
//// var memberValue = writeMembers[i].ReflectionLoadValue(value);
|
||||
//// offset += MessagePackSerializer.NonGeneric.Serialize(writeMembers[i].Type, ref bytes, offset, memberValue, formatterResolver);
|
||||
//// }
|
||||
|
||||
//// return offset - startOffset;
|
||||
//// }
|
||||
|
||||
//// internal static object Deserialize(ObjectSerializationInfo metaInfo, ObjectSerializationInfo.EmittableMember[] readMembers, int[] constructorParameterIndexes, AutomataDictionary mapMemberDictionary, byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize)
|
||||
//// {
|
||||
//// var startOffset = offset;
|
||||
//// object[] parameters = null;
|
||||
|
||||
//// var headerType = MessagePackBinary.GetMessagePackType(bytes, offset);
|
||||
//// if (headerType == MessagePackType.Nil)
|
||||
//// {
|
||||
//// readSize = 1;
|
||||
//// return null;
|
||||
//// }
|
||||
//// else if (headerType == MessagePackType.Array)
|
||||
//// {
|
||||
//// var arraySize = MessagePackBinary.ReadArrayHeader(bytes, offset, out readSize);
|
||||
//// offset += readSize;
|
||||
|
||||
//// // ReadValues
|
||||
//// parameters = new object[arraySize];
|
||||
//// for (int i = 0; i < arraySize; i++)
|
||||
//// {
|
||||
//// var info = readMembers[i];
|
||||
//// if (info != null)
|
||||
//// {
|
||||
//// parameters[i] = MessagePackSerializer.NonGeneric.Deserialize(info.Type, bytes, offset, formatterResolver, out readSize);
|
||||
//// offset += readSize;
|
||||
//// }
|
||||
//// else
|
||||
//// {
|
||||
//// offset += MessagePackBinary.ReadNextBlock(bytes, offset);
|
||||
//// }
|
||||
//// }
|
||||
//// }
|
||||
//// else if (headerType == MessagePackType.Map)
|
||||
//// {
|
||||
//// var mapSize = MessagePackBinary.ReadMapHeader(bytes, offset, out readSize);
|
||||
//// offset += readSize;
|
||||
|
||||
//// // ReadValues
|
||||
//// parameters = new object[mapSize];
|
||||
//// for (int i = 0; i < mapSize; i++)
|
||||
//// {
|
||||
//// var rawPropName = MessagePackBinary.ReadStringSegment(bytes, offset, out readSize);
|
||||
//// offset += readSize;
|
||||
|
||||
//// int index;
|
||||
//// if (mapMemberDictionary.TryGetValue(rawPropName.Array, rawPropName.Offset, rawPropName.Count, out index))
|
||||
//// {
|
||||
//// var info = readMembers[index];
|
||||
//// parameters[index] = MessagePackSerializer.NonGeneric.Deserialize(info.Type, bytes, offset, formatterResolver, out readSize);
|
||||
//// offset += readSize;
|
||||
//// }
|
||||
//// else
|
||||
//// {
|
||||
//// offset += MessagePackBinary.ReadNextBlock(bytes, offset);
|
||||
//// }
|
||||
//// }
|
||||
//// }
|
||||
//// else
|
||||
//// {
|
||||
//// throw new MessagePackSerializationException("Invalid MessagePackType:" + MessagePackCode.ToFormatName(bytes[offset]));
|
||||
//// }
|
||||
|
||||
//// // CreateObject
|
||||
//// object result = null;
|
||||
//// if (constructorParameterIndexes.Length == 0)
|
||||
//// {
|
||||
//// result = Activator.CreateInstance(metaInfo.Type);
|
||||
//// }
|
||||
//// else
|
||||
//// {
|
||||
//// var args = new object[constructorParameterIndexes.Length];
|
||||
//// for (int i = 0; i < constructorParameterIndexes.Length; i++)
|
||||
//// {
|
||||
//// args[i] = parameters[constructorParameterIndexes[i]];
|
||||
//// }
|
||||
|
||||
//// result = Activator.CreateInstance(metaInfo.Type, args);
|
||||
//// }
|
||||
|
||||
//// // SetMembers
|
||||
//// for (int i = 0; i < readMembers.Length; i++)
|
||||
//// {
|
||||
//// var info = readMembers[i];
|
||||
//// if (info != null)
|
||||
//// {
|
||||
//// info.ReflectionStoreValue(result, parameters[i]);
|
||||
//// }
|
||||
//// }
|
||||
|
||||
//// readSize = offset - startOffset;
|
||||
//// return result;
|
||||
//// }
|
||||
////}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 953431b29940de61a8da84acda591d9e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
// 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.Reflection;
|
||||
using MessagePack.Formatters;
|
||||
using MessagePack.Internal;
|
||||
|
||||
namespace MessagePack.Resolvers
|
||||
{
|
||||
public sealed class DynamicEnumAsStringResolver : IFormatterResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// The singleton instance that can be used.
|
||||
/// </summary>
|
||||
public static readonly DynamicEnumAsStringResolver Instance;
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="MessagePackSerializerOptions"/> instance with this formatter pre-configured.
|
||||
/// </summary>
|
||||
public static readonly MessagePackSerializerOptions Options;
|
||||
|
||||
static DynamicEnumAsStringResolver()
|
||||
{
|
||||
Instance = new DynamicEnumAsStringResolver();
|
||||
Options = new MessagePackSerializerOptions(Instance);
|
||||
}
|
||||
|
||||
private DynamicEnumAsStringResolver()
|
||||
{
|
||||
}
|
||||
|
||||
public IMessagePackFormatter<T> GetFormatter<T>()
|
||||
{
|
||||
return FormatterCache<T>.Formatter;
|
||||
}
|
||||
|
||||
private static class FormatterCache<T>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<T> Formatter;
|
||||
|
||||
static FormatterCache()
|
||||
{
|
||||
TypeInfo ti = typeof(T).GetTypeInfo();
|
||||
|
||||
if (ti.IsNullable())
|
||||
{
|
||||
// build underlying type and use wrapped formatter.
|
||||
ti = ti.GenericTypeArguments[0].GetTypeInfo();
|
||||
if (!ti.IsEnum)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var innerFormatter = DynamicEnumAsStringResolver.Instance.GetFormatterDynamic(ti.AsType());
|
||||
if (innerFormatter == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Formatter = (IMessagePackFormatter<T>)Activator.CreateInstance(typeof(StaticNullableFormatter<>).MakeGenericType(ti.AsType()), new object[] { innerFormatter });
|
||||
return;
|
||||
}
|
||||
else if (!ti.IsEnum)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Formatter = (IMessagePackFormatter<T>)(object)new EnumAsStringFormatter<T>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 54a09685d140ed621bbd779af8f4e6cc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
129
Assets/Scripts/MessagePack/Resolvers/DynamicEnumResolver.cs
Normal file
129
Assets/Scripts/MessagePack/Resolvers/DynamicEnumResolver.cs
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#if !(UNITY_2018_3_OR_NEWER && NET_STANDARD_2_0)
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Threading;
|
||||
using MessagePack.Formatters;
|
||||
using MessagePack.Internal;
|
||||
|
||||
namespace MessagePack.Resolvers
|
||||
{
|
||||
/// <summary>
|
||||
/// EnumResolver by dynamic code generation, serialized underlying type.
|
||||
/// </summary>
|
||||
public sealed class DynamicEnumResolver : IFormatterResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// The singleton instance that can be used.
|
||||
/// </summary>
|
||||
public static readonly DynamicEnumResolver Instance = new DynamicEnumResolver();
|
||||
|
||||
private const string ModuleName = "MessagePack.Resolvers.DynamicEnumResolver";
|
||||
|
||||
private static readonly DynamicAssembly DynamicAssembly;
|
||||
|
||||
private static int nameSequence = 0;
|
||||
|
||||
private DynamicEnumResolver()
|
||||
{
|
||||
}
|
||||
|
||||
static DynamicEnumResolver()
|
||||
{
|
||||
DynamicAssembly = new DynamicAssembly(ModuleName);
|
||||
}
|
||||
|
||||
#if NETFRAMEWORK
|
||||
public AssemblyBuilder Save()
|
||||
{
|
||||
return DynamicAssembly.Save();
|
||||
}
|
||||
#endif
|
||||
|
||||
public IMessagePackFormatter<T> GetFormatter<T>()
|
||||
{
|
||||
return FormatterCache<T>.Formatter;
|
||||
}
|
||||
|
||||
private static class FormatterCache<T>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<T> Formatter;
|
||||
|
||||
static FormatterCache()
|
||||
{
|
||||
TypeInfo ti = typeof(T).GetTypeInfo();
|
||||
if (ti.IsNullable())
|
||||
{
|
||||
// build underlying type and use wrapped formatter.
|
||||
ti = ti.GenericTypeArguments[0].GetTypeInfo();
|
||||
if (!ti.IsEnum)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var innerFormatter = DynamicEnumResolver.Instance.GetFormatterDynamic(ti.AsType());
|
||||
if (innerFormatter == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Formatter = (IMessagePackFormatter<T>)Activator.CreateInstance(typeof(StaticNullableFormatter<>).MakeGenericType(ti.AsType()), new object[] { innerFormatter });
|
||||
return;
|
||||
}
|
||||
else if (!ti.IsEnum)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TypeInfo formatterTypeInfo = BuildType(typeof(T));
|
||||
Formatter = (IMessagePackFormatter<T>)Activator.CreateInstance(formatterTypeInfo.AsType());
|
||||
}
|
||||
}
|
||||
|
||||
private static TypeInfo BuildType(Type enumType)
|
||||
{
|
||||
Type underlyingType = Enum.GetUnderlyingType(enumType);
|
||||
Type formatterType = typeof(IMessagePackFormatter<>).MakeGenericType(enumType);
|
||||
|
||||
TypeBuilder typeBuilder = DynamicAssembly.DefineType("MessagePack.Formatters." + enumType.FullName.Replace(".", "_") + "Formatter" + Interlocked.Increment(ref nameSequence), TypeAttributes.Public | TypeAttributes.Sealed, null, new[] { formatterType });
|
||||
|
||||
// void Serialize(ref MessagePackWriter writer, T value, MessagePackSerializerOptions options);
|
||||
{
|
||||
MethodBuilder method = typeBuilder.DefineMethod(
|
||||
"Serialize",
|
||||
MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual,
|
||||
null,
|
||||
new Type[] { typeof(MessagePackWriter).MakeByRefType(), enumType, typeof(MessagePackSerializerOptions) });
|
||||
|
||||
ILGenerator il = method.GetILGenerator();
|
||||
il.Emit(OpCodes.Ldarg_1);
|
||||
il.Emit(OpCodes.Ldarg_2);
|
||||
il.Emit(OpCodes.Call, typeof(MessagePackWriter).GetRuntimeMethod(nameof(MessagePackWriter.Write), new[] { underlyingType }));
|
||||
il.Emit(OpCodes.Ret);
|
||||
}
|
||||
|
||||
// T Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options);
|
||||
{
|
||||
MethodBuilder method = typeBuilder.DefineMethod(
|
||||
"Deserialize",
|
||||
MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual,
|
||||
enumType,
|
||||
new Type[] { typeof(MessagePackReader).MakeByRefType(), typeof(MessagePackSerializerOptions) });
|
||||
|
||||
ILGenerator il = method.GetILGenerator();
|
||||
il.Emit(OpCodes.Ldarg_1);
|
||||
il.Emit(OpCodes.Call, typeof(MessagePackReader).GetRuntimeMethod("Read" + underlyingType.Name, Type.EmptyTypes));
|
||||
il.Emit(OpCodes.Ret);
|
||||
}
|
||||
|
||||
return typeBuilder.CreateTypeInfo();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 56f454cdc164d6a03bcb2dd11fa9e73a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
284
Assets/Scripts/MessagePack/Resolvers/DynamicGenericResolver.cs
Normal file
284
Assets/Scripts/MessagePack/Resolvers/DynamicGenericResolver.cs
Normal file
|
|
@ -0,0 +1,284 @@
|
|||
// 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.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using MessagePack.Formatters;
|
||||
using MessagePack.Internal;
|
||||
|
||||
#pragma warning disable SA1403 // File may only contain a single namespace
|
||||
|
||||
namespace MessagePack.Resolvers
|
||||
{
|
||||
public sealed class DynamicGenericResolver : IFormatterResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// The singleton instance that can be used.
|
||||
/// </summary>
|
||||
public static readonly DynamicGenericResolver Instance = new DynamicGenericResolver();
|
||||
|
||||
private DynamicGenericResolver()
|
||||
{
|
||||
}
|
||||
|
||||
public IMessagePackFormatter<T> GetFormatter<T>()
|
||||
{
|
||||
return FormatterCache<T>.Formatter;
|
||||
}
|
||||
|
||||
private static class FormatterCache<T>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<T> Formatter;
|
||||
|
||||
static FormatterCache()
|
||||
{
|
||||
Formatter = (IMessagePackFormatter<T>)DynamicGenericResolverGetFormatterHelper.GetFormatter(typeof(T));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace MessagePack.Internal
|
||||
{
|
||||
internal static class DynamicGenericResolverGetFormatterHelper
|
||||
{
|
||||
private static readonly Dictionary<Type, Type> FormatterMap = new Dictionary<Type, Type>()
|
||||
{
|
||||
{ typeof(List<>), typeof(ListFormatter<>) },
|
||||
{ typeof(LinkedList<>), typeof(LinkedListFormatter<>) },
|
||||
{ typeof(Queue<>), typeof(QueueFormatter<>) },
|
||||
{ typeof(Stack<>), typeof(StackFormatter<>) },
|
||||
{ typeof(HashSet<>), typeof(HashSetFormatter<>) },
|
||||
{ typeof(ReadOnlyCollection<>), typeof(ReadOnlyCollectionFormatter<>) },
|
||||
{ typeof(IList<>), typeof(InterfaceListFormatter2<>) },
|
||||
{ typeof(ICollection<>), typeof(InterfaceCollectionFormatter2<>) },
|
||||
{ typeof(IEnumerable<>), typeof(InterfaceEnumerableFormatter<>) },
|
||||
{ typeof(Dictionary<,>), typeof(DictionaryFormatter<,>) },
|
||||
{ typeof(IDictionary<,>), typeof(InterfaceDictionaryFormatter<,>) },
|
||||
{ typeof(SortedDictionary<,>), typeof(SortedDictionaryFormatter<,>) },
|
||||
{ typeof(SortedList<,>), typeof(SortedListFormatter<,>) },
|
||||
{ typeof(ILookup<,>), typeof(InterfaceLookupFormatter<,>) },
|
||||
{ typeof(IGrouping<,>), typeof(InterfaceGroupingFormatter<,>) },
|
||||
{ typeof(ObservableCollection<>), typeof(ObservableCollectionFormatter<>) },
|
||||
{ typeof(ReadOnlyObservableCollection<>), typeof(ReadOnlyObservableCollectionFormatter<>) },
|
||||
{ typeof(IReadOnlyList<>), typeof(InterfaceReadOnlyListFormatter<>) },
|
||||
{ typeof(IReadOnlyCollection<>), typeof(InterfaceReadOnlyCollectionFormatter<>) },
|
||||
{ typeof(ISet<>), typeof(InterfaceSetFormatter<>) },
|
||||
{ typeof(System.Collections.Concurrent.ConcurrentBag<>), typeof(ConcurrentBagFormatter<>) },
|
||||
{ typeof(System.Collections.Concurrent.ConcurrentQueue<>), typeof(ConcurrentQueueFormatter<>) },
|
||||
{ typeof(System.Collections.Concurrent.ConcurrentStack<>), typeof(ConcurrentStackFormatter<>) },
|
||||
{ typeof(ReadOnlyDictionary<,>), typeof(ReadOnlyDictionaryFormatter<,>) },
|
||||
{ typeof(IReadOnlyDictionary<,>), typeof(InterfaceReadOnlyDictionaryFormatter<,>) },
|
||||
{ typeof(System.Collections.Concurrent.ConcurrentDictionary<,>), typeof(ConcurrentDictionaryFormatter<,>) },
|
||||
{ typeof(Lazy<>), typeof(LazyFormatter<>) },
|
||||
};
|
||||
|
||||
// Reduce IL2CPP code generate size(don't write long code in <T>)
|
||||
internal static object GetFormatter(Type t)
|
||||
{
|
||||
TypeInfo ti = t.GetTypeInfo();
|
||||
|
||||
if (t.IsArray)
|
||||
{
|
||||
var rank = t.GetArrayRank();
|
||||
if (rank == 1)
|
||||
{
|
||||
if (t.GetElementType() == typeof(byte))
|
||||
{
|
||||
// byte[] is also supported in builtin formatter.
|
||||
return ByteArrayFormatter.Instance;
|
||||
}
|
||||
|
||||
return Activator.CreateInstance(typeof(ArrayFormatter<>).MakeGenericType(t.GetElementType()));
|
||||
}
|
||||
else if (rank == 2)
|
||||
{
|
||||
return Activator.CreateInstance(typeof(TwoDimensionalArrayFormatter<>).MakeGenericType(t.GetElementType()));
|
||||
}
|
||||
else if (rank == 3)
|
||||
{
|
||||
return Activator.CreateInstance(typeof(ThreeDimensionalArrayFormatter<>).MakeGenericType(t.GetElementType()));
|
||||
}
|
||||
else if (rank == 4)
|
||||
{
|
||||
return Activator.CreateInstance(typeof(FourDimensionalArrayFormatter<>).MakeGenericType(t.GetElementType()));
|
||||
}
|
||||
else
|
||||
{
|
||||
return null; // not supported built-in
|
||||
}
|
||||
}
|
||||
else if (ti.IsGenericType)
|
||||
{
|
||||
Type genericType = ti.GetGenericTypeDefinition();
|
||||
TypeInfo genericTypeInfo = genericType.GetTypeInfo();
|
||||
var isNullable = genericTypeInfo.IsNullable();
|
||||
Type nullableElementType = isNullable ? ti.GenericTypeArguments[0] : null;
|
||||
|
||||
if (genericType == typeof(KeyValuePair<,>))
|
||||
{
|
||||
return CreateInstance(typeof(KeyValuePairFormatter<,>), ti.GenericTypeArguments);
|
||||
}
|
||||
|
||||
// Tuple
|
||||
else if (ti.FullName.StartsWith("System.Tuple"))
|
||||
{
|
||||
Type tupleFormatterType = null;
|
||||
switch (ti.GenericTypeArguments.Length)
|
||||
{
|
||||
case 1:
|
||||
tupleFormatterType = typeof(TupleFormatter<>);
|
||||
break;
|
||||
case 2:
|
||||
tupleFormatterType = typeof(TupleFormatter<,>);
|
||||
break;
|
||||
case 3:
|
||||
tupleFormatterType = typeof(TupleFormatter<,,>);
|
||||
break;
|
||||
case 4:
|
||||
tupleFormatterType = typeof(TupleFormatter<,,,>);
|
||||
break;
|
||||
case 5:
|
||||
tupleFormatterType = typeof(TupleFormatter<,,,,>);
|
||||
break;
|
||||
case 6:
|
||||
tupleFormatterType = typeof(TupleFormatter<,,,,,>);
|
||||
break;
|
||||
case 7:
|
||||
tupleFormatterType = typeof(TupleFormatter<,,,,,,>);
|
||||
break;
|
||||
case 8:
|
||||
tupleFormatterType = typeof(TupleFormatter<,,,,,,,>);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return CreateInstance(tupleFormatterType, ti.GenericTypeArguments);
|
||||
}
|
||||
|
||||
// ValueTuple
|
||||
else if (ti.FullName.StartsWith("System.ValueTuple"))
|
||||
{
|
||||
Type tupleFormatterType = null;
|
||||
switch (ti.GenericTypeArguments.Length)
|
||||
{
|
||||
case 1:
|
||||
tupleFormatterType = typeof(ValueTupleFormatter<>);
|
||||
break;
|
||||
case 2:
|
||||
tupleFormatterType = typeof(ValueTupleFormatter<,>);
|
||||
break;
|
||||
case 3:
|
||||
tupleFormatterType = typeof(ValueTupleFormatter<,,>);
|
||||
break;
|
||||
case 4:
|
||||
tupleFormatterType = typeof(ValueTupleFormatter<,,,>);
|
||||
break;
|
||||
case 5:
|
||||
tupleFormatterType = typeof(ValueTupleFormatter<,,,,>);
|
||||
break;
|
||||
case 6:
|
||||
tupleFormatterType = typeof(ValueTupleFormatter<,,,,,>);
|
||||
break;
|
||||
case 7:
|
||||
tupleFormatterType = typeof(ValueTupleFormatter<,,,,,,>);
|
||||
break;
|
||||
case 8:
|
||||
tupleFormatterType = typeof(ValueTupleFormatter<,,,,,,,>);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return CreateInstance(tupleFormatterType, ti.GenericTypeArguments);
|
||||
}
|
||||
|
||||
// ArraySegement
|
||||
else if (genericType == typeof(ArraySegment<>))
|
||||
{
|
||||
if (ti.GenericTypeArguments[0] == typeof(byte))
|
||||
{
|
||||
return ByteArraySegmentFormatter.Instance;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CreateInstance(typeof(ArraySegmentFormatter<>), ti.GenericTypeArguments);
|
||||
}
|
||||
}
|
||||
|
||||
// Standard Nullable
|
||||
else if (isNullable)
|
||||
{
|
||||
return CreateInstance(typeof(NullableFormatter<>), new[] { nullableElementType });
|
||||
}
|
||||
|
||||
// Mapped formatter
|
||||
else
|
||||
{
|
||||
Type formatterType;
|
||||
if (FormatterMap.TryGetValue(genericType, out formatterType))
|
||||
{
|
||||
return CreateInstance(formatterType, ti.GenericTypeArguments);
|
||||
}
|
||||
|
||||
// generic collection
|
||||
else if (ti.GenericTypeArguments.Length == 1
|
||||
&& ti.ImplementedInterfaces.Any(x => x.GetTypeInfo().IsConstructedGenericType() && x.GetGenericTypeDefinition() == typeof(ICollection<>))
|
||||
&& ti.DeclaredConstructors.Any(x => x.GetParameters().Length == 0))
|
||||
{
|
||||
Type elemType = ti.GenericTypeArguments[0];
|
||||
return CreateInstance(typeof(GenericCollectionFormatter<,>), new[] { elemType, t });
|
||||
}
|
||||
|
||||
// generic dictionary
|
||||
else if (ti.GenericTypeArguments.Length == 2
|
||||
&& ti.ImplementedInterfaces.Any(x => x.GetTypeInfo().IsConstructedGenericType() && x.GetGenericTypeDefinition() == typeof(IDictionary<,>))
|
||||
&& ti.DeclaredConstructors.Any(x => x.GetParameters().Length == 0))
|
||||
{
|
||||
Type keyType = ti.GenericTypeArguments[0];
|
||||
Type valueType = ti.GenericTypeArguments[1];
|
||||
return CreateInstance(typeof(GenericDictionaryFormatter<,,>), new[] { keyType, valueType, t });
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ti.IsEnum)
|
||||
{
|
||||
return CreateInstance(typeof(GenericEnumFormatter<>), new[] { t });
|
||||
}
|
||||
else
|
||||
{
|
||||
// NonGeneric Collection
|
||||
if (t == typeof(IList))
|
||||
{
|
||||
return NonGenericInterfaceListFormatter.Instance;
|
||||
}
|
||||
else if (t == typeof(IDictionary))
|
||||
{
|
||||
return NonGenericInterfaceDictionaryFormatter.Instance;
|
||||
}
|
||||
|
||||
if (typeof(IList).GetTypeInfo().IsAssignableFrom(ti) && ti.DeclaredConstructors.Any(x => x.GetParameters().Length == 0))
|
||||
{
|
||||
return Activator.CreateInstance(typeof(NonGenericListFormatter<>).MakeGenericType(t));
|
||||
}
|
||||
else if (typeof(IDictionary).GetTypeInfo().IsAssignableFrom(ti) && ti.DeclaredConstructors.Any(x => x.GetParameters().Length == 0))
|
||||
{
|
||||
return Activator.CreateInstance(typeof(NonGenericDictionaryFormatter<>).MakeGenericType(t));
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static object CreateInstance(Type genericType, Type[] genericTypeArguments, params object[] arguments)
|
||||
{
|
||||
return Activator.CreateInstance(genericType.MakeGenericType(genericTypeArguments), arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c97d6b550962b8536b1363db3bd98cae
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
2071
Assets/Scripts/MessagePack/Resolvers/DynamicObjectResolver.cs
Normal file
2071
Assets/Scripts/MessagePack/Resolvers/DynamicObjectResolver.cs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 14db1290355a2f56a919749640cbcc7c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
517
Assets/Scripts/MessagePack/Resolvers/DynamicUnionResolver.cs
Normal file
517
Assets/Scripts/MessagePack/Resolvers/DynamicUnionResolver.cs
Normal file
|
|
@ -0,0 +1,517 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#if !(UNITY_2018_3_OR_NEWER && NET_STANDARD_2_0)
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using MessagePack.Formatters;
|
||||
using MessagePack.Internal;
|
||||
|
||||
#pragma warning disable SA1403 // File may only contain a single namespace
|
||||
#pragma warning disable SA1509 // Opening braces should not be preceded by blank line
|
||||
|
||||
namespace MessagePack.Resolvers
|
||||
{
|
||||
/// <summary>
|
||||
/// UnionResolver by dynamic code generation.
|
||||
/// </summary>
|
||||
public sealed class DynamicUnionResolver : IFormatterResolver
|
||||
{
|
||||
private const string ModuleName = "MessagePack.Resolvers.DynamicUnionResolver";
|
||||
|
||||
/// <summary>
|
||||
/// The singleton instance that can be used.
|
||||
/// </summary>
|
||||
public static readonly DynamicUnionResolver Instance;
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="MessagePackSerializerOptions"/> instance with this formatter pre-configured.
|
||||
/// </summary>
|
||||
public static readonly MessagePackSerializerOptions Options;
|
||||
|
||||
private static readonly DynamicAssembly DynamicAssembly;
|
||||
#if !UNITY_2018_3_OR_NEWER
|
||||
private static readonly Regex SubtractFullNameRegex = new Regex(@", Version=\d+.\d+.\d+.\d+, Culture=\w+, PublicKeyToken=\w+", RegexOptions.Compiled);
|
||||
#else
|
||||
private static readonly Regex SubtractFullNameRegex = new Regex(@", Version=\d+.\d+.\d+.\d+, Culture=\w+, PublicKeyToken=\w+");
|
||||
#endif
|
||||
|
||||
private static int nameSequence = 0;
|
||||
|
||||
static DynamicUnionResolver()
|
||||
{
|
||||
Instance = new DynamicUnionResolver();
|
||||
Options = new MessagePackSerializerOptions(Instance);
|
||||
DynamicAssembly = new DynamicAssembly(ModuleName);
|
||||
}
|
||||
|
||||
private DynamicUnionResolver()
|
||||
{
|
||||
}
|
||||
|
||||
#if NETFRAMEWORK
|
||||
public AssemblyBuilder Save()
|
||||
{
|
||||
return DynamicAssembly.Save();
|
||||
}
|
||||
#endif
|
||||
|
||||
public IMessagePackFormatter<T> GetFormatter<T>()
|
||||
{
|
||||
return FormatterCache<T>.Formatter;
|
||||
}
|
||||
|
||||
private static class FormatterCache<T>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<T> Formatter;
|
||||
|
||||
static FormatterCache()
|
||||
{
|
||||
TypeInfo ti = typeof(T).GetTypeInfo();
|
||||
if (ti.IsNullable())
|
||||
{
|
||||
ti = ti.GenericTypeArguments[0].GetTypeInfo();
|
||||
|
||||
var innerFormatter = DynamicUnionResolver.Instance.GetFormatterDynamic(ti.AsType());
|
||||
if (innerFormatter == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Formatter = (IMessagePackFormatter<T>)Activator.CreateInstance(typeof(StaticNullableFormatter<>).MakeGenericType(ti.AsType()), new object[] { innerFormatter });
|
||||
return;
|
||||
}
|
||||
|
||||
TypeInfo formatterTypeInfo = BuildType(typeof(T));
|
||||
if (formatterTypeInfo == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Formatter = (IMessagePackFormatter<T>)Activator.CreateInstance(formatterTypeInfo.AsType());
|
||||
}
|
||||
}
|
||||
|
||||
private static TypeInfo BuildType(Type type)
|
||||
{
|
||||
TypeInfo ti = type.GetTypeInfo();
|
||||
|
||||
// order by key(important for use jump-table of switch)
|
||||
UnionAttribute[] unionAttrs = ti.GetCustomAttributes<UnionAttribute>().OrderBy(x => x.Key).ToArray();
|
||||
|
||||
if (unionAttrs.Length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!ti.IsInterface && !ti.IsAbstract)
|
||||
{
|
||||
throw new MessagePackDynamicUnionResolverException("Union can only be interface or abstract class. Type:" + type.Name);
|
||||
}
|
||||
|
||||
var checker1 = new HashSet<int>();
|
||||
var checker2 = new HashSet<Type>();
|
||||
foreach (UnionAttribute item in unionAttrs)
|
||||
{
|
||||
if (!checker1.Add(item.Key))
|
||||
{
|
||||
throw new MessagePackDynamicUnionResolverException("Same union key has found. Type:" + type.Name + " Key:" + item.Key);
|
||||
}
|
||||
|
||||
if (!checker2.Add(item.SubType))
|
||||
{
|
||||
throw new MessagePackDynamicUnionResolverException("Same union subType has found. Type:" + type.Name + " SubType: " + item.SubType);
|
||||
}
|
||||
}
|
||||
|
||||
Type formatterType = typeof(IMessagePackFormatter<>).MakeGenericType(type);
|
||||
TypeBuilder typeBuilder = DynamicAssembly.DefineType("MessagePack.Formatters." + SubtractFullNameRegex.Replace(type.FullName, string.Empty).Replace(".", "_") + "Formatter" + +Interlocked.Increment(ref nameSequence), TypeAttributes.Public | TypeAttributes.Sealed, null, new[] { formatterType });
|
||||
|
||||
FieldBuilder typeToKeyAndJumpMap = null; // Dictionary<RuntimeTypeHandle, KeyValuePair<int, int>>
|
||||
FieldBuilder keyToJumpMap = null; // Dictionary<int, int>
|
||||
|
||||
// create map dictionary
|
||||
{
|
||||
ConstructorBuilder method = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes);
|
||||
typeToKeyAndJumpMap = typeBuilder.DefineField("typeToKeyAndJumpMap", typeof(Dictionary<RuntimeTypeHandle, KeyValuePair<int, int>>), FieldAttributes.Private | FieldAttributes.InitOnly);
|
||||
keyToJumpMap = typeBuilder.DefineField("keyToJumpMap", typeof(Dictionary<int, int>), FieldAttributes.Private | FieldAttributes.InitOnly);
|
||||
|
||||
ILGenerator il = method.GetILGenerator();
|
||||
BuildConstructor(type, unionAttrs, method, typeToKeyAndJumpMap, keyToJumpMap, il);
|
||||
}
|
||||
|
||||
{
|
||||
MethodBuilder method = typeBuilder.DefineMethod(
|
||||
"Serialize",
|
||||
MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.NewSlot,
|
||||
null,
|
||||
new Type[] { typeof(MessagePackWriter).MakeByRefType(), type, typeof(MessagePackSerializerOptions) });
|
||||
|
||||
ILGenerator il = method.GetILGenerator();
|
||||
BuildSerialize(type, unionAttrs, method, typeToKeyAndJumpMap, il);
|
||||
}
|
||||
|
||||
{
|
||||
MethodBuilder method = typeBuilder.DefineMethod(
|
||||
"Deserialize",
|
||||
MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.NewSlot,
|
||||
type,
|
||||
new Type[] { refMessagePackReader, typeof(MessagePackSerializerOptions) });
|
||||
|
||||
ILGenerator il = method.GetILGenerator();
|
||||
BuildDeserialize(type, unionAttrs, method, keyToJumpMap, il);
|
||||
}
|
||||
|
||||
return typeBuilder.CreateTypeInfo();
|
||||
}
|
||||
|
||||
private static void BuildConstructor(Type type, UnionAttribute[] infos, ConstructorInfo method, FieldBuilder typeToKeyAndJumpMap, FieldBuilder keyToJumpMap, ILGenerator il)
|
||||
{
|
||||
il.EmitLdarg(0);
|
||||
il.Emit(OpCodes.Call, objectCtor);
|
||||
|
||||
{
|
||||
il.EmitLdarg(0);
|
||||
il.EmitLdc_I4(infos.Length);
|
||||
il.Emit(OpCodes.Ldsfld, runtimeTypeHandleEqualityComparer);
|
||||
il.Emit(OpCodes.Newobj, typeMapDictionaryConstructor);
|
||||
|
||||
var index = 0;
|
||||
foreach (UnionAttribute item in infos)
|
||||
{
|
||||
il.Emit(OpCodes.Dup);
|
||||
il.Emit(OpCodes.Ldtoken, item.SubType);
|
||||
il.EmitLdc_I4(item.Key);
|
||||
il.EmitLdc_I4(index);
|
||||
il.Emit(OpCodes.Newobj, intIntKeyValuePairConstructor);
|
||||
il.EmitCall(typeMapDictionaryAdd);
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
il.Emit(OpCodes.Stfld, typeToKeyAndJumpMap);
|
||||
}
|
||||
|
||||
{
|
||||
il.EmitLdarg(0);
|
||||
il.EmitLdc_I4(infos.Length);
|
||||
il.Emit(OpCodes.Newobj, keyMapDictionaryConstructor);
|
||||
|
||||
var index = 0;
|
||||
foreach (UnionAttribute item in infos)
|
||||
{
|
||||
il.Emit(OpCodes.Dup);
|
||||
il.EmitLdc_I4(item.Key);
|
||||
il.EmitLdc_I4(index);
|
||||
il.EmitCall(keyMapDictionaryAdd);
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
il.Emit(OpCodes.Stfld, keyToJumpMap);
|
||||
}
|
||||
|
||||
il.Emit(OpCodes.Ret);
|
||||
}
|
||||
|
||||
// void Serialize([arg:1]MessagePackWriter writer, [arg:2]T value, [arg:3]MessagePackSerializerOptions options);
|
||||
private static void BuildSerialize(Type type, UnionAttribute[] infos, MethodBuilder method, FieldBuilder typeToKeyAndJumpMap, ILGenerator il)
|
||||
{
|
||||
// if(value == null) return WriteNil
|
||||
Label elseBody = il.DefineLabel();
|
||||
Label notFoundType = il.DefineLabel();
|
||||
|
||||
il.EmitLdarg(2);
|
||||
il.Emit(OpCodes.Brtrue_S, elseBody);
|
||||
il.Emit(OpCodes.Br, notFoundType);
|
||||
il.MarkLabel(elseBody);
|
||||
|
||||
// IFormatterResolver resolver = options.Resolver;
|
||||
LocalBuilder localResolver = il.DeclareLocal(typeof(IFormatterResolver));
|
||||
il.EmitLdarg(3);
|
||||
il.EmitCall(getResolverFromOptions);
|
||||
il.EmitStloc(localResolver);
|
||||
|
||||
LocalBuilder keyPair = il.DeclareLocal(typeof(KeyValuePair<int, int>));
|
||||
|
||||
il.EmitLoadThis();
|
||||
il.EmitLdfld(typeToKeyAndJumpMap);
|
||||
il.EmitLdarg(2);
|
||||
il.EmitCall(objectGetType);
|
||||
il.EmitCall(getTypeHandle);
|
||||
il.EmitLdloca(keyPair);
|
||||
il.EmitCall(typeMapDictionaryTryGetValue);
|
||||
il.Emit(OpCodes.Brfalse, notFoundType);
|
||||
|
||||
// writer.WriteArrayHeader(2, false);
|
||||
il.EmitLdarg(1);
|
||||
il.EmitLdc_I4(2);
|
||||
il.EmitCall(MessagePackWriterTypeInfo.WriteArrayHeader);
|
||||
|
||||
// writer.Write(keyPair.Key)
|
||||
il.EmitLdarg(1);
|
||||
il.EmitLdloca(keyPair);
|
||||
il.EmitCall(intIntKeyValuePairGetKey);
|
||||
il.EmitCall(MessagePackWriterTypeInfo.WriteInt32);
|
||||
|
||||
Label loopEnd = il.DefineLabel();
|
||||
|
||||
// switch-case (offset += resolver.GetFormatter.Serialize(with cast)
|
||||
var switchLabels = infos.Select(x => new { Label = il.DefineLabel(), Attr = x }).ToArray();
|
||||
il.EmitLdloca(keyPair);
|
||||
il.EmitCall(intIntKeyValuePairGetValue);
|
||||
il.Emit(OpCodes.Switch, switchLabels.Select(x => x.Label).ToArray());
|
||||
il.Emit(OpCodes.Br, loopEnd); // default
|
||||
|
||||
foreach (var item in switchLabels)
|
||||
{
|
||||
il.MarkLabel(item.Label);
|
||||
il.EmitLdloc(localResolver);
|
||||
il.Emit(OpCodes.Call, getFormatterWithVerify.MakeGenericMethod(item.Attr.SubType));
|
||||
|
||||
il.EmitLdarg(1);
|
||||
il.EmitLdarg(2);
|
||||
if (item.Attr.SubType.GetTypeInfo().IsValueType)
|
||||
{
|
||||
il.Emit(OpCodes.Unbox_Any, item.Attr.SubType);
|
||||
}
|
||||
else
|
||||
{
|
||||
il.Emit(OpCodes.Castclass, item.Attr.SubType);
|
||||
}
|
||||
|
||||
il.EmitLdarg(3);
|
||||
il.Emit(OpCodes.Callvirt, getSerialize(item.Attr.SubType));
|
||||
|
||||
il.Emit(OpCodes.Br, loopEnd);
|
||||
}
|
||||
|
||||
// return;
|
||||
il.MarkLabel(loopEnd);
|
||||
il.Emit(OpCodes.Ret);
|
||||
|
||||
// else, return WriteNil
|
||||
il.MarkLabel(notFoundType);
|
||||
il.EmitLdarg(1);
|
||||
il.EmitCall(MessagePackWriterTypeInfo.WriteNil);
|
||||
il.Emit(OpCodes.Ret);
|
||||
}
|
||||
|
||||
// T Deserialize([arg:1]ref MessagePackReader reader, [arg:2]MessagePackSerializerOptions options);
|
||||
private static void BuildDeserialize(Type type, UnionAttribute[] infos, MethodBuilder method, FieldBuilder keyToJumpMap, ILGenerator il)
|
||||
{
|
||||
// if(MessagePackBinary.TryReadNil()) { return null; }
|
||||
Label falseLabel = il.DefineLabel();
|
||||
il.EmitLdarg(1);
|
||||
il.EmitCall(MessagePackReaderTypeInfo.TryReadNil);
|
||||
il.Emit(OpCodes.Brfalse_S, falseLabel);
|
||||
|
||||
il.Emit(OpCodes.Ldnull);
|
||||
il.Emit(OpCodes.Ret);
|
||||
|
||||
il.MarkLabel(falseLabel);
|
||||
|
||||
// IFormatterResolver resolver = options.Resolver;
|
||||
LocalBuilder localResolver = il.DeclareLocal(typeof(IFormatterResolver));
|
||||
il.EmitLdarg(2);
|
||||
il.EmitCall(getResolverFromOptions);
|
||||
il.EmitStloc(localResolver);
|
||||
|
||||
// read-array header and validate, reader.ReadArrayHeader() != 2) throw;
|
||||
Label rightLabel = il.DefineLabel();
|
||||
var writer = new ArgumentField(il, 1);
|
||||
writer.EmitLdarg();
|
||||
il.EmitCall(MessagePackReaderTypeInfo.ReadArrayHeader);
|
||||
il.EmitLdc_I4(2);
|
||||
il.Emit(OpCodes.Beq_S, rightLabel);
|
||||
il.Emit(OpCodes.Ldstr, "Invalid Union data was detected. Type:" + type.FullName);
|
||||
il.Emit(OpCodes.Newobj, invalidOperationExceptionConstructor);
|
||||
il.Emit(OpCodes.Throw);
|
||||
|
||||
il.MarkLabel(rightLabel);
|
||||
|
||||
// read key
|
||||
LocalBuilder key = il.DeclareLocal(typeof(int));
|
||||
writer.EmitLdarg();
|
||||
il.EmitCall(MessagePackReaderTypeInfo.ReadInt32);
|
||||
il.EmitStloc(key);
|
||||
|
||||
// is-sequential don't need else convert key to jump-table value
|
||||
if (!IsZeroStartSequential(infos))
|
||||
{
|
||||
Label endKeyMapGet = il.DefineLabel();
|
||||
il.EmitLdarg(0);
|
||||
il.EmitLdfld(keyToJumpMap);
|
||||
il.EmitLdloc(key);
|
||||
il.EmitLdloca(key);
|
||||
il.EmitCall(keyMapDictionaryTryGetValue);
|
||||
il.Emit(OpCodes.Brtrue_S, endKeyMapGet);
|
||||
il.EmitLdc_I4(-1);
|
||||
il.EmitStloc(key);
|
||||
|
||||
il.MarkLabel(endKeyMapGet);
|
||||
}
|
||||
|
||||
// switch->read
|
||||
LocalBuilder result = il.DeclareLocal(type);
|
||||
Label loopEnd = il.DefineLabel();
|
||||
il.Emit(OpCodes.Ldnull);
|
||||
il.EmitStloc(result);
|
||||
il.Emit(OpCodes.Ldloc, key);
|
||||
|
||||
var switchLabels = infos.Select(x => new { Label = il.DefineLabel(), Attr = x }).ToArray();
|
||||
il.Emit(OpCodes.Switch, switchLabels.Select(x => x.Label).ToArray());
|
||||
|
||||
// default
|
||||
writer.EmitLdarg();
|
||||
il.EmitCall(MessagePackReaderTypeInfo.Skip);
|
||||
il.Emit(OpCodes.Br, loopEnd);
|
||||
|
||||
foreach (var item in switchLabels)
|
||||
{
|
||||
il.MarkLabel(item.Label);
|
||||
il.EmitLdloc(localResolver);
|
||||
il.EmitCall(getFormatterWithVerify.MakeGenericMethod(item.Attr.SubType));
|
||||
il.EmitLdarg(1);
|
||||
il.EmitLdarg(2);
|
||||
il.EmitCall(getDeserialize(item.Attr.SubType));
|
||||
if (item.Attr.SubType.GetTypeInfo().IsValueType)
|
||||
{
|
||||
il.Emit(OpCodes.Box, item.Attr.SubType);
|
||||
}
|
||||
|
||||
il.Emit(OpCodes.Stloc, result);
|
||||
il.Emit(OpCodes.Br, loopEnd);
|
||||
}
|
||||
|
||||
il.MarkLabel(loopEnd);
|
||||
|
||||
il.Emit(OpCodes.Ldloc, result);
|
||||
il.Emit(OpCodes.Ret);
|
||||
}
|
||||
|
||||
private static bool IsZeroStartSequential(UnionAttribute[] infos)
|
||||
{
|
||||
for (int i = 0; i < infos.Length; i++)
|
||||
{
|
||||
if (infos[i].Key != i)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#pragma warning disable SA1311 // Static readonly fields should begin with upper-case letter
|
||||
|
||||
// EmitInfos...
|
||||
private static readonly Type refMessagePackReader = typeof(MessagePackReader).MakeByRefType();
|
||||
private static readonly Type refKvp = typeof(KeyValuePair<int, int>).MakeByRefType();
|
||||
private static readonly MethodInfo getFormatterWithVerify = typeof(FormatterResolverExtensions).GetRuntimeMethods().First(x => x.Name == "GetFormatterWithVerify");
|
||||
private static readonly MethodInfo getResolverFromOptions = typeof(MessagePackSerializerOptions).GetRuntimeProperty(nameof(MessagePackSerializerOptions.Resolver)).GetMethod;
|
||||
|
||||
private static readonly Func<Type, MethodInfo> getSerialize = t => typeof(IMessagePackFormatter<>).MakeGenericType(t).GetRuntimeMethod("Serialize", new[] { typeof(MessagePackWriter).MakeByRefType(), t, typeof(MessagePackSerializerOptions) });
|
||||
private static readonly Func<Type, MethodInfo> getDeserialize = t => typeof(IMessagePackFormatter<>).MakeGenericType(t).GetRuntimeMethod("Deserialize", new[] { typeof(MessagePackReader).MakeByRefType(), typeof(MessagePackSerializerOptions) });
|
||||
|
||||
private static readonly FieldInfo runtimeTypeHandleEqualityComparer = typeof(RuntimeTypeHandleEqualityComparer).GetRuntimeField("Default");
|
||||
private static readonly ConstructorInfo intIntKeyValuePairConstructor = typeof(KeyValuePair<int, int>).GetTypeInfo().DeclaredConstructors.First(x => x.GetParameters().Length == 2);
|
||||
private static readonly ConstructorInfo typeMapDictionaryConstructor = typeof(Dictionary<RuntimeTypeHandle, KeyValuePair<int, int>>).GetTypeInfo().DeclaredConstructors.First(x =>
|
||||
{
|
||||
ParameterInfo[] p = x.GetParameters();
|
||||
return p.Length == 2 && p[0].ParameterType == typeof(int);
|
||||
});
|
||||
|
||||
private static readonly MethodInfo typeMapDictionaryAdd = typeof(Dictionary<RuntimeTypeHandle, KeyValuePair<int, int>>).GetRuntimeMethod("Add", new[] { typeof(RuntimeTypeHandle), typeof(KeyValuePair<int, int>) });
|
||||
private static readonly MethodInfo typeMapDictionaryTryGetValue = typeof(Dictionary<RuntimeTypeHandle, KeyValuePair<int, int>>).GetRuntimeMethod("TryGetValue", new[] { typeof(RuntimeTypeHandle), refKvp });
|
||||
|
||||
private static readonly ConstructorInfo keyMapDictionaryConstructor = typeof(Dictionary<int, int>).GetTypeInfo().DeclaredConstructors.First(x =>
|
||||
{
|
||||
ParameterInfo[] p = x.GetParameters();
|
||||
return p.Length == 1 && p[0].ParameterType == typeof(int);
|
||||
});
|
||||
|
||||
private static readonly MethodInfo keyMapDictionaryAdd = typeof(Dictionary<int, int>).GetRuntimeMethod("Add", new[] { typeof(int), typeof(int) });
|
||||
private static readonly MethodInfo keyMapDictionaryTryGetValue = typeof(Dictionary<int, int>).GetRuntimeMethod("TryGetValue", new[] { typeof(int), typeof(int).MakeByRefType() });
|
||||
|
||||
private static readonly MethodInfo objectGetType = typeof(object).GetRuntimeMethod("GetType", Type.EmptyTypes);
|
||||
private static readonly MethodInfo getTypeHandle = typeof(Type).GetRuntimeProperty("TypeHandle").GetGetMethod();
|
||||
|
||||
private static readonly MethodInfo intIntKeyValuePairGetKey = typeof(KeyValuePair<int, int>).GetRuntimeProperty("Key").GetGetMethod();
|
||||
private static readonly MethodInfo intIntKeyValuePairGetValue = typeof(KeyValuePair<int, int>).GetRuntimeProperty("Value").GetGetMethod();
|
||||
|
||||
private static readonly ConstructorInfo invalidOperationExceptionConstructor = typeof(System.InvalidOperationException).GetTypeInfo().DeclaredConstructors.First(
|
||||
x =>
|
||||
{
|
||||
ParameterInfo[] p = x.GetParameters();
|
||||
return p.Length == 1 && p[0].ParameterType == typeof(string);
|
||||
});
|
||||
|
||||
private static readonly ConstructorInfo objectCtor = typeof(object).GetTypeInfo().DeclaredConstructors.First(x => x.GetParameters().Length == 0);
|
||||
|
||||
#pragma warning restore SA1311 // Static readonly fields should begin with upper-case letter
|
||||
|
||||
private static class MessagePackReaderTypeInfo
|
||||
{
|
||||
internal static readonly TypeInfo ReaderTypeInfo = typeof(MessagePackReader).GetTypeInfo();
|
||||
|
||||
internal static readonly MethodInfo ReadBytes = typeof(MessagePackReader).GetRuntimeMethod(nameof(MessagePackReader.ReadBytes), Type.EmptyTypes);
|
||||
internal static readonly MethodInfo ReadInt32 = typeof(MessagePackReader).GetRuntimeMethod(nameof(MessagePackReader.ReadInt32), Type.EmptyTypes);
|
||||
internal static readonly MethodInfo ReadString = typeof(MessagePackReader).GetRuntimeMethod(nameof(MessagePackReader.ReadString), Type.EmptyTypes);
|
||||
internal static readonly MethodInfo TryReadNil = typeof(MessagePackReader).GetRuntimeMethod(nameof(MessagePackReader.TryReadNil), Type.EmptyTypes);
|
||||
internal static readonly MethodInfo Skip = typeof(MessagePackReader).GetRuntimeMethod(nameof(MessagePackReader.Skip), Type.EmptyTypes);
|
||||
internal static readonly MethodInfo ReadArrayHeader = typeof(MessagePackReader).GetRuntimeMethod(nameof(MessagePackReader.ReadArrayHeader), Type.EmptyTypes);
|
||||
internal static readonly MethodInfo ReadMapHeader = typeof(MessagePackReader).GetRuntimeMethod(nameof(MessagePackReader.ReadMapHeader), Type.EmptyTypes);
|
||||
}
|
||||
|
||||
private static class MessagePackWriterTypeInfo
|
||||
{
|
||||
internal static readonly TypeInfo WriterTypeInfo = typeof(MessagePackWriter).GetTypeInfo();
|
||||
|
||||
internal static readonly MethodInfo WriteArrayHeader = typeof(MessagePackWriter).GetRuntimeMethod(nameof(MessagePackWriter.WriteArrayHeader), new[] { typeof(int) });
|
||||
internal static readonly MethodInfo WriteInt32 = typeof(MessagePackWriter).GetRuntimeMethod(nameof(MessagePackWriter.Write), new[] { typeof(int) });
|
||||
internal static readonly MethodInfo WriteNil = typeof(MessagePackWriter).GetRuntimeMethod(nameof(MessagePackWriter.WriteNil), Type.EmptyTypes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace MessagePack.Internal
|
||||
{
|
||||
// RuntimeTypeHandle can embed directly by OpCodes.Ldtoken
|
||||
// It does not implements IEquatable<T>(but GetHashCode and Equals is implemented) so needs this to avoid boxing.
|
||||
public class RuntimeTypeHandleEqualityComparer : IEqualityComparer<RuntimeTypeHandle>
|
||||
{
|
||||
public static readonly IEqualityComparer<RuntimeTypeHandle> Default = new RuntimeTypeHandleEqualityComparer();
|
||||
|
||||
private RuntimeTypeHandleEqualityComparer()
|
||||
{
|
||||
}
|
||||
|
||||
public bool Equals(RuntimeTypeHandle x, RuntimeTypeHandle y)
|
||||
{
|
||||
return x.Equals(y);
|
||||
}
|
||||
|
||||
public int GetHashCode(RuntimeTypeHandle obj)
|
||||
{
|
||||
return obj.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
internal class MessagePackDynamicUnionResolverException : MessagePackSerializationException
|
||||
{
|
||||
public MessagePackDynamicUnionResolverException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 90ad303c7072b2339bba5b667f71b34c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
// 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 MessagePack.Formatters;
|
||||
using MessagePack.Internal;
|
||||
|
||||
#pragma warning disable SA1403 // File may only contain a single namespace
|
||||
|
||||
namespace MessagePack.Resolvers
|
||||
{
|
||||
public sealed class NativeDateTimeResolver : IFormatterResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// The singleton instance that can be used.
|
||||
/// </summary>
|
||||
public static readonly NativeDateTimeResolver Instance;
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="MessagePackSerializerOptions"/> instance with this formatter pre-configured.
|
||||
/// </summary>
|
||||
public static readonly MessagePackSerializerOptions Options;
|
||||
|
||||
static NativeDateTimeResolver()
|
||||
{
|
||||
Instance = new NativeDateTimeResolver();
|
||||
Options = new MessagePackSerializerOptions(Instance);
|
||||
}
|
||||
|
||||
private NativeDateTimeResolver()
|
||||
{
|
||||
}
|
||||
|
||||
public IMessagePackFormatter<T> GetFormatter<T>()
|
||||
{
|
||||
return FormatterCache<T>.Formatter;
|
||||
}
|
||||
|
||||
private static class FormatterCache<T>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<T> Formatter;
|
||||
|
||||
static FormatterCache()
|
||||
{
|
||||
Formatter = (IMessagePackFormatter<T>)NativeDateTimeResolverGetFormatterHelper.GetFormatter(typeof(T));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace MessagePack.Internal
|
||||
{
|
||||
internal static class NativeDateTimeResolverGetFormatterHelper
|
||||
{
|
||||
internal static object GetFormatter(Type t)
|
||||
{
|
||||
if (t == typeof(DateTime))
|
||||
{
|
||||
return NativeDateTimeFormatter.Instance;
|
||||
}
|
||||
else if (t == typeof(DateTime?))
|
||||
{
|
||||
return new StaticNullableFormatter<DateTime>(NativeDateTimeFormatter.Instance);
|
||||
}
|
||||
else if (t == typeof(DateTime[]))
|
||||
{
|
||||
return NativeDateTimeArrayFormatter.Instance;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bee453915d14c4376a4cf68b338f7f4a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
// 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 MessagePack.Formatters;
|
||||
|
||||
namespace MessagePack.Resolvers
|
||||
{
|
||||
public sealed class NativeDecimalResolver : IFormatterResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// The singleton instance that can be used.
|
||||
/// </summary>
|
||||
public static readonly NativeDecimalResolver Instance = new NativeDecimalResolver();
|
||||
|
||||
private NativeDecimalResolver()
|
||||
{
|
||||
}
|
||||
|
||||
public IMessagePackFormatter<T> GetFormatter<T>()
|
||||
{
|
||||
return FormatterCache<T>.Formatter;
|
||||
}
|
||||
|
||||
private static object GetFormatterHelper(Type t)
|
||||
{
|
||||
if (t == typeof(Decimal))
|
||||
{
|
||||
return NativeDecimalFormatter.Instance;
|
||||
}
|
||||
else if (t == typeof(Decimal?))
|
||||
{
|
||||
return new StaticNullableFormatter<Decimal>(NativeDecimalFormatter.Instance);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class FormatterCache<T>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<T> Formatter;
|
||||
|
||||
static FormatterCache()
|
||||
{
|
||||
Formatter = (IMessagePackFormatter<T>)GetFormatterHelper(typeof(T));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 058b6071c8115560499afd0cc97e2fbd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
49
Assets/Scripts/MessagePack/Resolvers/NativeGuidResolver.cs
Normal file
49
Assets/Scripts/MessagePack/Resolvers/NativeGuidResolver.cs
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// 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 MessagePack.Formatters;
|
||||
|
||||
namespace MessagePack.Resolvers
|
||||
{
|
||||
public sealed class NativeGuidResolver : IFormatterResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// The singleton instance that can be used.
|
||||
/// </summary>
|
||||
public static readonly NativeGuidResolver Instance = new NativeGuidResolver();
|
||||
|
||||
private NativeGuidResolver()
|
||||
{
|
||||
}
|
||||
|
||||
public IMessagePackFormatter<T> GetFormatter<T>()
|
||||
{
|
||||
return FormatterCache<T>.Formatter;
|
||||
}
|
||||
|
||||
private static object GetFormatterHelper(Type t)
|
||||
{
|
||||
if (t == typeof(Guid))
|
||||
{
|
||||
return NativeGuidFormatter.Instance;
|
||||
}
|
||||
else if (t == typeof(Guid?))
|
||||
{
|
||||
return new StaticNullableFormatter<Guid>(NativeGuidFormatter.Instance);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class FormatterCache<T>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<T> Formatter;
|
||||
|
||||
static FormatterCache()
|
||||
{
|
||||
Formatter = (IMessagePackFormatter<T>)GetFormatterHelper(typeof(T));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a800419f557b36754a52fca66a1ed462
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using MessagePack.Formatters;
|
||||
|
||||
namespace MessagePack.Resolvers
|
||||
{
|
||||
public sealed class PrimitiveObjectResolver : IFormatterResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// The singleton instance that can be used.
|
||||
/// </summary>
|
||||
public static readonly PrimitiveObjectResolver Instance;
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="MessagePackSerializerOptions"/> instance with this formatter pre-configured.
|
||||
/// </summary>
|
||||
public static readonly MessagePackSerializerOptions Options;
|
||||
|
||||
static PrimitiveObjectResolver()
|
||||
{
|
||||
Instance = new PrimitiveObjectResolver();
|
||||
Options = new MessagePackSerializerOptions(Instance);
|
||||
}
|
||||
|
||||
private PrimitiveObjectResolver()
|
||||
{
|
||||
}
|
||||
|
||||
public IMessagePackFormatter<T> GetFormatter<T>()
|
||||
{
|
||||
return FormatterCache<T>.Formatter;
|
||||
}
|
||||
|
||||
private static class FormatterCache<T>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<T> Formatter;
|
||||
|
||||
static FormatterCache()
|
||||
{
|
||||
Formatter = (typeof(T) == typeof(object))
|
||||
? (IMessagePackFormatter<T>)(object)PrimitiveObjectFormatter.Instance
|
||||
: null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////#if !UNITY_2018_3_OR_NEWER
|
||||
|
||||
//// /// <summary>
|
||||
//// /// In `object`, when serializing resolve by concrete type and when deserializing use primitive.
|
||||
//// /// </summary>
|
||||
//// public sealed class DynamicObjectTypeFallbackResolver : IFormatterResolver
|
||||
//// {
|
||||
//// public static readonly DynamicObjectTypeFallbackResolver Instance = new DynamicObjectTypeFallbackResolver();
|
||||
|
||||
//// DynamicObjectTypeFallbackResolver()
|
||||
//// {
|
||||
|
||||
//// }
|
||||
|
||||
//// public IMessagePackFormatter<T> GetFormatter<T>()
|
||||
//// {
|
||||
//// return FormatterCache<T>.formatter;
|
||||
//// }
|
||||
|
||||
//// static class FormatterCache<T>
|
||||
//// {
|
||||
//// public static readonly IMessagePackFormatter<T> formatter;
|
||||
|
||||
//// static FormatterCache()
|
||||
//// {
|
||||
//// formatter = (typeof(T) == typeof(object))
|
||||
//// ? (IMessagePackFormatter<T>)(object)DynamicObjectTypeFallbackFormatter.Instance
|
||||
//// : null;
|
||||
//// }
|
||||
//// }
|
||||
//// }
|
||||
|
||||
////#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5b5a40f7f1c67953c8b8066277e196f6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
305
Assets/Scripts/MessagePack/Resolvers/StandardResolver.cs
Normal file
305
Assets/Scripts/MessagePack/Resolvers/StandardResolver.cs
Normal file
|
|
@ -0,0 +1,305 @@
|
|||
// 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.Linq;
|
||||
using MessagePack.Formatters;
|
||||
using MessagePack.Internal;
|
||||
using MessagePack.Resolvers;
|
||||
|
||||
#pragma warning disable SA1403 // File may only contain a single namespace
|
||||
|
||||
namespace MessagePack.Resolvers
|
||||
{
|
||||
/// <summary>
|
||||
/// Default composited resolver, builtin -> attribute -> dynamic enum -> dynamic generic -> dynamic union -> dynamic object -> primitive.
|
||||
/// </summary>
|
||||
public sealed class StandardResolver : IFormatterResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// The singleton instance that can be used.
|
||||
/// </summary>
|
||||
public static readonly StandardResolver Instance;
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="MessagePackSerializerOptions"/> instance with this formatter pre-configured.
|
||||
/// </summary>
|
||||
public static readonly MessagePackSerializerOptions Options;
|
||||
|
||||
private static readonly IFormatterResolver[] Resolvers = StandardResolverHelper.DefaultResolvers.Concat(new IFormatterResolver[]
|
||||
{
|
||||
#if !ENABLE_IL2CPP && !NET_STANDARD_2_0
|
||||
DynamicObjectResolver.Instance, // Try Object
|
||||
#endif
|
||||
}).ToArray();
|
||||
|
||||
static StandardResolver()
|
||||
{
|
||||
Instance = new StandardResolver();
|
||||
Options = new MessagePackSerializerOptions(Instance);
|
||||
}
|
||||
|
||||
private StandardResolver()
|
||||
{
|
||||
}
|
||||
|
||||
public IMessagePackFormatter<T> GetFormatter<T>()
|
||||
{
|
||||
return FormatterCache<T>.Formatter;
|
||||
}
|
||||
|
||||
private static class FormatterCache<T>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<T> Formatter;
|
||||
|
||||
static FormatterCache()
|
||||
{
|
||||
if (typeof(T) == typeof(object))
|
||||
{
|
||||
// final fallback
|
||||
#if !ENABLE_IL2CPP
|
||||
Formatter = (IMessagePackFormatter<T>)DynamicObjectTypeFallbackFormatter.Instance;
|
||||
#else
|
||||
Formatter = PrimitiveObjectResolver.Instance.GetFormatter<T>();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (IFormatterResolver item in Resolvers)
|
||||
{
|
||||
IMessagePackFormatter<T> f = item.GetFormatter<T>();
|
||||
if (f != null)
|
||||
{
|
||||
Formatter = f;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ContractlessStandardResolver : IFormatterResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// The singleton instance that can be used.
|
||||
/// </summary>
|
||||
public static readonly ContractlessStandardResolver Instance;
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="MessagePackSerializerOptions"/> instance with this formatter pre-configured.
|
||||
/// </summary>
|
||||
public static readonly MessagePackSerializerOptions Options;
|
||||
|
||||
private static readonly IFormatterResolver[] Resolvers = StandardResolverHelper.DefaultResolvers.Concat(new IFormatterResolver[]
|
||||
{
|
||||
#if !ENABLE_IL2CPP && !NET_STANDARD_2_0
|
||||
DynamicObjectResolver.Instance, // Try Object
|
||||
DynamicContractlessObjectResolver.Instance, // Serializes keys as strings
|
||||
#endif
|
||||
}).ToArray();
|
||||
|
||||
static ContractlessStandardResolver()
|
||||
{
|
||||
Instance = new ContractlessStandardResolver();
|
||||
Options = new MessagePackSerializerOptions(Instance);
|
||||
}
|
||||
|
||||
private ContractlessStandardResolver()
|
||||
{
|
||||
}
|
||||
|
||||
public IMessagePackFormatter<T> GetFormatter<T>()
|
||||
{
|
||||
return FormatterCache<T>.Formatter;
|
||||
}
|
||||
|
||||
private static class FormatterCache<T>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<T> Formatter;
|
||||
|
||||
static FormatterCache()
|
||||
{
|
||||
if (typeof(T) == typeof(object))
|
||||
{
|
||||
// final fallback
|
||||
#if !ENABLE_IL2CPP
|
||||
Formatter = (IMessagePackFormatter<T>)DynamicObjectTypeFallbackFormatter.Instance;
|
||||
#else
|
||||
Formatter = PrimitiveObjectResolver.Instance.GetFormatter<T>();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (IFormatterResolver item in Resolvers)
|
||||
{
|
||||
IMessagePackFormatter<T> f = item.GetFormatter<T>();
|
||||
if (f != null)
|
||||
{
|
||||
Formatter = f;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class StandardResolverAllowPrivate : IFormatterResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// The singleton instance that can be used.
|
||||
/// </summary>
|
||||
public static readonly StandardResolverAllowPrivate Instance;
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="MessagePackSerializerOptions"/> instance with this formatter pre-configured.
|
||||
/// </summary>
|
||||
public static readonly MessagePackSerializerOptions Options;
|
||||
|
||||
private static readonly IFormatterResolver[] Resolvers = StandardResolverHelper.DefaultResolvers.Concat(new IFormatterResolver[]
|
||||
{
|
||||
#if !ENABLE_IL2CPP && !NET_STANDARD_2_0
|
||||
DynamicObjectResolverAllowPrivate.Instance, // Try Object
|
||||
#endif
|
||||
}).ToArray();
|
||||
|
||||
static StandardResolverAllowPrivate()
|
||||
{
|
||||
Instance = new StandardResolverAllowPrivate();
|
||||
Options = new MessagePackSerializerOptions(Instance);
|
||||
}
|
||||
|
||||
private StandardResolverAllowPrivate()
|
||||
{
|
||||
}
|
||||
|
||||
public IMessagePackFormatter<T> GetFormatter<T>()
|
||||
{
|
||||
return FormatterCache<T>.Formatter;
|
||||
}
|
||||
|
||||
private static class FormatterCache<T>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<T> Formatter;
|
||||
|
||||
static FormatterCache()
|
||||
{
|
||||
if (typeof(T) == typeof(object))
|
||||
{
|
||||
// final fallback
|
||||
#if !ENABLE_IL2CPP
|
||||
Formatter = (IMessagePackFormatter<T>)DynamicObjectTypeFallbackFormatter.Instance;
|
||||
#else
|
||||
Formatter = PrimitiveObjectResolver.Instance.GetFormatter<T>();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (IFormatterResolver item in Resolvers)
|
||||
{
|
||||
IMessagePackFormatter<T> f = item.GetFormatter<T>();
|
||||
if (f != null)
|
||||
{
|
||||
Formatter = f;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ContractlessStandardResolverAllowPrivate : IFormatterResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// The singleton instance that can be used.
|
||||
/// </summary>
|
||||
public static readonly ContractlessStandardResolverAllowPrivate Instance;
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="MessagePackSerializerOptions"/> instance with this formatter pre-configured.
|
||||
/// </summary>
|
||||
public static readonly MessagePackSerializerOptions Options;
|
||||
|
||||
private static readonly IFormatterResolver[] Resolvers = StandardResolverHelper.DefaultResolvers.Concat(new IFormatterResolver[]
|
||||
{
|
||||
#if !ENABLE_IL2CPP && !NET_STANDARD_2_0
|
||||
DynamicObjectResolverAllowPrivate.Instance, // Try Object
|
||||
DynamicContractlessObjectResolverAllowPrivate.Instance, // Serializes keys as strings
|
||||
#endif
|
||||
}).ToArray();
|
||||
|
||||
static ContractlessStandardResolverAllowPrivate()
|
||||
{
|
||||
Instance = new ContractlessStandardResolverAllowPrivate();
|
||||
Options = new MessagePackSerializerOptions(Instance);
|
||||
}
|
||||
|
||||
private ContractlessStandardResolverAllowPrivate()
|
||||
{
|
||||
}
|
||||
|
||||
public IMessagePackFormatter<T> GetFormatter<T>()
|
||||
{
|
||||
return FormatterCache<T>.Formatter;
|
||||
}
|
||||
|
||||
private static class FormatterCache<T>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<T> Formatter;
|
||||
|
||||
static FormatterCache()
|
||||
{
|
||||
if (typeof(T) == typeof(object))
|
||||
{
|
||||
// final fallback
|
||||
#if !ENABLE_IL2CPP
|
||||
Formatter = (IMessagePackFormatter<T>)DynamicObjectTypeFallbackFormatter.Instance;
|
||||
#else
|
||||
Formatter = PrimitiveObjectResolver.Instance.GetFormatter<T>();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (IFormatterResolver item in Resolvers)
|
||||
{
|
||||
IMessagePackFormatter<T> f = item.GetFormatter<T>();
|
||||
if (f != null)
|
||||
{
|
||||
Formatter = f;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace MessagePack.Internal
|
||||
{
|
||||
internal static class StandardResolverHelper
|
||||
{
|
||||
public static readonly IFormatterResolver[] DefaultResolvers = new IFormatterResolver[]
|
||||
{
|
||||
BuiltinResolver.Instance, // Try Builtin
|
||||
AttributeFormatterResolver.Instance, // Try use [MessagePackFormatter]
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
MessagePack.Unity.UnityResolver.Instance,
|
||||
#endif
|
||||
|
||||
#if !ENABLE_IL2CPP && !NET_STANDARD_2_0
|
||||
DynamicEnumResolver.Instance, // Try Enum
|
||||
#endif
|
||||
|
||||
#if !ENABLE_IL2CPP
|
||||
DynamicGenericResolver.Instance, // Try Array, Tuple, Collection, Enum(Generic Fallback)
|
||||
#endif
|
||||
|
||||
#if !ENABLE_IL2CPP && !NET_STANDARD_2_0
|
||||
DynamicUnionResolver.Instance, // Try Union(Interface)
|
||||
#endif
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2273a153a02536bb1809f799fbfb2ceb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
149
Assets/Scripts/MessagePack/Resolvers/StaticCompositeResolver.cs
Normal file
149
Assets/Scripts/MessagePack/Resolvers/StaticCompositeResolver.cs
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
// 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.Collections.Generic;
|
||||
using MessagePack.Formatters;
|
||||
|
||||
namespace MessagePack.Resolvers
|
||||
{
|
||||
/// <summary>
|
||||
/// Singleton version of CompositeResolver, which be able to register a collection of formatters and resolvers to a single instance.
|
||||
/// </summary>
|
||||
public class StaticCompositeResolver : IFormatterResolver
|
||||
{
|
||||
public static readonly StaticCompositeResolver Instance = new StaticCompositeResolver();
|
||||
|
||||
private bool freezed;
|
||||
private IReadOnlyList<IMessagePackFormatter> formatters;
|
||||
private IReadOnlyList<IFormatterResolver> resolvers;
|
||||
|
||||
private StaticCompositeResolver()
|
||||
{
|
||||
formatters = Array.Empty<IMessagePackFormatter>();
|
||||
resolvers = Array.Empty<IFormatterResolver>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a singleton instance with the specified formatters.
|
||||
/// This method can only call before use StaticCompositeResolver.Instance.GetFormatter.
|
||||
/// If call twice in the Register methods, registered formatters and resolvers will be overridden.
|
||||
/// </summary>
|
||||
/// <param name="formatters">
|
||||
/// A list of instances of <see cref="IMessagePackFormatter{T}"/>.
|
||||
/// The formatters are searched in the order given, so if two formatters support serializing the same type, the first one is used.
|
||||
/// </param>
|
||||
public void Register(params IMessagePackFormatter[] formatters)
|
||||
{
|
||||
if (this.freezed)
|
||||
{
|
||||
throw new InvalidOperationException("Register must call on startup(before use GetFormatter<T>).");
|
||||
}
|
||||
|
||||
if (this.formatters is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(formatters));
|
||||
}
|
||||
|
||||
this.formatters = formatters;
|
||||
this.resolvers = Array.Empty<IFormatterResolver>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a singleton instance with the specified formatters and sub-resolvers.
|
||||
/// This method can only call before use StaticCompositeResolver.Instance.GetFormatter.
|
||||
/// If call twice in the Register methods, registered formatters and resolvers will be overridden.
|
||||
/// </summary>
|
||||
/// <param name="resolvers">
|
||||
/// A list of resolvers to use for serializing types.
|
||||
/// The resolvers are searched in the order given, so if two resolvers support serializing the same type, the first one is used.
|
||||
/// </param>
|
||||
public void Register(params IFormatterResolver[] resolvers)
|
||||
{
|
||||
if (this.freezed)
|
||||
{
|
||||
throw new InvalidOperationException("Register must call on startup(before use GetFormatter<T>).");
|
||||
}
|
||||
|
||||
if (resolvers is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(resolvers));
|
||||
}
|
||||
|
||||
this.formatters = Array.Empty<IMessagePackFormatter>();
|
||||
this.resolvers = resolvers;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a singleton instance with the specified formatters and sub-resolvers.
|
||||
/// This method can only call before use StaticCompositeResolver.Instance.GetFormatter.
|
||||
/// If call twice in the Register methods, registered formatters and resolvers will be overridden.
|
||||
/// </summary>
|
||||
/// <param name="formatters">
|
||||
/// A list of instances of <see cref="IMessagePackFormatter{T}"/>.
|
||||
/// The formatters are searched in the order given, so if two formatters support serializing the same type, the first one is used.
|
||||
/// </param>
|
||||
/// <param name="resolvers">
|
||||
/// A list of resolvers to use for serializing types for which <paramref name="formatters"/> does not include a formatter.
|
||||
/// The resolvers are searched in the order given, so if two resolvers support serializing the same type, the first one is used.
|
||||
/// </param>
|
||||
public void Register(IReadOnlyList<IMessagePackFormatter> formatters, IReadOnlyList<IFormatterResolver> resolvers)
|
||||
{
|
||||
if (this.freezed)
|
||||
{
|
||||
throw new InvalidOperationException("Register must call on startup(before use GetFormatter<T>).");
|
||||
}
|
||||
|
||||
if (formatters is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(formatters));
|
||||
}
|
||||
|
||||
if (resolvers is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(resolvers));
|
||||
}
|
||||
|
||||
this.formatters = formatters;
|
||||
this.resolvers = resolvers;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an <see cref="IMessagePackFormatter{T}"/> instance that can serialize or deserialize some type <typeparamref name="T"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of value to be serialized or deserialized.</typeparam>
|
||||
/// <returns>A formatter, if this resolver supplies one for type <typeparamref name="T"/>; otherwise <c>null</c>.</returns>
|
||||
public IMessagePackFormatter<T> GetFormatter<T>()
|
||||
{
|
||||
return Cache<T>.Formatter;
|
||||
}
|
||||
|
||||
private static class Cache<T>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<T> Formatter;
|
||||
|
||||
static Cache()
|
||||
{
|
||||
Instance.freezed = true;
|
||||
foreach (var item in Instance.formatters)
|
||||
{
|
||||
if (item is IMessagePackFormatter<T> f)
|
||||
{
|
||||
Formatter = f;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var item in Instance.resolvers)
|
||||
{
|
||||
var f = item.GetFormatter<T>();
|
||||
if (f != null)
|
||||
{
|
||||
Formatter = f;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 26c258a5a36d7dbf99caf4e98a7cbd53
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#if !UNITY_2018_3_OR_NEWER
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MessagePack.Formatters;
|
||||
using MessagePack.Internal;
|
||||
|
||||
namespace MessagePack.Resolvers
|
||||
{
|
||||
/// <summary>
|
||||
/// Embeds the full name of .NET types for <see cref="object"/> typed fields/collection items
|
||||
/// Preserves .NET <see cref="DateTime"/> timezone.
|
||||
/// </summary>
|
||||
public sealed class TypelessContractlessStandardResolver : IFormatterResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// The singleton instance that can be used.
|
||||
/// </summary>
|
||||
public static readonly TypelessContractlessStandardResolver Instance;
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="MessagePackSerializerOptions"/> instance with this formatter pre-configured.
|
||||
/// </summary>
|
||||
public static readonly MessagePackSerializerOptions Options;
|
||||
|
||||
/// <summary>
|
||||
/// A *private* list of resolvers. If we ever want to expose any of these (so the user can adjust settings, etc.)
|
||||
/// then we must make this an instance collection instead of a static collection so that each consumer can have their own settings.
|
||||
/// </summary>
|
||||
private static readonly IReadOnlyList<IFormatterResolver> Resolvers = new IFormatterResolver[]
|
||||
{
|
||||
NativeDateTimeResolver.Instance, // Native c# DateTime format, preserving timezone
|
||||
ForceSizePrimitiveObjectResolver.Instance, // Preserve particular integer types
|
||||
BuiltinResolver.Instance, // Try Builtin
|
||||
AttributeFormatterResolver.Instance, // Try use [MessagePackFormatter]
|
||||
#if !ENABLE_IL2CPP
|
||||
DynamicEnumResolver.Instance, // Try Enum
|
||||
DynamicGenericResolver.Instance, // Try Array, Tuple, Collection
|
||||
DynamicUnionResolver.Instance, // Try Union(Interface)
|
||||
DynamicObjectResolver.Instance, // Try Object
|
||||
#endif
|
||||
DynamicContractlessObjectResolverAllowPrivate.Instance, // Serializes keys as strings
|
||||
TypelessObjectResolver.Instance,
|
||||
};
|
||||
|
||||
static TypelessContractlessStandardResolver()
|
||||
{
|
||||
Instance = new TypelessContractlessStandardResolver();
|
||||
Options = new MessagePackSerializerOptions(Instance);
|
||||
}
|
||||
|
||||
private readonly ResolverCache resolverCache = new ResolverCache(Resolvers);
|
||||
|
||||
public IMessagePackFormatter<T> GetFormatter<T>() => this.resolverCache.GetFormatter<T>();
|
||||
|
||||
private class ResolverCache : CachingFormatterResolver
|
||||
{
|
||||
private readonly IReadOnlyList<IFormatterResolver> resolvers;
|
||||
|
||||
internal ResolverCache(IReadOnlyList<IFormatterResolver> resolvers)
|
||||
{
|
||||
this.resolvers = resolvers ?? throw new ArgumentNullException(nameof(resolvers));
|
||||
}
|
||||
|
||||
protected override IMessagePackFormatter<T> GetFormatterCore<T>()
|
||||
{
|
||||
foreach (IFormatterResolver item in this.resolvers)
|
||||
{
|
||||
IMessagePackFormatter<T> f = item.GetFormatter<T>();
|
||||
if (f != null)
|
||||
{
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d4b1e4648b37d6308ac35a0e31148ab0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
142
Assets/Scripts/MessagePack/Resolvers/TypelessObjectResolver.cs
Normal file
142
Assets/Scripts/MessagePack/Resolvers/TypelessObjectResolver.cs
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
// 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.Collections.Generic;
|
||||
using MessagePack.Formatters;
|
||||
using MessagePack.Internal;
|
||||
|
||||
namespace MessagePack.Resolvers
|
||||
{
|
||||
#if !UNITY_2018_3_OR_NEWER
|
||||
|
||||
/// <summary>
|
||||
/// Used for `object` fields/collections, ex: var arr = new object[] { 1, "a", new Model() };
|
||||
/// The runtime type of value in object field, should be covered by one of resolvers in complex/standard resolver.
|
||||
/// <see cref="TypelessObjectResolver"/> should be placed before DynamicObjectTypeFallbackResolver and <see cref="PrimitiveObjectFormatter"/> in resolvers list.
|
||||
/// Deserializer uses Namespace.TypeName, AssemblyName to get runtime type in destination app, so that combination must be present in destination app.
|
||||
/// Serialized binary is valid MessagePack binary used ext-format and custom typecode(100).
|
||||
/// Inside ext - assembly qualified type name, and serialized object.
|
||||
/// </summary>
|
||||
public sealed class TypelessObjectResolver : IFormatterResolver
|
||||
{
|
||||
public static readonly IFormatterResolver Instance = new TypelessObjectResolver();
|
||||
|
||||
private static readonly IFormatterResolver[] Resolvers = new IFormatterResolver[]
|
||||
{
|
||||
ForceSizePrimitiveObjectResolver.Instance,
|
||||
ContractlessStandardResolverAllowPrivate.Instance,
|
||||
};
|
||||
|
||||
private TypelessObjectResolver()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IMessagePackFormatter<T> GetFormatter<T>()
|
||||
{
|
||||
if (typeof(T) == typeof(object))
|
||||
{
|
||||
return (IMessagePackFormatter<T>)TypelessFormatter.Instance;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (IFormatterResolver item in Resolvers)
|
||||
{
|
||||
IMessagePackFormatter<T> f = item.GetFormatter<T>();
|
||||
if (f != null)
|
||||
{
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* helpers for TypelessFormatter */
|
||||
|
||||
internal sealed class ForceSizePrimitiveObjectResolver : IFormatterResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// The singleton instance that can be used.
|
||||
/// </summary>
|
||||
public static readonly ForceSizePrimitiveObjectResolver Instance;
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="MessagePackSerializerOptions"/> instance with this formatter pre-configured.
|
||||
/// </summary>
|
||||
public static readonly MessagePackSerializerOptions Options;
|
||||
|
||||
static ForceSizePrimitiveObjectResolver()
|
||||
{
|
||||
Instance = new ForceSizePrimitiveObjectResolver();
|
||||
Options = new MessagePackSerializerOptions(Instance);
|
||||
}
|
||||
|
||||
private ForceSizePrimitiveObjectResolver()
|
||||
{
|
||||
}
|
||||
|
||||
public IMessagePackFormatter<T> GetFormatter<T>()
|
||||
{
|
||||
return FormatterCache<T>.Formatter;
|
||||
}
|
||||
|
||||
private static class FormatterCache<T>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<T> Formatter;
|
||||
|
||||
static FormatterCache()
|
||||
{
|
||||
Formatter = (IMessagePackFormatter<T>)Helper.GetFormatter(typeof(T));
|
||||
}
|
||||
}
|
||||
|
||||
private static class Helper
|
||||
{
|
||||
private static readonly Dictionary<Type, object> FormatterMap = new Dictionary<Type, object>()
|
||||
{
|
||||
// Primitive
|
||||
{ typeof(Int16), ForceInt16BlockFormatter.Instance },
|
||||
{ typeof(Int32), ForceInt32BlockFormatter.Instance },
|
||||
{ typeof(Int64), ForceInt64BlockFormatter.Instance },
|
||||
{ typeof(UInt16), ForceUInt16BlockFormatter.Instance },
|
||||
{ typeof(UInt32), ForceUInt32BlockFormatter.Instance },
|
||||
{ typeof(UInt64), ForceUInt64BlockFormatter.Instance },
|
||||
{ typeof(byte), ForceByteBlockFormatter.Instance },
|
||||
{ typeof(sbyte), ForceSByteBlockFormatter.Instance },
|
||||
|
||||
// Nullable Primitive
|
||||
{ typeof(Int16?), NullableForceInt16BlockFormatter.Instance },
|
||||
{ typeof(Int32?), NullableForceInt32BlockFormatter.Instance },
|
||||
{ typeof(Int64?), NullableForceInt64BlockFormatter.Instance },
|
||||
{ typeof(UInt16?), NullableForceUInt16BlockFormatter.Instance },
|
||||
{ typeof(UInt32?), NullableForceUInt32BlockFormatter.Instance },
|
||||
{ typeof(UInt64?), NullableForceUInt64BlockFormatter.Instance },
|
||||
{ typeof(byte?), NullableForceByteBlockFormatter.Instance },
|
||||
{ typeof(sbyte?), NullableForceSByteBlockFormatter.Instance },
|
||||
|
||||
// optimized primitive array formatter
|
||||
{ typeof(Int16[]), ForceInt16BlockArrayFormatter.Instance },
|
||||
{ typeof(Int32[]), ForceInt32BlockArrayFormatter.Instance },
|
||||
{ typeof(Int64[]), ForceInt64BlockArrayFormatter.Instance },
|
||||
{ typeof(UInt16[]), ForceUInt16BlockArrayFormatter.Instance },
|
||||
{ typeof(UInt32[]), ForceUInt32BlockArrayFormatter.Instance },
|
||||
{ typeof(UInt64[]), ForceUInt64BlockArrayFormatter.Instance },
|
||||
{ typeof(SByte[]), ForceSByteBlockArrayFormatter.Instance },
|
||||
};
|
||||
|
||||
public static object GetFormatter(Type type)
|
||||
{
|
||||
object formatter;
|
||||
return FormatterMap.TryGetValue(type, out formatter)
|
||||
? formatter
|
||||
: null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 857aa0d32f3e2955491df1c9d5bb6f5d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loading…
Reference in a new issue