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
1074
Assets/Scripts/MessagePack/Formatters/CollectionFormatter.cs
Normal file
1074
Assets/Scripts/MessagePack/Formatters/CollectionFormatter.cs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f92b8946eec0ab476a689a0dfa8c2498
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
52
Assets/Scripts/MessagePack/Formatters/CollectionHelpers`2.cs
Normal file
52
Assets/Scripts/MessagePack/Formatters/CollectionHelpers`2.cs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
// 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.Expressions;
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides general helpers for creating collections (including dictionaries).
|
||||
/// </summary>
|
||||
/// <typeparam name="TCollection">The concrete type of collection to create.</typeparam>
|
||||
/// <typeparam name="TEqualityComparer">The type of equality comparer that we would hope to pass into the collection's constructor.</typeparam>
|
||||
internal static class CollectionHelpers<TCollection, TEqualityComparer>
|
||||
where TCollection : new()
|
||||
{
|
||||
/// <summary>
|
||||
/// The delegate that will create the collection, if the typical (int count, IEqualityComparer{T} equalityComparer) constructor was found.
|
||||
/// </summary>
|
||||
private static Func<int, TEqualityComparer, TCollection> collectionCreator;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes static members of the <see cref="CollectionHelpers{TCollection, TEqualityComparer}"/> class.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Initializes a delegate that is optimized to create a collection of a given size and using the given equality comparer, if possible.
|
||||
/// </remarks>
|
||||
static CollectionHelpers()
|
||||
{
|
||||
var ctor = typeof(TCollection).GetConstructor(new Type[] { typeof(int), typeof(TEqualityComparer) });
|
||||
if (ctor != null)
|
||||
{
|
||||
ParameterExpression param1 = Expression.Parameter(typeof(int), "count");
|
||||
ParameterExpression param2 = Expression.Parameter(typeof(TEqualityComparer), "equalityComparer");
|
||||
NewExpression body = Expression.New(ctor, param1, param2);
|
||||
collectionCreator = Expression.Lambda<Func<int, TEqualityComparer, TCollection>>(body, param1, param2).Compile();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <typeparamref name="TCollection"/> collection.
|
||||
/// </summary>
|
||||
/// <param name="count">The number of elements the collection should be prepared to receive.</param>
|
||||
/// <param name="equalityComparer">The equality comparer to initialize the collection with.</param>
|
||||
/// <returns>The newly initialized collection.</returns>
|
||||
/// <remarks>
|
||||
/// Use of the <paramref name="count"/> and <paramref name="equalityComparer"/> are a best effort.
|
||||
/// If we can't find a constructor on the collection in the expected shape, we'll just instantiate the collection with its default constructor.
|
||||
/// </remarks>
|
||||
internal static TCollection CreateHashCollection(int count, TEqualityComparer equalityComparer) => collectionCreator != null ? collectionCreator.Invoke(count, equalityComparer) : new TCollection();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 25f9fe82ddb369c8f9600901293b80f8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
70
Assets/Scripts/MessagePack/Formatters/DateTimeFormatters.cs
Normal file
70
Assets/Scripts/MessagePack/Formatters/DateTimeFormatters.cs
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
// 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;
|
||||
|
||||
#pragma warning disable SA1649 // File name should match first type name
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
/// <summary>
|
||||
/// Serialize by .NET native DateTime binary format.
|
||||
/// </summary>
|
||||
public sealed class NativeDateTimeFormatter : IMessagePackFormatter<DateTime>
|
||||
{
|
||||
public static readonly NativeDateTimeFormatter Instance = new NativeDateTimeFormatter();
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, DateTime value, MessagePackSerializerOptions options)
|
||||
{
|
||||
var dateData = value.ToBinary();
|
||||
writer.Write(dateData);
|
||||
}
|
||||
|
||||
public DateTime Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
var dateData = reader.ReadInt64();
|
||||
return DateTime.FromBinary(dateData);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class NativeDateTimeArrayFormatter : IMessagePackFormatter<DateTime[]>
|
||||
{
|
||||
public static readonly NativeDateTimeArrayFormatter Instance = new NativeDateTimeArrayFormatter();
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, DateTime[] value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteArrayHeader(value.Length);
|
||||
for (int i = 0; i < value.Length; i++)
|
||||
{
|
||||
writer.Write(value[i].ToBinary());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public DateTime[] Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.TryReadNil())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var len = reader.ReadArrayHeader();
|
||||
var array = new DateTime[len];
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
var dateData = reader.ReadInt64();
|
||||
array[i] = DateTime.FromBinary(dateData);
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e28b94bd9483c36efae78067f97c65cb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
280
Assets/Scripts/MessagePack/Formatters/DictionaryFormatter.cs
Normal file
280
Assets/Scripts/MessagePack/Formatters/DictionaryFormatter.cs
Normal file
|
|
@ -0,0 +1,280 @@
|
|||
// 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.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Reflection;
|
||||
|
||||
#pragma warning disable SA1649 // File name should match first type name
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
// unfortunately, can't use IDictionary<KVP> because supports IReadOnlyDictionary.
|
||||
public abstract class DictionaryFormatterBase<TKey, TValue, TIntermediate, TEnumerator, TDictionary> : IMessagePackFormatter<TDictionary>
|
||||
where TDictionary : IEnumerable<KeyValuePair<TKey, TValue>>
|
||||
where TEnumerator : IEnumerator<KeyValuePair<TKey, TValue>>
|
||||
{
|
||||
public void Serialize(ref MessagePackWriter writer, TDictionary value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
else
|
||||
{
|
||||
IFormatterResolver resolver = options.Resolver;
|
||||
IMessagePackFormatter<TKey> keyFormatter = resolver.GetFormatterWithVerify<TKey>();
|
||||
IMessagePackFormatter<TValue> valueFormatter = resolver.GetFormatterWithVerify<TValue>();
|
||||
|
||||
int count;
|
||||
{
|
||||
var col = value as ICollection<KeyValuePair<TKey, TValue>>;
|
||||
if (col != null)
|
||||
{
|
||||
count = col.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
var col2 = value as IReadOnlyCollection<KeyValuePair<TKey, TValue>>;
|
||||
if (col2 != null)
|
||||
{
|
||||
count = col2.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new MessagePackSerializationException("DictionaryFormatterBase's TDictionary supports only ICollection<KVP> or IReadOnlyCollection<KVP>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writer.WriteMapHeader(count);
|
||||
|
||||
TEnumerator e = this.GetSourceEnumerator(value);
|
||||
try
|
||||
{
|
||||
while (e.MoveNext())
|
||||
{
|
||||
writer.CancellationToken.ThrowIfCancellationRequested();
|
||||
KeyValuePair<TKey, TValue> item = e.Current;
|
||||
keyFormatter.Serialize(ref writer, item.Key, options);
|
||||
valueFormatter.Serialize(ref writer, item.Value, options);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
e.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TDictionary Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.TryReadNil())
|
||||
{
|
||||
return default(TDictionary);
|
||||
}
|
||||
else
|
||||
{
|
||||
IFormatterResolver resolver = options.Resolver;
|
||||
IMessagePackFormatter<TKey> keyFormatter = resolver.GetFormatterWithVerify<TKey>();
|
||||
IMessagePackFormatter<TValue> valueFormatter = resolver.GetFormatterWithVerify<TValue>();
|
||||
|
||||
var len = reader.ReadMapHeader();
|
||||
|
||||
TIntermediate dict = this.Create(len, options);
|
||||
options.Security.DepthStep(ref reader);
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
reader.CancellationToken.ThrowIfCancellationRequested();
|
||||
TKey key = keyFormatter.Deserialize(ref reader, options);
|
||||
|
||||
TValue value = valueFormatter.Deserialize(ref reader, options);
|
||||
|
||||
this.Add(dict, i, key, value, options);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Depth--;
|
||||
}
|
||||
|
||||
return this.Complete(dict);
|
||||
}
|
||||
}
|
||||
|
||||
// abstraction for serialize
|
||||
|
||||
// Some collections can use struct iterator, this is optimization path
|
||||
protected abstract TEnumerator GetSourceEnumerator(TDictionary source);
|
||||
|
||||
// abstraction for deserialize
|
||||
protected abstract TIntermediate Create(int count, MessagePackSerializerOptions options);
|
||||
|
||||
protected abstract void Add(TIntermediate collection, int index, TKey key, TValue value, MessagePackSerializerOptions options);
|
||||
|
||||
protected abstract TDictionary Complete(TIntermediate intermediateCollection);
|
||||
}
|
||||
|
||||
public abstract class DictionaryFormatterBase<TKey, TValue, TIntermediate, TDictionary> : DictionaryFormatterBase<TKey, TValue, TIntermediate, IEnumerator<KeyValuePair<TKey, TValue>>, TDictionary>
|
||||
where TDictionary : IEnumerable<KeyValuePair<TKey, TValue>>
|
||||
{
|
||||
protected override IEnumerator<KeyValuePair<TKey, TValue>> GetSourceEnumerator(TDictionary source)
|
||||
{
|
||||
return source.GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class DictionaryFormatterBase<TKey, TValue, TDictionary> : DictionaryFormatterBase<TKey, TValue, TDictionary, TDictionary>
|
||||
where TDictionary : IDictionary<TKey, TValue>
|
||||
{
|
||||
protected override TDictionary Complete(TDictionary intermediateCollection)
|
||||
{
|
||||
return intermediateCollection;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DictionaryFormatter<TKey, TValue> : DictionaryFormatterBase<TKey, TValue, Dictionary<TKey, TValue>, Dictionary<TKey, TValue>.Enumerator, Dictionary<TKey, TValue>>
|
||||
{
|
||||
protected override void Add(Dictionary<TKey, TValue> collection, int index, TKey key, TValue value, MessagePackSerializerOptions options)
|
||||
{
|
||||
collection.Add(key, value);
|
||||
}
|
||||
|
||||
protected override Dictionary<TKey, TValue> Complete(Dictionary<TKey, TValue> intermediateCollection)
|
||||
{
|
||||
return intermediateCollection;
|
||||
}
|
||||
|
||||
protected override Dictionary<TKey, TValue> Create(int count, MessagePackSerializerOptions options)
|
||||
{
|
||||
return new Dictionary<TKey, TValue>(count, options.Security.GetEqualityComparer<TKey>());
|
||||
}
|
||||
|
||||
protected override Dictionary<TKey, TValue>.Enumerator GetSourceEnumerator(Dictionary<TKey, TValue> source)
|
||||
{
|
||||
return source.GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class GenericDictionaryFormatter<TKey, TValue, TDictionary> : DictionaryFormatterBase<TKey, TValue, TDictionary>
|
||||
where TDictionary : IDictionary<TKey, TValue>, new()
|
||||
{
|
||||
protected override void Add(TDictionary collection, int index, TKey key, TValue value, MessagePackSerializerOptions options)
|
||||
{
|
||||
collection.Add(key, value);
|
||||
}
|
||||
|
||||
protected override TDictionary Create(int count, MessagePackSerializerOptions options)
|
||||
{
|
||||
return CollectionHelpers<TDictionary, IEqualityComparer<TKey>>.CreateHashCollection(count, options.Security.GetEqualityComparer<TKey>());
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class InterfaceDictionaryFormatter<TKey, TValue> : DictionaryFormatterBase<TKey, TValue, Dictionary<TKey, TValue>, IDictionary<TKey, TValue>>
|
||||
{
|
||||
protected override void Add(Dictionary<TKey, TValue> collection, int index, TKey key, TValue value, MessagePackSerializerOptions options)
|
||||
{
|
||||
collection.Add(key, value);
|
||||
}
|
||||
|
||||
protected override Dictionary<TKey, TValue> Create(int count, MessagePackSerializerOptions options)
|
||||
{
|
||||
return new Dictionary<TKey, TValue>(count, options.Security.GetEqualityComparer<TKey>());
|
||||
}
|
||||
|
||||
protected override IDictionary<TKey, TValue> Complete(Dictionary<TKey, TValue> intermediateCollection)
|
||||
{
|
||||
return intermediateCollection;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class SortedListFormatter<TKey, TValue> : DictionaryFormatterBase<TKey, TValue, SortedList<TKey, TValue>>
|
||||
{
|
||||
protected override void Add(SortedList<TKey, TValue> collection, int index, TKey key, TValue value, MessagePackSerializerOptions options)
|
||||
{
|
||||
collection.Add(key, value);
|
||||
}
|
||||
|
||||
protected override SortedList<TKey, TValue> Create(int count, MessagePackSerializerOptions options)
|
||||
{
|
||||
return new SortedList<TKey, TValue>(count);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class SortedDictionaryFormatter<TKey, TValue> : DictionaryFormatterBase<TKey, TValue, SortedDictionary<TKey, TValue>, SortedDictionary<TKey, TValue>.Enumerator, SortedDictionary<TKey, TValue>>
|
||||
{
|
||||
protected override void Add(SortedDictionary<TKey, TValue> collection, int index, TKey key, TValue value, MessagePackSerializerOptions options)
|
||||
{
|
||||
collection.Add(key, value);
|
||||
}
|
||||
|
||||
protected override SortedDictionary<TKey, TValue> Complete(SortedDictionary<TKey, TValue> intermediateCollection)
|
||||
{
|
||||
return intermediateCollection;
|
||||
}
|
||||
|
||||
protected override SortedDictionary<TKey, TValue> Create(int count, MessagePackSerializerOptions options)
|
||||
{
|
||||
return new SortedDictionary<TKey, TValue>();
|
||||
}
|
||||
|
||||
protected override SortedDictionary<TKey, TValue>.Enumerator GetSourceEnumerator(SortedDictionary<TKey, TValue> source)
|
||||
{
|
||||
return source.GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ReadOnlyDictionaryFormatter<TKey, TValue> : DictionaryFormatterBase<TKey, TValue, Dictionary<TKey, TValue>, ReadOnlyDictionary<TKey, TValue>>
|
||||
{
|
||||
protected override void Add(Dictionary<TKey, TValue> collection, int index, TKey key, TValue value, MessagePackSerializerOptions options)
|
||||
{
|
||||
collection.Add(key, value);
|
||||
}
|
||||
|
||||
protected override ReadOnlyDictionary<TKey, TValue> Complete(Dictionary<TKey, TValue> intermediateCollection)
|
||||
{
|
||||
return new ReadOnlyDictionary<TKey, TValue>(intermediateCollection);
|
||||
}
|
||||
|
||||
protected override Dictionary<TKey, TValue> Create(int count, MessagePackSerializerOptions options)
|
||||
{
|
||||
return new Dictionary<TKey, TValue>(count, options.Security.GetEqualityComparer<TKey>());
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class InterfaceReadOnlyDictionaryFormatter<TKey, TValue> : DictionaryFormatterBase<TKey, TValue, Dictionary<TKey, TValue>, IReadOnlyDictionary<TKey, TValue>>
|
||||
{
|
||||
protected override void Add(Dictionary<TKey, TValue> collection, int index, TKey key, TValue value, MessagePackSerializerOptions options)
|
||||
{
|
||||
collection.Add(key, value);
|
||||
}
|
||||
|
||||
protected override IReadOnlyDictionary<TKey, TValue> Complete(Dictionary<TKey, TValue> intermediateCollection)
|
||||
{
|
||||
return intermediateCollection;
|
||||
}
|
||||
|
||||
protected override Dictionary<TKey, TValue> Create(int count, MessagePackSerializerOptions options)
|
||||
{
|
||||
return new Dictionary<TKey, TValue>(count, options.Security.GetEqualityComparer<TKey>());
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ConcurrentDictionaryFormatter<TKey, TValue> : DictionaryFormatterBase<TKey, TValue, System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue>>
|
||||
{
|
||||
protected override void Add(ConcurrentDictionary<TKey, TValue> collection, int index, TKey key, TValue value, MessagePackSerializerOptions options)
|
||||
{
|
||||
collection.TryAdd(key, value);
|
||||
}
|
||||
|
||||
protected override ConcurrentDictionary<TKey, TValue> Create(int count, MessagePackSerializerOptions options)
|
||||
{
|
||||
// concurrent dictionary can't access defaultConcurrecyLevel so does not use count overload.
|
||||
return new ConcurrentDictionary<TKey, TValue>(options.Security.GetEqualityComparer<TKey>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3f0984a238b11bd2c97eb781371bb121
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
// 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.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
/// <summary>
|
||||
/// This formatter can serialize any value whose static type is <see cref="object"/>
|
||||
/// for which another resolver can provide a formatter for the runtime type.
|
||||
/// Its deserialization is limited to forwarding all calls to the <see cref="PrimitiveObjectFormatter"/>.
|
||||
/// </summary>
|
||||
public sealed class DynamicObjectTypeFallbackFormatter : IMessagePackFormatter<object>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<object> Instance = new DynamicObjectTypeFallbackFormatter();
|
||||
|
||||
private delegate void SerializeMethod(object dynamicFormatter, ref MessagePackWriter writer, object value, MessagePackSerializerOptions options);
|
||||
|
||||
private static readonly Internal.ThreadsafeTypeKeyHashTable<SerializeMethod> SerializerDelegates = new Internal.ThreadsafeTypeKeyHashTable<SerializeMethod>();
|
||||
|
||||
private DynamicObjectTypeFallbackFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, object value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
return;
|
||||
}
|
||||
|
||||
Type type = value.GetType();
|
||||
TypeInfo ti = type.GetTypeInfo();
|
||||
|
||||
if (type == typeof(object))
|
||||
{
|
||||
// serialize to empty map
|
||||
writer.WriteMapHeader(0);
|
||||
return;
|
||||
}
|
||||
|
||||
object formatter = options.Resolver.GetFormatterDynamicWithVerify(type);
|
||||
if (!SerializerDelegates.TryGetValue(type, out SerializeMethod serializerDelegate))
|
||||
{
|
||||
lock (SerializerDelegates)
|
||||
{
|
||||
if (!SerializerDelegates.TryGetValue(type, out serializerDelegate))
|
||||
{
|
||||
Type formatterType = typeof(IMessagePackFormatter<>).MakeGenericType(type);
|
||||
ParameterExpression param0 = Expression.Parameter(typeof(object), "formatter");
|
||||
ParameterExpression param1 = Expression.Parameter(typeof(MessagePackWriter).MakeByRefType(), "writer");
|
||||
ParameterExpression param2 = Expression.Parameter(typeof(object), "value");
|
||||
ParameterExpression param3 = Expression.Parameter(typeof(MessagePackSerializerOptions), "options");
|
||||
|
||||
MethodInfo serializeMethodInfo = formatterType.GetRuntimeMethod("Serialize", new[] { typeof(MessagePackWriter).MakeByRefType(), type, typeof(MessagePackSerializerOptions) });
|
||||
|
||||
MethodCallExpression body = Expression.Call(
|
||||
Expression.Convert(param0, formatterType),
|
||||
serializeMethodInfo,
|
||||
param1,
|
||||
ti.IsValueType ? Expression.Unbox(param2, type) : Expression.Convert(param2, type),
|
||||
param3);
|
||||
|
||||
serializerDelegate = Expression.Lambda<SerializeMethod>(body, param0, param1, param2, param3).Compile();
|
||||
|
||||
SerializerDelegates.TryAdd(type, serializerDelegate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
serializerDelegate(formatter, ref writer, value, options);
|
||||
}
|
||||
|
||||
public object Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
return PrimitiveObjectFormatter.Instance.Deserialize(ref reader, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bc47abc7cd51279d9ac40fe1da6ffa1d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
128
Assets/Scripts/MessagePack/Formatters/EnumAsStringFormatter`1.cs
Normal file
128
Assets/Scripts/MessagePack/Formatters/EnumAsStringFormatter`1.cs
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
// 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.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
// Note:This implementation is 'not' fastest, should more improve.
|
||||
public sealed class EnumAsStringFormatter<T> : IMessagePackFormatter<T>
|
||||
{
|
||||
private readonly IReadOnlyDictionary<string, T> nameValueMapping;
|
||||
private readonly IReadOnlyDictionary<T, string> valueNameMapping;
|
||||
private readonly IReadOnlyDictionary<string, string> clrToSerializationName;
|
||||
private readonly IReadOnlyDictionary<string, string> serializationToClrName;
|
||||
private readonly bool enumMemberOverridesPresent;
|
||||
private readonly bool isFlags;
|
||||
|
||||
public EnumAsStringFormatter()
|
||||
{
|
||||
this.isFlags = typeof(T).GetCustomAttribute<FlagsAttribute>() is object;
|
||||
|
||||
var fields = typeof(T).GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Static);
|
||||
var nameValueMapping = new Dictionary<string, T>(fields.Length);
|
||||
var valueNameMapping = new Dictionary<T, string>();
|
||||
Dictionary<string, string> clrToSerializationName = null;
|
||||
Dictionary<string, string> serializationToClrName = null;
|
||||
|
||||
foreach (FieldInfo enumValueMember in fields)
|
||||
{
|
||||
string name = enumValueMember.Name;
|
||||
T value = (T)enumValueMember.GetValue(null);
|
||||
|
||||
// Consider the case where the serialized form of the enum value is overridden via an attribute.
|
||||
var attribute = enumValueMember.GetCustomAttribute<EnumMemberAttribute>();
|
||||
if (attribute?.IsValueSetExplicitly ?? false)
|
||||
{
|
||||
clrToSerializationName = clrToSerializationName ?? new Dictionary<string, string>();
|
||||
serializationToClrName = serializationToClrName ?? new Dictionary<string, string>();
|
||||
|
||||
clrToSerializationName.Add(name, attribute.Value);
|
||||
serializationToClrName.Add(attribute.Value, name);
|
||||
|
||||
name = attribute.Value;
|
||||
this.enumMemberOverridesPresent = true;
|
||||
}
|
||||
|
||||
nameValueMapping[name] = value;
|
||||
valueNameMapping[value] = name;
|
||||
}
|
||||
|
||||
this.nameValueMapping = nameValueMapping;
|
||||
this.valueNameMapping = valueNameMapping;
|
||||
this.clrToSerializationName = clrToSerializationName;
|
||||
this.serializationToClrName = serializationToClrName;
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, T value, MessagePackSerializerOptions options)
|
||||
{
|
||||
// Enum.ToString() is slow, so avoid it when we can.
|
||||
if (!this.valueNameMapping.TryGetValue(value, out string valueString))
|
||||
{
|
||||
// fallback for flags, values with no name, etc
|
||||
valueString = this.GetSerializedNames(value.ToString());
|
||||
}
|
||||
|
||||
writer.Write(valueString);
|
||||
}
|
||||
|
||||
public T Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
string name = reader.ReadString();
|
||||
|
||||
// Avoid Enum.Parse when we can because it is too slow.
|
||||
if (!this.nameValueMapping.TryGetValue(name, out T value))
|
||||
{
|
||||
value = (T)Enum.Parse(typeof(T), this.GetClrNames(name));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private string GetClrNames(string serializedNames)
|
||||
{
|
||||
if (this.enumMemberOverridesPresent && this.isFlags && serializedNames.IndexOf(", ", StringComparison.Ordinal) >= 0)
|
||||
{
|
||||
return Translate(serializedNames, this.serializationToClrName);
|
||||
}
|
||||
|
||||
// We don't need to consider the trivial case of no commas because our caller would have found that in the lookup table and not called us.
|
||||
return serializedNames;
|
||||
}
|
||||
|
||||
private string GetSerializedNames(string clrNames)
|
||||
{
|
||||
if (this.enumMemberOverridesPresent && this.isFlags && clrNames.IndexOf(", ", StringComparison.Ordinal) >= 0)
|
||||
{
|
||||
return Translate(clrNames, this.clrToSerializationName);
|
||||
}
|
||||
|
||||
// We don't need to consider the trivial case of no commas because our caller would have found that in the lookup table and not called us.
|
||||
return clrNames;
|
||||
}
|
||||
|
||||
private static string Translate(string items, IReadOnlyDictionary<string, string> mapping)
|
||||
{
|
||||
string[] elements = items.Split(',');
|
||||
|
||||
for (int i = 0; i < elements.Length; i++)
|
||||
{
|
||||
// Trim the leading space if there is one (due to the delimiter being ", ").
|
||||
if (i > 0 && elements[i].Length > 0 && elements[i][0] == ' ')
|
||||
{
|
||||
elements[i] = elements[i].Substring(1);
|
||||
}
|
||||
|
||||
if (mapping.TryGetValue(elements[i], out string substituteValue))
|
||||
{
|
||||
elements[i] = substituteValue;
|
||||
}
|
||||
}
|
||||
|
||||
return string.Join(", ", elements);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f7cdc1e759af9873989648baa08f0350
|
||||
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.Runtime.CompilerServices;
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
public sealed class GenericEnumFormatter<T> : IMessagePackFormatter<T>
|
||||
where T : Enum
|
||||
{
|
||||
private delegate void EnumSerialize(ref MessagePackWriter writer, ref T value);
|
||||
|
||||
private delegate T EnumDeserialize(ref MessagePackReader reader);
|
||||
|
||||
private readonly EnumSerialize serializer;
|
||||
private readonly EnumDeserialize deserializer;
|
||||
|
||||
public GenericEnumFormatter()
|
||||
{
|
||||
var underlyingType = typeof(T).GetEnumUnderlyingType();
|
||||
switch (Type.GetTypeCode(underlyingType))
|
||||
{
|
||||
#pragma warning disable SA1107 // Avoid multiple statements on same line.
|
||||
case TypeCode.Byte:
|
||||
serializer = (ref MessagePackWriter writer, ref T value) => writer.Write(Unsafe.As<T, Byte>(ref value));
|
||||
deserializer = (ref MessagePackReader reader) => { var v = reader.ReadByte(); return Unsafe.As<Byte, T>(ref v); };
|
||||
break;
|
||||
case TypeCode.Int16:
|
||||
serializer = (ref MessagePackWriter writer, ref T value) => writer.Write(Unsafe.As<T, Int16>(ref value));
|
||||
deserializer = (ref MessagePackReader reader) => { var v = reader.ReadInt16(); return Unsafe.As<Int16, T>(ref v); };
|
||||
break;
|
||||
case TypeCode.Int32:
|
||||
serializer = (ref MessagePackWriter writer, ref T value) => writer.Write(Unsafe.As<T, Int32>(ref value));
|
||||
deserializer = (ref MessagePackReader reader) => { var v = reader.ReadInt32(); return Unsafe.As<Int32, T>(ref v); };
|
||||
break;
|
||||
case TypeCode.Int64:
|
||||
serializer = (ref MessagePackWriter writer, ref T value) => writer.Write(Unsafe.As<T, Int64>(ref value));
|
||||
deserializer = (ref MessagePackReader reader) => { var v = reader.ReadInt64(); return Unsafe.As<Int64, T>(ref v); };
|
||||
break;
|
||||
case TypeCode.SByte:
|
||||
serializer = (ref MessagePackWriter writer, ref T value) => writer.Write(Unsafe.As<T, SByte>(ref value));
|
||||
deserializer = (ref MessagePackReader reader) => { var v = reader.ReadSByte(); return Unsafe.As<SByte, T>(ref v); };
|
||||
break;
|
||||
case TypeCode.UInt16:
|
||||
serializer = (ref MessagePackWriter writer, ref T value) => writer.Write(Unsafe.As<T, UInt16>(ref value));
|
||||
deserializer = (ref MessagePackReader reader) => { var v = reader.ReadUInt16(); return Unsafe.As<UInt16, T>(ref v); };
|
||||
break;
|
||||
case TypeCode.UInt32:
|
||||
serializer = (ref MessagePackWriter writer, ref T value) => writer.Write(Unsafe.As<T, UInt32>(ref value));
|
||||
deserializer = (ref MessagePackReader reader) => { var v = reader.ReadUInt32(); return Unsafe.As<UInt32, T>(ref v); };
|
||||
break;
|
||||
case TypeCode.UInt64:
|
||||
serializer = (ref MessagePackWriter writer, ref T value) => writer.Write(Unsafe.As<T, UInt64>(ref value));
|
||||
deserializer = (ref MessagePackReader reader) => { var v = reader.ReadUInt64(); return Unsafe.As<UInt64, T>(ref v); };
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
#pragma warning restore SA1107 // Avoid multiple statements on same line.
|
||||
}
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, T value, MessagePackSerializerOptions options)
|
||||
{
|
||||
serializer(ref writer, ref value);
|
||||
}
|
||||
|
||||
public T Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
return deserializer(ref reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7f3275d9a9f3275ec9cc43d6859964fe
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
// 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.Buffers;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
#pragma warning disable SA1649 // File name should match first type name
|
||||
/// <summary>
|
||||
/// A base interface for <see cref="IMessagePackFormatter{T}"/> so that all generic implementations
|
||||
/// can be detected by a common base type.
|
||||
/// </summary>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public interface IMessagePackFormatter
|
||||
{
|
||||
}
|
||||
#pragma warning restore SA1649 // File name should match first type name
|
||||
|
||||
/// <summary>
|
||||
/// The contract for serialization of some specific type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to be serialized or deserialized.</typeparam>
|
||||
public interface IMessagePackFormatter<T> : IMessagePackFormatter
|
||||
{
|
||||
/// <summary>
|
||||
/// Serializes a value.
|
||||
/// </summary>
|
||||
/// <param name="writer">The writer to use when serializing the value.</param>
|
||||
/// <param name="value">The value to be serialized.</param>
|
||||
/// <param name="options">The serialization settings to use, including the resolver to use to obtain formatters for types that make up the composite type <typeparamref name="T"/>.</param>
|
||||
void Serialize(ref MessagePackWriter writer, T value, MessagePackSerializerOptions options);
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes a value.
|
||||
/// </summary>
|
||||
/// <param name="reader">The reader to deserialize from.</param>
|
||||
/// <param name="options">The serialization settings to use, including the resolver to use to obtain formatters for types that make up the composite type <typeparamref name="T"/>.</param>
|
||||
/// <returns>The deserialized value.</returns>
|
||||
T Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cd75a2bcccf20dfb6824d447ec99a1fa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
21
Assets/Scripts/MessagePack/Formatters/IgnoreFormatter`1.cs
Normal file
21
Assets/Scripts/MessagePack/Formatters/IgnoreFormatter`1.cs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
// 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.Buffers;
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
public sealed class IgnoreFormatter<T> : IMessagePackFormatter<T>
|
||||
{
|
||||
public void Serialize(ref MessagePackWriter writer, T value, MessagePackSerializerOptions options)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
|
||||
public T Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
reader.Skip();
|
||||
return default(T);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 64fa7163708478803a466c61cdb596d6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,293 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
#pragma warning disable SA1649 // File name should match first type name
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
/* multi dimensional array serialize to [i, j, [seq]] */
|
||||
|
||||
public sealed class TwoDimensionalArrayFormatter<T> : IMessagePackFormatter<T[,]>
|
||||
{
|
||||
private const int ArrayLength = 3;
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, T[,] value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
else
|
||||
{
|
||||
var i = value.GetLength(0);
|
||||
var j = value.GetLength(1);
|
||||
|
||||
IMessagePackFormatter<T> formatter = options.Resolver.GetFormatterWithVerify<T>();
|
||||
|
||||
writer.WriteArrayHeader(ArrayLength);
|
||||
writer.Write(i);
|
||||
writer.Write(j);
|
||||
|
||||
writer.WriteArrayHeader(value.Length);
|
||||
foreach (T item in value)
|
||||
{
|
||||
writer.CancellationToken.ThrowIfCancellationRequested();
|
||||
formatter.Serialize(ref writer, item, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public T[,] Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.TryReadNil())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
IMessagePackFormatter<T> formatter = options.Resolver.GetFormatterWithVerify<T>();
|
||||
|
||||
var len = reader.ReadArrayHeader();
|
||||
if (len != ArrayLength)
|
||||
{
|
||||
throw new MessagePackSerializationException("Invalid T[,] format");
|
||||
}
|
||||
|
||||
var iLength = reader.ReadInt32();
|
||||
var jLength = reader.ReadInt32();
|
||||
var maxLen = reader.ReadArrayHeader();
|
||||
|
||||
var array = new T[iLength, jLength];
|
||||
|
||||
var i = 0;
|
||||
var j = -1;
|
||||
options.Security.DepthStep(ref reader);
|
||||
try
|
||||
{
|
||||
for (int loop = 0; loop < maxLen; loop++)
|
||||
{
|
||||
reader.CancellationToken.ThrowIfCancellationRequested();
|
||||
if (j < jLength - 1)
|
||||
{
|
||||
j++;
|
||||
}
|
||||
else
|
||||
{
|
||||
j = 0;
|
||||
i++;
|
||||
}
|
||||
|
||||
array[i, j] = formatter.Deserialize(ref reader, options);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Depth--;
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ThreeDimensionalArrayFormatter<T> : IMessagePackFormatter<T[,,]>
|
||||
{
|
||||
private const int ArrayLength = 4;
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, T[,,] value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
else
|
||||
{
|
||||
var i = value.GetLength(0);
|
||||
var j = value.GetLength(1);
|
||||
var k = value.GetLength(2);
|
||||
|
||||
IMessagePackFormatter<T> formatter = options.Resolver.GetFormatterWithVerify<T>();
|
||||
|
||||
writer.WriteArrayHeader(ArrayLength);
|
||||
writer.Write(i);
|
||||
writer.Write(j);
|
||||
writer.Write(k);
|
||||
|
||||
writer.WriteArrayHeader(value.Length);
|
||||
foreach (T item in value)
|
||||
{
|
||||
writer.CancellationToken.ThrowIfCancellationRequested();
|
||||
formatter.Serialize(ref writer, item, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public T[,,] Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.TryReadNil())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
IMessagePackFormatter<T> formatter = options.Resolver.GetFormatterWithVerify<T>();
|
||||
|
||||
var len = reader.ReadArrayHeader();
|
||||
if (len != ArrayLength)
|
||||
{
|
||||
throw new MessagePackSerializationException("Invalid T[,,] format");
|
||||
}
|
||||
|
||||
var iLength = reader.ReadInt32();
|
||||
var jLength = reader.ReadInt32();
|
||||
var kLength = reader.ReadInt32();
|
||||
var maxLen = reader.ReadArrayHeader();
|
||||
|
||||
var array = new T[iLength, jLength, kLength];
|
||||
|
||||
var i = 0;
|
||||
var j = 0;
|
||||
var k = -1;
|
||||
options.Security.DepthStep(ref reader);
|
||||
try
|
||||
{
|
||||
for (int loop = 0; loop < maxLen; loop++)
|
||||
{
|
||||
reader.CancellationToken.ThrowIfCancellationRequested();
|
||||
if (k < kLength - 1)
|
||||
{
|
||||
k++;
|
||||
}
|
||||
else if (j < jLength - 1)
|
||||
{
|
||||
k = 0;
|
||||
j++;
|
||||
}
|
||||
else
|
||||
{
|
||||
k = 0;
|
||||
j = 0;
|
||||
i++;
|
||||
}
|
||||
|
||||
array[i, j, k] = formatter.Deserialize(ref reader, options);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Depth--;
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class FourDimensionalArrayFormatter<T> : IMessagePackFormatter<T[,,,]>
|
||||
{
|
||||
private const int ArrayLength = 5;
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, T[,,,] value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
else
|
||||
{
|
||||
var i = value.GetLength(0);
|
||||
var j = value.GetLength(1);
|
||||
var k = value.GetLength(2);
|
||||
var l = value.GetLength(3);
|
||||
|
||||
IMessagePackFormatter<T> formatter = options.Resolver.GetFormatterWithVerify<T>();
|
||||
|
||||
writer.WriteArrayHeader(ArrayLength);
|
||||
writer.Write(i);
|
||||
writer.Write(j);
|
||||
writer.Write(k);
|
||||
writer.Write(l);
|
||||
|
||||
writer.WriteArrayHeader(value.Length);
|
||||
foreach (T item in value)
|
||||
{
|
||||
writer.CancellationToken.ThrowIfCancellationRequested();
|
||||
formatter.Serialize(ref writer, item, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public T[,,,] Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.TryReadNil())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
IMessagePackFormatter<T> formatter = options.Resolver.GetFormatterWithVerify<T>();
|
||||
|
||||
var len = reader.ReadArrayHeader();
|
||||
if (len != ArrayLength)
|
||||
{
|
||||
throw new MessagePackSerializationException("Invalid T[,,,] format");
|
||||
}
|
||||
|
||||
var iLength = reader.ReadInt32();
|
||||
var jLength = reader.ReadInt32();
|
||||
var kLength = reader.ReadInt32();
|
||||
var lLength = reader.ReadInt32();
|
||||
var maxLen = reader.ReadArrayHeader();
|
||||
var array = new T[iLength, jLength, kLength, lLength];
|
||||
|
||||
var i = 0;
|
||||
var j = 0;
|
||||
var k = 0;
|
||||
var l = -1;
|
||||
options.Security.DepthStep(ref reader);
|
||||
try
|
||||
{
|
||||
for (int loop = 0; loop < maxLen; loop++)
|
||||
{
|
||||
reader.CancellationToken.ThrowIfCancellationRequested();
|
||||
if (l < lLength - 1)
|
||||
{
|
||||
l++;
|
||||
}
|
||||
else if (k < kLength - 1)
|
||||
{
|
||||
l = 0;
|
||||
k++;
|
||||
}
|
||||
else if (j < jLength - 1)
|
||||
{
|
||||
l = 0;
|
||||
k = 0;
|
||||
j++;
|
||||
}
|
||||
else
|
||||
{
|
||||
l = 0;
|
||||
k = 0;
|
||||
j = 0;
|
||||
i++;
|
||||
}
|
||||
|
||||
array[i, j, k, l] = formatter.Deserialize(ref reader, options);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Depth--;
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8a4af86ee0f0a74de9e88b1fe8c9826d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
44
Assets/Scripts/MessagePack/Formatters/NilFormatter.cs
Normal file
44
Assets/Scripts/MessagePack/Formatters/NilFormatter.cs
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
public class NilFormatter : IMessagePackFormatter<Nil>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<Nil> Instance = new NilFormatter();
|
||||
|
||||
private NilFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, Nil value, MessagePackSerializerOptions options)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
|
||||
public Nil Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
return reader.ReadNil();
|
||||
}
|
||||
}
|
||||
|
||||
// NullableNil is same as Nil.
|
||||
public class NullableNilFormatter : IMessagePackFormatter<Nil?>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<Nil?> Instance = new NullableNilFormatter();
|
||||
|
||||
private NullableNilFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, Nil? value, MessagePackSerializerOptions options)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
|
||||
public Nil? Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
return reader.ReadNil();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/MessagePack/Formatters/NilFormatter.cs.meta
Normal file
11
Assets/Scripts/MessagePack/Formatters/NilFormatter.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 708c91d45dcbf19469504ec78aa2abee
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
73
Assets/Scripts/MessagePack/Formatters/NullableFormatter.cs
Normal file
73
Assets/Scripts/MessagePack/Formatters/NullableFormatter.cs
Normal file
|
|
@ -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.Buffers;
|
||||
|
||||
#pragma warning disable SA1649 // File name should match first type name
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
public sealed class NullableFormatter<T> : IMessagePackFormatter<T?>
|
||||
where T : struct
|
||||
{
|
||||
public void Serialize(ref MessagePackWriter writer, T? value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
else
|
||||
{
|
||||
options.Resolver.GetFormatterWithVerify<T>().Serialize(ref writer, value.Value, options);
|
||||
}
|
||||
}
|
||||
|
||||
public T? Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.IsNil)
|
||||
{
|
||||
reader.ReadNil();
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return options.Resolver.GetFormatterWithVerify<T>().Deserialize(ref reader, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class StaticNullableFormatter<T> : IMessagePackFormatter<T?>
|
||||
where T : struct
|
||||
{
|
||||
private readonly IMessagePackFormatter<T> underlyingFormatter;
|
||||
|
||||
public StaticNullableFormatter(IMessagePackFormatter<T> underlyingFormatter)
|
||||
{
|
||||
this.underlyingFormatter = underlyingFormatter;
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, T? value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.underlyingFormatter.Serialize(ref writer, value.Value, options);
|
||||
}
|
||||
}
|
||||
|
||||
public T? Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.TryReadNil())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.underlyingFormatter.Deserialize(ref reader, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 88e906d65ee7d29d3ae1fb5865b8f6ab
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,337 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
public sealed class PrimitiveObjectFormatter : IMessagePackFormatter<object>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<object> Instance = new PrimitiveObjectFormatter();
|
||||
|
||||
private static readonly Dictionary<Type, int> TypeToJumpCode = new Dictionary<Type, int>()
|
||||
{
|
||||
// When adding types whose size exceeds 32-bits, add support in MessagePackSecurity.GetHashCollisionResistantEqualityComparer<T>()
|
||||
{ typeof(Boolean), 0 },
|
||||
{ typeof(Char), 1 },
|
||||
{ typeof(SByte), 2 },
|
||||
{ typeof(Byte), 3 },
|
||||
{ typeof(Int16), 4 },
|
||||
{ typeof(UInt16), 5 },
|
||||
{ typeof(Int32), 6 },
|
||||
{ typeof(UInt32), 7 },
|
||||
{ typeof(Int64), 8 },
|
||||
{ typeof(UInt64), 9 },
|
||||
{ typeof(Single), 10 },
|
||||
{ typeof(Double), 11 },
|
||||
{ typeof(DateTime), 12 },
|
||||
{ typeof(string), 13 },
|
||||
{ typeof(byte[]), 14 },
|
||||
};
|
||||
|
||||
private PrimitiveObjectFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
#if !UNITY_2018_3_OR_NEWER
|
||||
|
||||
public static bool IsSupportedType(Type type, TypeInfo typeInfo, object value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TypeToJumpCode.ContainsKey(type))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (typeInfo.IsEnum)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (value is System.Collections.IDictionary)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (value is System.Collections.ICollection)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, object value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
return;
|
||||
}
|
||||
|
||||
Type t = value.GetType();
|
||||
|
||||
int code;
|
||||
if (TypeToJumpCode.TryGetValue(t, out code))
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case 0:
|
||||
writer.Write((bool)value);
|
||||
return;
|
||||
case 1:
|
||||
writer.Write((char)value);
|
||||
return;
|
||||
case 2:
|
||||
writer.WriteInt8((sbyte)value);
|
||||
return;
|
||||
case 3:
|
||||
writer.WriteUInt8((byte)value);
|
||||
return;
|
||||
case 4:
|
||||
writer.WriteInt16((Int16)value);
|
||||
return;
|
||||
case 5:
|
||||
writer.WriteUInt16((UInt16)value);
|
||||
return;
|
||||
case 6:
|
||||
writer.WriteInt32((Int32)value);
|
||||
return;
|
||||
case 7:
|
||||
writer.WriteUInt32((UInt32)value);
|
||||
return;
|
||||
case 8:
|
||||
writer.WriteInt64((Int64)value);
|
||||
return;
|
||||
case 9:
|
||||
writer.WriteUInt64((UInt64)value);
|
||||
return;
|
||||
case 10:
|
||||
writer.Write((Single)value);
|
||||
return;
|
||||
case 11:
|
||||
writer.Write((double)value);
|
||||
return;
|
||||
case 12:
|
||||
writer.Write((DateTime)value);
|
||||
return;
|
||||
case 13:
|
||||
writer.Write((string)value);
|
||||
return;
|
||||
case 14:
|
||||
writer.Write((byte[])value);
|
||||
return;
|
||||
default:
|
||||
throw new MessagePackSerializationException("Not supported primitive object resolver. type:" + t.Name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#if UNITY_2018_3_OR_NEWER && !NETFX_CORE
|
||||
if (t.IsEnum)
|
||||
#else
|
||||
if (t.GetTypeInfo().IsEnum)
|
||||
#endif
|
||||
{
|
||||
Type underlyingType = Enum.GetUnderlyingType(t);
|
||||
var code2 = TypeToJumpCode[underlyingType];
|
||||
switch (code2)
|
||||
{
|
||||
case 2:
|
||||
writer.WriteInt8((sbyte)value);
|
||||
return;
|
||||
case 3:
|
||||
writer.WriteUInt8((byte)value);
|
||||
return;
|
||||
case 4:
|
||||
writer.WriteInt16((Int16)value);
|
||||
return;
|
||||
case 5:
|
||||
writer.WriteUInt16((UInt16)value);
|
||||
return;
|
||||
case 6:
|
||||
writer.WriteInt32((Int32)value);
|
||||
return;
|
||||
case 7:
|
||||
writer.WriteUInt32((UInt32)value);
|
||||
return;
|
||||
case 8:
|
||||
writer.WriteInt64((Int64)value);
|
||||
return;
|
||||
case 9:
|
||||
writer.WriteUInt64((UInt64)value);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (value is System.Collections.IDictionary)
|
||||
{
|
||||
// check IDictionary first
|
||||
var d = value as System.Collections.IDictionary;
|
||||
writer.WriteMapHeader(d.Count);
|
||||
foreach (System.Collections.DictionaryEntry item in d)
|
||||
{
|
||||
this.Serialize(ref writer, item.Key, options);
|
||||
this.Serialize(ref writer, item.Value, options);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else if (value is System.Collections.ICollection)
|
||||
{
|
||||
var c = value as System.Collections.ICollection;
|
||||
writer.WriteArrayHeader(c.Count);
|
||||
foreach (var item in c)
|
||||
{
|
||||
this.Serialize(ref writer, item, options);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new MessagePackSerializationException("Not supported primitive object resolver. type:" + t.Name);
|
||||
}
|
||||
|
||||
public object Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
MessagePackType type = reader.NextMessagePackType;
|
||||
IFormatterResolver resolver = options.Resolver;
|
||||
switch (type)
|
||||
{
|
||||
case MessagePackType.Integer:
|
||||
var code = reader.NextCode;
|
||||
if (code >= MessagePackCode.MinNegativeFixInt && code <= MessagePackCode.MaxNegativeFixInt)
|
||||
{
|
||||
return reader.ReadSByte();
|
||||
}
|
||||
else if (code >= MessagePackCode.MinFixInt && code <= MessagePackCode.MaxFixInt)
|
||||
{
|
||||
return reader.ReadByte();
|
||||
}
|
||||
else if (code == MessagePackCode.Int8)
|
||||
{
|
||||
return reader.ReadSByte();
|
||||
}
|
||||
else if (code == MessagePackCode.Int16)
|
||||
{
|
||||
return reader.ReadInt16();
|
||||
}
|
||||
else if (code == MessagePackCode.Int32)
|
||||
{
|
||||
return reader.ReadInt32();
|
||||
}
|
||||
else if (code == MessagePackCode.Int64)
|
||||
{
|
||||
return reader.ReadInt64();
|
||||
}
|
||||
else if (code == MessagePackCode.UInt8)
|
||||
{
|
||||
return reader.ReadByte();
|
||||
}
|
||||
else if (code == MessagePackCode.UInt16)
|
||||
{
|
||||
return reader.ReadUInt16();
|
||||
}
|
||||
else if (code == MessagePackCode.UInt32)
|
||||
{
|
||||
return reader.ReadUInt32();
|
||||
}
|
||||
else if (code == MessagePackCode.UInt64)
|
||||
{
|
||||
return reader.ReadUInt64();
|
||||
}
|
||||
|
||||
throw new MessagePackSerializationException("Invalid primitive bytes.");
|
||||
case MessagePackType.Boolean:
|
||||
return reader.ReadBoolean();
|
||||
case MessagePackType.Float:
|
||||
if (reader.NextCode == MessagePackCode.Float32)
|
||||
{
|
||||
return reader.ReadSingle();
|
||||
}
|
||||
else
|
||||
{
|
||||
return reader.ReadDouble();
|
||||
}
|
||||
|
||||
case MessagePackType.String:
|
||||
return reader.ReadString();
|
||||
case MessagePackType.Binary:
|
||||
// We must copy the sequence returned by ReadBytes since the reader's sequence is only valid during deserialization.
|
||||
return reader.ReadBytes()?.ToArray();
|
||||
case MessagePackType.Extension:
|
||||
ExtensionHeader ext = reader.ReadExtensionFormatHeader();
|
||||
if (ext.TypeCode == ReservedMessagePackExtensionTypeCode.DateTime)
|
||||
{
|
||||
return reader.ReadDateTime(ext);
|
||||
}
|
||||
|
||||
throw new MessagePackSerializationException("Invalid primitive bytes.");
|
||||
case MessagePackType.Array:
|
||||
{
|
||||
var length = reader.ReadArrayHeader();
|
||||
|
||||
IMessagePackFormatter<object> objectFormatter = resolver.GetFormatter<object>();
|
||||
var array = new object[length];
|
||||
options.Security.DepthStep(ref reader);
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
array[i] = objectFormatter.Deserialize(ref reader, options);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Depth--;
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
case MessagePackType.Map:
|
||||
{
|
||||
var length = reader.ReadMapHeader();
|
||||
|
||||
IMessagePackFormatter<object> objectFormatter = resolver.GetFormatter<object>();
|
||||
var hash = new Dictionary<object, object>(length, options.Security.GetEqualityComparer<object>());
|
||||
options.Security.DepthStep(ref reader);
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
var key = objectFormatter.Deserialize(ref reader, options);
|
||||
|
||||
var value = objectFormatter.Deserialize(ref reader, options);
|
||||
|
||||
hash.Add(key, value);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Depth--;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
case MessagePackType.Nil:
|
||||
reader.ReadNil();
|
||||
return null;
|
||||
default:
|
||||
throw new MessagePackSerializationException("Invalid primitive bytes.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d46d293dc804af1669409cc12690a3ad
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,599 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using MessagePack.Internal;
|
||||
|
||||
#pragma warning disable SA1649 // File name should match first type name
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
// NET40 -> BigInteger, Complex, Tuple
|
||||
|
||||
// byte[] is special. represents bin type.
|
||||
public sealed class ByteArrayFormatter : IMessagePackFormatter<byte[]>
|
||||
{
|
||||
public static readonly ByteArrayFormatter Instance = new ByteArrayFormatter();
|
||||
|
||||
private ByteArrayFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, byte[] value, MessagePackSerializerOptions options)
|
||||
{
|
||||
writer.Write(value);
|
||||
}
|
||||
|
||||
public byte[] Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
return reader.ReadBytes()?.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class NullableStringFormatter : IMessagePackFormatter<String>
|
||||
{
|
||||
public static readonly NullableStringFormatter Instance = new NullableStringFormatter();
|
||||
|
||||
private NullableStringFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, string value, MessagePackSerializerOptions options)
|
||||
{
|
||||
writer.Write(value);
|
||||
}
|
||||
|
||||
public string Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
return reader.ReadString();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class NullableStringArrayFormatter : IMessagePackFormatter<String[]>
|
||||
{
|
||||
public static readonly NullableStringArrayFormatter Instance = new NullableStringArrayFormatter();
|
||||
|
||||
private NullableStringArrayFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, String[] value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteArrayHeader(value.Length);
|
||||
for (int i = 0; i < value.Length; i++)
|
||||
{
|
||||
writer.Write(value[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String[] Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.TryReadNil())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var len = reader.ReadArrayHeader();
|
||||
var array = new String[len];
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
array[i] = reader.ReadString();
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DecimalFormatter : IMessagePackFormatter<Decimal>
|
||||
{
|
||||
public static readonly DecimalFormatter Instance = new DecimalFormatter();
|
||||
|
||||
private DecimalFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, decimal value, MessagePackSerializerOptions options)
|
||||
{
|
||||
var dest = writer.GetSpan(MessagePackRange.MaxFixStringLength);
|
||||
if (System.Buffers.Text.Utf8Formatter.TryFormat(value, dest.Slice(1), out var written))
|
||||
{
|
||||
// write header
|
||||
dest[0] = (byte)(MessagePackCode.MinFixStr | written);
|
||||
writer.Advance(written + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// reset writer's span previously acquired that does not use
|
||||
writer.Advance(0);
|
||||
writer.Write(value.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
}
|
||||
|
||||
public decimal Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (!(reader.ReadStringSequence() is ReadOnlySequence<byte> sequence))
|
||||
{
|
||||
throw new MessagePackSerializationException(string.Format("Unexpected msgpack code {0} ({1}) encountered.", MessagePackCode.Nil, MessagePackCode.ToFormatName(MessagePackCode.Nil)));
|
||||
}
|
||||
|
||||
if (sequence.IsSingleSegment)
|
||||
{
|
||||
var span = sequence.First.Span;
|
||||
if (System.Buffers.Text.Utf8Parser.TryParse(span, out decimal result, out var bytesConsumed))
|
||||
{
|
||||
if (span.Length != bytesConsumed)
|
||||
{
|
||||
throw new MessagePackSerializationException("Unexpected length of string.");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// sequence.Length is not free
|
||||
var seqLen = (int)sequence.Length;
|
||||
if (seqLen < 128)
|
||||
{
|
||||
Span<byte> span = stackalloc byte[seqLen];
|
||||
sequence.CopyTo(span);
|
||||
if (System.Buffers.Text.Utf8Parser.TryParse(span, out decimal result, out var bytesConsumed))
|
||||
{
|
||||
if (seqLen != bytesConsumed)
|
||||
{
|
||||
throw new MessagePackSerializationException("Unexpected length of string.");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var rentArray = ArrayPool<byte>.Shared.Rent(seqLen);
|
||||
try
|
||||
{
|
||||
sequence.CopyTo(rentArray);
|
||||
if (System.Buffers.Text.Utf8Parser.TryParse(rentArray.AsSpan(0, seqLen), out decimal result, out var bytesConsumed))
|
||||
{
|
||||
if (seqLen != bytesConsumed)
|
||||
{
|
||||
throw new MessagePackSerializationException("Unexpected length of string.");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(rentArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new MessagePackSerializationException("Can't parse to decimal, input string was not in a correct format.");
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class TimeSpanFormatter : IMessagePackFormatter<TimeSpan>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<TimeSpan> Instance = new TimeSpanFormatter();
|
||||
|
||||
private TimeSpanFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, TimeSpan value, MessagePackSerializerOptions options)
|
||||
{
|
||||
writer.Write(value.Ticks);
|
||||
return;
|
||||
}
|
||||
|
||||
public TimeSpan Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
return new TimeSpan(reader.ReadInt64());
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DateTimeOffsetFormatter : IMessagePackFormatter<DateTimeOffset>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<DateTimeOffset> Instance = new DateTimeOffsetFormatter();
|
||||
|
||||
private DateTimeOffsetFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, DateTimeOffset value, MessagePackSerializerOptions options)
|
||||
{
|
||||
writer.WriteArrayHeader(2);
|
||||
writer.Write(new DateTime(value.Ticks, DateTimeKind.Utc)); // current ticks as is
|
||||
writer.Write((short)value.Offset.TotalMinutes); // offset is normalized in minutes
|
||||
return;
|
||||
}
|
||||
|
||||
public DateTimeOffset Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
var count = reader.ReadArrayHeader();
|
||||
|
||||
if (count != 2)
|
||||
{
|
||||
throw new MessagePackSerializationException("Invalid DateTimeOffset format.");
|
||||
}
|
||||
|
||||
DateTime utc = reader.ReadDateTime();
|
||||
|
||||
var dtOffsetMinutes = reader.ReadInt16();
|
||||
|
||||
return new DateTimeOffset(utc.Ticks, TimeSpan.FromMinutes(dtOffsetMinutes));
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class GuidFormatter : IMessagePackFormatter<Guid>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<Guid> Instance = new GuidFormatter();
|
||||
|
||||
private GuidFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public unsafe void Serialize(ref MessagePackWriter writer, Guid value, MessagePackSerializerOptions options)
|
||||
{
|
||||
byte* pBytes = stackalloc byte[36];
|
||||
Span<byte> bytes = new Span<byte>(pBytes, 36);
|
||||
new GuidBits(ref value).Write(bytes);
|
||||
writer.WriteString(bytes);
|
||||
}
|
||||
|
||||
public Guid Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
ReadOnlySequence<byte> segment = reader.ReadStringSequence().Value;
|
||||
if (segment.Length != 36)
|
||||
{
|
||||
throw new MessagePackSerializationException("Unexpected length of string.");
|
||||
}
|
||||
|
||||
GuidBits result;
|
||||
if (segment.IsSingleSegment)
|
||||
{
|
||||
result = new GuidBits(segment.First.Span);
|
||||
}
|
||||
else
|
||||
{
|
||||
Span<byte> bytes = stackalloc byte[36];
|
||||
segment.CopyTo(bytes);
|
||||
result = new GuidBits(bytes);
|
||||
}
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class UriFormatter : IMessagePackFormatter<Uri>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<Uri> Instance = new UriFormatter();
|
||||
|
||||
private UriFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, Uri value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write(value.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public Uri Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.TryReadNil())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Uri(reader.ReadString(), UriKind.RelativeOrAbsolute);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class VersionFormatter : IMessagePackFormatter<Version>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<Version> Instance = new VersionFormatter();
|
||||
|
||||
private VersionFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, Version value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write(value.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public Version Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.TryReadNil())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Version(reader.ReadString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class KeyValuePairFormatter<TKey, TValue> : IMessagePackFormatter<KeyValuePair<TKey, TValue>>
|
||||
{
|
||||
public void Serialize(ref MessagePackWriter writer, KeyValuePair<TKey, TValue> value, MessagePackSerializerOptions options)
|
||||
{
|
||||
writer.WriteArrayHeader(2);
|
||||
IFormatterResolver resolver = options.Resolver;
|
||||
resolver.GetFormatterWithVerify<TKey>().Serialize(ref writer, value.Key, options);
|
||||
resolver.GetFormatterWithVerify<TValue>().Serialize(ref writer, value.Value, options);
|
||||
return;
|
||||
}
|
||||
|
||||
public KeyValuePair<TKey, TValue> Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
var count = reader.ReadArrayHeader();
|
||||
|
||||
if (count != 2)
|
||||
{
|
||||
throw new MessagePackSerializationException("Invalid KeyValuePair format.");
|
||||
}
|
||||
|
||||
IFormatterResolver resolver = options.Resolver;
|
||||
options.Security.DepthStep(ref reader);
|
||||
try
|
||||
{
|
||||
TKey key = resolver.GetFormatterWithVerify<TKey>().Deserialize(ref reader, options);
|
||||
TValue value = resolver.GetFormatterWithVerify<TValue>().Deserialize(ref reader, options);
|
||||
return new KeyValuePair<TKey, TValue>(key, value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Depth--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class StringBuilderFormatter : IMessagePackFormatter<StringBuilder>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<StringBuilder> Instance = new StringBuilderFormatter();
|
||||
|
||||
private StringBuilderFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, StringBuilder value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write(value.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public StringBuilder Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.TryReadNil())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new StringBuilder(reader.ReadString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class BitArrayFormatter : IMessagePackFormatter<BitArray>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<BitArray> Instance = new BitArrayFormatter();
|
||||
|
||||
private BitArrayFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, BitArray value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
else
|
||||
{
|
||||
var len = value.Length;
|
||||
writer.WriteArrayHeader(len);
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
writer.Write(value.Get(i));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public BitArray Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.TryReadNil())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var len = reader.ReadArrayHeader();
|
||||
|
||||
var array = new BitArray(len);
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
array[i] = reader.ReadBoolean();
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class BigIntegerFormatter : IMessagePackFormatter<System.Numerics.BigInteger>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<System.Numerics.BigInteger> Instance = new BigIntegerFormatter();
|
||||
|
||||
private BigIntegerFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, System.Numerics.BigInteger value, MessagePackSerializerOptions options)
|
||||
{
|
||||
#if NETCOREAPP2_1
|
||||
if (!writer.OldSpec)
|
||||
{
|
||||
// try to get bin8 buffer.
|
||||
var span = writer.GetSpan(byte.MaxValue);
|
||||
if (value.TryWriteBytes(span.Slice(2), out var written))
|
||||
{
|
||||
span[0] = MessagePackCode.Bin8;
|
||||
span[1] = (byte)written;
|
||||
|
||||
writer.Advance(written + 2);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// reset writer's span previously acquired that does not use
|
||||
writer.Advance(0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
writer.Write(value.ToByteArray());
|
||||
return;
|
||||
}
|
||||
|
||||
public System.Numerics.BigInteger Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
ReadOnlySequence<byte> bytes = reader.ReadBytes().Value;
|
||||
#if NETCOREAPP2_1
|
||||
if (bytes.IsSingleSegment)
|
||||
{
|
||||
return new System.Numerics.BigInteger(bytes.First.Span);
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] bytesArray = ArrayPool<byte>.Shared.Rent((int)bytes.Length);
|
||||
try
|
||||
{
|
||||
bytes.CopyTo(bytesArray);
|
||||
return new System.Numerics.BigInteger(bytesArray.AsSpan(0, (int)bytes.Length));
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(bytesArray);
|
||||
}
|
||||
}
|
||||
#else
|
||||
return new System.Numerics.BigInteger(bytes.ToArray());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ComplexFormatter : IMessagePackFormatter<System.Numerics.Complex>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<System.Numerics.Complex> Instance = new ComplexFormatter();
|
||||
|
||||
private ComplexFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, System.Numerics.Complex value, MessagePackSerializerOptions options)
|
||||
{
|
||||
writer.WriteArrayHeader(2);
|
||||
writer.Write(value.Real);
|
||||
writer.Write(value.Imaginary);
|
||||
return;
|
||||
}
|
||||
|
||||
public System.Numerics.Complex Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
var count = reader.ReadArrayHeader();
|
||||
|
||||
if (count != 2)
|
||||
{
|
||||
throw new MessagePackSerializationException("Invalid Complex format.");
|
||||
}
|
||||
|
||||
var real = reader.ReadDouble();
|
||||
|
||||
var imaginary = reader.ReadDouble();
|
||||
|
||||
return new System.Numerics.Complex(real, imaginary);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class LazyFormatter<T> : IMessagePackFormatter<Lazy<T>>
|
||||
{
|
||||
public void Serialize(ref MessagePackWriter writer, Lazy<T> value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
else
|
||||
{
|
||||
IFormatterResolver resolver = options.Resolver;
|
||||
resolver.GetFormatterWithVerify<T>().Serialize(ref writer, value.Value, options);
|
||||
}
|
||||
}
|
||||
|
||||
public Lazy<T> Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.TryReadNil())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
options.Security.DepthStep(ref reader);
|
||||
try
|
||||
{
|
||||
// deserialize immediately(no delay, because capture byte[] causes memory leak)
|
||||
IFormatterResolver resolver = options.Resolver;
|
||||
T v = resolver.GetFormatterWithVerify<T>().Deserialize(ref reader, options);
|
||||
return new Lazy<T>(() => v);
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Depth--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6dc8f5f9191421c21bd1ba87f5a70d27
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
313
Assets/Scripts/MessagePack/Formatters/TypelessFormatter.cs
Normal file
313
Assets/Scripts/MessagePack/Formatters/TypelessFormatter.cs
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
// 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.Buffers;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.RegularExpressions;
|
||||
using MessagePack.Internal;
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
/// <summary>
|
||||
/// For `object` field that holds derived from `object` value, ex: var arr = new object[] { 1, "a", new Model() };.
|
||||
/// </summary>
|
||||
public sealed class TypelessFormatter : IMessagePackFormatter<object>
|
||||
{
|
||||
private delegate void SerializeMethod(object dynamicContractlessFormatter, ref MessagePackWriter writer, object value, MessagePackSerializerOptions options);
|
||||
|
||||
private delegate object DeserializeMethod(object dynamicContractlessFormatter, ref MessagePackReader reader, MessagePackSerializerOptions options);
|
||||
|
||||
/// <summary>
|
||||
/// The singleton instance that can be used.
|
||||
/// </summary>
|
||||
public static readonly IMessagePackFormatter<object> Instance = new TypelessFormatter();
|
||||
|
||||
private readonly ThreadsafeTypeKeyHashTable<SerializeMethod> serializers = new ThreadsafeTypeKeyHashTable<SerializeMethod>();
|
||||
private readonly ThreadsafeTypeKeyHashTable<DeserializeMethod> deserializers = new ThreadsafeTypeKeyHashTable<DeserializeMethod>();
|
||||
private readonly ThreadsafeTypeKeyHashTable<byte[]> fullTypeNameCache = new ThreadsafeTypeKeyHashTable<byte[]>();
|
||||
private readonly ThreadsafeTypeKeyHashTable<byte[]> shortenedTypeNameCache = new ThreadsafeTypeKeyHashTable<byte[]>();
|
||||
private readonly AsymmetricKeyHashTable<byte[], ArraySegment<byte>, Type> typeCache = new AsymmetricKeyHashTable<byte[], ArraySegment<byte>, Type>(new StringArraySegmentByteAscymmetricEqualityComparer());
|
||||
|
||||
private static readonly HashSet<Type> UseBuiltinTypes = new HashSet<Type>
|
||||
{
|
||||
typeof(Boolean),
|
||||
////typeof(Char),
|
||||
typeof(SByte),
|
||||
typeof(Byte),
|
||||
typeof(Int16),
|
||||
typeof(UInt16),
|
||||
typeof(Int32),
|
||||
typeof(UInt32),
|
||||
typeof(Int64),
|
||||
typeof(UInt64),
|
||||
typeof(Single),
|
||||
typeof(Double),
|
||||
typeof(string),
|
||||
typeof(byte[]),
|
||||
|
||||
// array should save their types.
|
||||
////typeof(Boolean[]),
|
||||
////typeof(Char[]),
|
||||
////typeof(SByte[]),
|
||||
////typeof(Int16[]),
|
||||
////typeof(UInt16[]),
|
||||
////typeof(Int32[]),
|
||||
////typeof(UInt32[]),
|
||||
////typeof(Int64[]),
|
||||
////typeof(UInt64[]),
|
||||
////typeof(Single[]),
|
||||
////typeof(Double[]),
|
||||
////typeof(string[]),
|
||||
|
||||
typeof(Boolean?),
|
||||
////typeof(Char?),
|
||||
typeof(SByte?),
|
||||
typeof(Byte?),
|
||||
typeof(Int16?),
|
||||
typeof(UInt16?),
|
||||
typeof(Int32?),
|
||||
typeof(UInt32?),
|
||||
typeof(Int64?),
|
||||
typeof(UInt64?),
|
||||
typeof(Single?),
|
||||
typeof(Double?),
|
||||
};
|
||||
|
||||
//ForceSizePrimitiveObjectResolver.Instance,
|
||||
//ContractlessStandardResolverAllowPrivate.Instance);
|
||||
|
||||
// mscorlib or System.Private.CoreLib
|
||||
private static readonly bool IsMscorlib = typeof(int).AssemblyQualifiedName.Contains("mscorlib");
|
||||
|
||||
private TypelessFormatter()
|
||||
{
|
||||
this.serializers.TryAdd(typeof(object), _ => (object p1, ref MessagePackWriter p2, object p3, MessagePackSerializerOptions p4) => { });
|
||||
this.deserializers.TryAdd(typeof(object), _ => (object p1, ref MessagePackReader p2, MessagePackSerializerOptions p3) => new object());
|
||||
}
|
||||
|
||||
private string BuildTypeName(Type type, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (options.OmitAssemblyVersion)
|
||||
{
|
||||
string full = type.AssemblyQualifiedName;
|
||||
|
||||
var shortened = MessagePackSerializerOptions.AssemblyNameVersionSelectorRegex.Replace(full, string.Empty);
|
||||
if (Type.GetType(shortened, false) == null)
|
||||
{
|
||||
// if type cannot be found with shortened name - use full name
|
||||
shortened = full;
|
||||
}
|
||||
|
||||
return shortened;
|
||||
}
|
||||
else
|
||||
{
|
||||
return type.AssemblyQualifiedName;
|
||||
}
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, object value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
return;
|
||||
}
|
||||
|
||||
Type type = value.GetType();
|
||||
|
||||
byte[] typeName;
|
||||
var typeNameCache = options.OmitAssemblyVersion ? this.shortenedTypeNameCache : this.fullTypeNameCache;
|
||||
if (!typeNameCache.TryGetValue(type, out typeName))
|
||||
{
|
||||
TypeInfo ti = type.GetTypeInfo();
|
||||
if (ti.IsAnonymous() || UseBuiltinTypes.Contains(type))
|
||||
{
|
||||
typeName = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
typeName = StringEncoding.UTF8.GetBytes(this.BuildTypeName(type, options));
|
||||
}
|
||||
|
||||
typeNameCache.TryAdd(type, typeName);
|
||||
}
|
||||
|
||||
if (typeName == null)
|
||||
{
|
||||
DynamicObjectTypeFallbackFormatter.Instance.Serialize(ref writer, value, options);
|
||||
return;
|
||||
}
|
||||
|
||||
var formatter = options.Resolver.GetFormatterDynamicWithVerify(type);
|
||||
|
||||
// don't use GetOrAdd for avoid closure capture.
|
||||
if (!this.serializers.TryGetValue(type, out SerializeMethod serializeMethod))
|
||||
{
|
||||
// double check locking...
|
||||
lock (this.serializers)
|
||||
{
|
||||
if (!this.serializers.TryGetValue(type, out serializeMethod))
|
||||
{
|
||||
TypeInfo ti = type.GetTypeInfo();
|
||||
|
||||
Type formatterType = typeof(IMessagePackFormatter<>).MakeGenericType(type);
|
||||
ParameterExpression param0 = Expression.Parameter(typeof(object), "formatter");
|
||||
ParameterExpression param1 = Expression.Parameter(typeof(MessagePackWriter).MakeByRefType(), "writer");
|
||||
ParameterExpression param2 = Expression.Parameter(typeof(object), "value");
|
||||
ParameterExpression param3 = Expression.Parameter(typeof(MessagePackSerializerOptions), "options");
|
||||
|
||||
MethodInfo serializeMethodInfo = formatterType.GetRuntimeMethod("Serialize", new[] { typeof(MessagePackWriter).MakeByRefType(), type, typeof(MessagePackSerializerOptions) });
|
||||
|
||||
MethodCallExpression body = Expression.Call(
|
||||
Expression.Convert(param0, formatterType),
|
||||
serializeMethodInfo,
|
||||
param1,
|
||||
ti.IsValueType ? Expression.Unbox(param2, type) : Expression.Convert(param2, type),
|
||||
param3);
|
||||
|
||||
serializeMethod = Expression.Lambda<SerializeMethod>(body, param0, param1, param2, param3).Compile();
|
||||
|
||||
this.serializers.TryAdd(type, serializeMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mark will be written at the end, when size is known
|
||||
using (var scratchRental = SequencePool.Shared.Rent())
|
||||
{
|
||||
MessagePackWriter scratchWriter = writer.Clone(scratchRental.Value);
|
||||
scratchWriter.WriteString(typeName);
|
||||
serializeMethod(formatter, ref scratchWriter, value, options);
|
||||
scratchWriter.Flush();
|
||||
|
||||
// mark as extension with code 100
|
||||
writer.WriteExtensionFormat(new ExtensionResult((sbyte)ThisLibraryExtensionTypeCodes.TypelessFormatter, scratchRental.Value));
|
||||
}
|
||||
}
|
||||
|
||||
public object Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.TryReadNil())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (reader.NextMessagePackType == MessagePackType.Extension)
|
||||
{
|
||||
ExtensionHeader ext = reader.ReadExtensionFormatHeader();
|
||||
if (ext.TypeCode == ThisLibraryExtensionTypeCodes.TypelessFormatter)
|
||||
{
|
||||
// it has type name serialized
|
||||
ReadOnlySequence<byte> typeName = reader.ReadStringSequence().Value;
|
||||
ArraySegment<byte> typeNameArraySegment;
|
||||
byte[] rented = null;
|
||||
if (!typeName.IsSingleSegment || !MemoryMarshal.TryGetArray(typeName.First, out typeNameArraySegment))
|
||||
{
|
||||
rented = ArrayPool<byte>.Shared.Rent((int)typeName.Length);
|
||||
typeName.CopyTo(rented);
|
||||
typeNameArraySegment = new ArraySegment<byte>(rented, 0, (int)typeName.Length);
|
||||
}
|
||||
|
||||
var result = this.DeserializeByTypeName(typeNameArraySegment, ref reader, options);
|
||||
|
||||
if (rented != null)
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(rented);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// fallback
|
||||
return DynamicObjectTypeFallbackFormatter.Instance.Deserialize(ref reader, options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does not support deserializing of anonymous types
|
||||
/// Type should be covered by preceeding resolvers in complex/standard resolver.
|
||||
/// </summary>
|
||||
private object DeserializeByTypeName(ArraySegment<byte> typeName, ref MessagePackReader byteSequence, MessagePackSerializerOptions options)
|
||||
{
|
||||
// try get type with assembly name, throw if not found
|
||||
Type type;
|
||||
if (!this.typeCache.TryGetValue(typeName, out type))
|
||||
{
|
||||
var buffer = new byte[typeName.Count];
|
||||
Buffer.BlockCopy(typeName.Array, typeName.Offset, buffer, 0, buffer.Length);
|
||||
var str = StringEncoding.UTF8.GetString(buffer);
|
||||
type = options.LoadType(str);
|
||||
if (type == null)
|
||||
{
|
||||
if (IsMscorlib && str.Contains("System.Private.CoreLib"))
|
||||
{
|
||||
str = str.Replace("System.Private.CoreLib", "mscorlib");
|
||||
type = Type.GetType(str, true); // throw
|
||||
}
|
||||
else if (!IsMscorlib && str.Contains("mscorlib"))
|
||||
{
|
||||
str = str.Replace("mscorlib", "System.Private.CoreLib");
|
||||
type = Type.GetType(str, true); // throw
|
||||
}
|
||||
else
|
||||
{
|
||||
type = Type.GetType(str, true); // re-throw
|
||||
}
|
||||
}
|
||||
|
||||
this.typeCache.TryAdd(buffer, type);
|
||||
}
|
||||
|
||||
options.ThrowIfDeserializingTypeIsDisallowed(type);
|
||||
|
||||
var formatter = options.Resolver.GetFormatterDynamicWithVerify(type);
|
||||
|
||||
if (!this.deserializers.TryGetValue(type, out DeserializeMethod deserializeMethod))
|
||||
{
|
||||
lock (this.deserializers)
|
||||
{
|
||||
if (!this.deserializers.TryGetValue(type, out deserializeMethod))
|
||||
{
|
||||
TypeInfo ti = type.GetTypeInfo();
|
||||
|
||||
Type formatterType = typeof(IMessagePackFormatter<>).MakeGenericType(type);
|
||||
ParameterExpression param0 = Expression.Parameter(typeof(object), "formatter");
|
||||
ParameterExpression param1 = Expression.Parameter(typeof(MessagePackReader).MakeByRefType(), "reader");
|
||||
ParameterExpression param2 = Expression.Parameter(typeof(MessagePackSerializerOptions), "options");
|
||||
|
||||
MethodInfo deserializeMethodInfo = formatterType.GetRuntimeMethod("Deserialize", new[] { typeof(MessagePackReader).MakeByRefType(), typeof(MessagePackSerializerOptions) });
|
||||
|
||||
MethodCallExpression deserialize = Expression.Call(
|
||||
Expression.Convert(param0, formatterType),
|
||||
deserializeMethodInfo,
|
||||
param1,
|
||||
param2);
|
||||
|
||||
Expression body = deserialize;
|
||||
if (ti.IsValueType)
|
||||
{
|
||||
body = Expression.Convert(deserialize, typeof(object));
|
||||
}
|
||||
|
||||
deserializeMethod = Expression.Lambda<DeserializeMethod>(body, param0, param1, param2).Compile();
|
||||
|
||||
this.deserializers.TryAdd(type, deserializeMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return deserializeMethod(formatter, ref byteSequence, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fe17a811684aa2fa786684f83f7fbbe7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
100
Assets/Scripts/MessagePack/Formatters/UnsafeBinaryFormatters.cs
Normal file
100
Assets/Scripts/MessagePack/Formatters/UnsafeBinaryFormatters.cs
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
|
||||
#pragma warning disable SA1649 // File name should match first type name
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
public sealed class NativeGuidFormatter : IMessagePackFormatter<Guid>
|
||||
{
|
||||
/// <summary>
|
||||
/// Unsafe binary Guid formatter. this is only allowed on LittleEndian environment.
|
||||
/// </summary>
|
||||
public static readonly IMessagePackFormatter<Guid> Instance = new NativeGuidFormatter();
|
||||
|
||||
private NativeGuidFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
/* Guid's underlying _a,...,_k field is sequential and same layout as .NET Framework and Mono(Unity).
|
||||
* But target machines must be same endian so restrict only for little endian. */
|
||||
|
||||
public unsafe void Serialize(ref MessagePackWriter writer, Guid value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
{
|
||||
throw new InvalidOperationException("NativeGuidFormatter only allows on little endian env.");
|
||||
}
|
||||
|
||||
var valueSpan = new ReadOnlySpan<byte>(&value, sizeof(Guid));
|
||||
writer.Write(valueSpan);
|
||||
}
|
||||
|
||||
public unsafe Guid Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
{
|
||||
throw new InvalidOperationException("NativeGuidFormatter only allows on little endian env.");
|
||||
}
|
||||
|
||||
ReadOnlySequence<byte> valueSequence = reader.ReadBytes().Value;
|
||||
if (valueSequence.Length != sizeof(Guid))
|
||||
{
|
||||
throw new MessagePackSerializationException("Invalid Guid Size.");
|
||||
}
|
||||
|
||||
Guid result;
|
||||
var resultSpan = new Span<byte>(&result, sizeof(Guid));
|
||||
valueSequence.CopyTo(resultSpan);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class NativeDecimalFormatter : IMessagePackFormatter<Decimal>
|
||||
{
|
||||
/// <summary>
|
||||
/// Unsafe binary Decimal formatter. this is only allows on LittleEndian environment.
|
||||
/// </summary>
|
||||
public static readonly IMessagePackFormatter<Decimal> Instance = new NativeDecimalFormatter();
|
||||
|
||||
private NativeDecimalFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
/* decimal underlying "flags, hi, lo, mid" fields are sequential and same layuout with .NET Framework and Mono(Unity)
|
||||
* But target machines must be same endian so restrict only for little endian. */
|
||||
|
||||
public unsafe void Serialize(ref MessagePackWriter writer, Decimal value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
{
|
||||
throw new InvalidOperationException("NativeDecimalFormatter only allows on little endian env.");
|
||||
}
|
||||
|
||||
var valueSpan = new ReadOnlySpan<byte>(&value, sizeof(Decimal));
|
||||
writer.Write(valueSpan);
|
||||
}
|
||||
|
||||
public unsafe Decimal Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
{
|
||||
throw new InvalidOperationException("NativeDecimalFormatter only allows on little endian env.");
|
||||
}
|
||||
|
||||
ReadOnlySequence<byte> valueSequence = reader.ReadBytes().Value;
|
||||
if (valueSequence.Length != sizeof(decimal))
|
||||
{
|
||||
throw new MessagePackSerializationException("Invalid decimal Size.");
|
||||
}
|
||||
|
||||
decimal result;
|
||||
var resultSpan = new Span<byte>(&result, sizeof(decimal));
|
||||
valueSequence.CopyTo(resultSpan);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2c4fcfc3f496806c7915aba0cdb3f1ba
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loading…
Reference in a new issue