You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
303 lines
13 KiB
303 lines
13 KiB
4 years ago
|
#if !UNITY_WSA
|
||
|
|
||
|
using MessagePack.Formatters;
|
||
|
using System.Linq;
|
||
|
using MessagePack.Internal;
|
||
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Reflection;
|
||
|
using System.Collections.ObjectModel;
|
||
|
using System.Collections;
|
||
|
|
||
|
#if NETSTANDARD
|
||
|
using System.Threading.Tasks;
|
||
|
#endif
|
||
|
|
||
|
namespace MessagePack.Resolvers
|
||
|
{
|
||
|
public sealed class DynamicGenericResolver : IFormatterResolver
|
||
|
{
|
||
|
public static readonly IFormatterResolver Instance = new DynamicGenericResolver();
|
||
|
|
||
|
DynamicGenericResolver()
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
public IMessagePackFormatter<T> GetFormatter<T>()
|
||
|
{
|
||
|
return FormatterCache<T>.formatter;
|
||
|
}
|
||
|
|
||
|
static class FormatterCache<T>
|
||
|
{
|
||
|
public static readonly IMessagePackFormatter<T> formatter;
|
||
|
|
||
|
static FormatterCache()
|
||
|
{
|
||
|
formatter = (IMessagePackFormatter<T>)DynamicGenericResolverGetFormatterHelper.GetFormatter(typeof(T));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
namespace MessagePack.Internal
|
||
|
{
|
||
|
internal static class DynamicGenericResolverGetFormatterHelper
|
||
|
{
|
||
|
static readonly Dictionary<Type, Type> formatterMap = new Dictionary<Type, Type>()
|
||
|
{
|
||
|
{typeof(List<>), typeof(ListFormatter<>)},
|
||
|
{typeof(LinkedList<>), typeof(LinkedListFormatter<>)},
|
||
|
{typeof(Queue<>), typeof(QeueueFormatter<>)},
|
||
|
{typeof(Stack<>), typeof(StackFormatter<>)},
|
||
|
{typeof(HashSet<>), typeof(HashSetFormatter<>)},
|
||
|
{typeof(ReadOnlyCollection<>), typeof(ReadOnlyCollectionFormatter<>)},
|
||
|
{typeof(IList<>), typeof(InterfaceListFormatter<>)},
|
||
|
{typeof(ICollection<>), typeof(InterfaceCollectionFormatter<>)},
|
||
|
{typeof(IEnumerable<>), typeof(InterfaceEnumerableFormatter<>)},
|
||
|
{typeof(Dictionary<,>), typeof(DictionaryFormatter<,>)},
|
||
|
{typeof(IDictionary<,>), typeof(InterfaceDictionaryFormatter<,>)},
|
||
|
{typeof(SortedDictionary<,>), typeof(SortedDictionaryFormatter<,>)},
|
||
|
{typeof(SortedList<,>), typeof(SortedListFormatter<,>)},
|
||
|
{typeof(ILookup<,>), typeof(InterfaceLookupFormatter<,>)},
|
||
|
{typeof(IGrouping<,>), typeof(InterfaceGroupingFormatter<,>)},
|
||
|
#if NETSTANDARD
|
||
|
{typeof(ObservableCollection<>), typeof(ObservableCollectionFormatter<>)},
|
||
|
{typeof(ReadOnlyObservableCollection<>),(typeof(ReadOnlyObservableCollectionFormatter<>))},
|
||
|
{typeof(IReadOnlyList<>), typeof(InterfaceReadOnlyListFormatter<>)},
|
||
|
{typeof(IReadOnlyCollection<>), typeof(InterfaceReadOnlyCollectionFormatter<>)},
|
||
|
{typeof(ISet<>), typeof(InterfaceSetFormatter<>)},
|
||
|
{typeof(System.Collections.Concurrent.ConcurrentBag<>), typeof(ConcurrentBagFormatter<>)},
|
||
|
{typeof(System.Collections.Concurrent.ConcurrentQueue<>), typeof(ConcurrentQueueFormatter<>)},
|
||
|
{typeof(System.Collections.Concurrent.ConcurrentStack<>), typeof(ConcurrentStackFormatter<>)},
|
||
|
{typeof(ReadOnlyDictionary<,>), typeof(ReadOnlyDictionaryFormatter<,>)},
|
||
|
{typeof(IReadOnlyDictionary<,>), typeof(InterfaceReadOnlyDictionaryFormatter<,>)},
|
||
|
{typeof(System.Collections.Concurrent.ConcurrentDictionary<,>), typeof(ConcurrentDictionaryFormatter<,>)},
|
||
|
{typeof(Lazy<>), typeof(LazyFormatter<>)},
|
||
|
{typeof(Task<>), typeof(TaskValueFormatter<>)},
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
// Reduce IL2CPP code generate size(don't write long code in <T>)
|
||
|
internal static object GetFormatter(Type t)
|
||
|
{
|
||
|
var ti = t.GetTypeInfo();
|
||
|
|
||
|
if (t.IsArray)
|
||
|
{
|
||
|
var rank = t.GetArrayRank();
|
||
|
if (rank == 1)
|
||
|
{
|
||
|
if (t.GetElementType() == typeof(byte)) // byte[] is also supported in builtin formatter.
|
||
|
{
|
||
|
return ByteArrayFormatter.Instance;
|
||
|
}
|
||
|
|
||
|
return Activator.CreateInstance(typeof(ArrayFormatter<>).MakeGenericType(t.GetElementType()));
|
||
|
}
|
||
|
else if (rank == 2)
|
||
|
{
|
||
|
return Activator.CreateInstance(typeof(TwoDimentionalArrayFormatter<>).MakeGenericType(t.GetElementType()));
|
||
|
}
|
||
|
else if (rank == 3)
|
||
|
{
|
||
|
return Activator.CreateInstance(typeof(ThreeDimentionalArrayFormatter<>).MakeGenericType(t.GetElementType()));
|
||
|
}
|
||
|
else if (rank == 4)
|
||
|
{
|
||
|
return Activator.CreateInstance(typeof(FourDimentionalArrayFormatter<>).MakeGenericType(t.GetElementType()));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return null; // not supported built-in
|
||
|
}
|
||
|
}
|
||
|
else if (ti.IsGenericType)
|
||
|
{
|
||
|
var genericType = ti.GetGenericTypeDefinition();
|
||
|
var genericTypeInfo = genericType.GetTypeInfo();
|
||
|
var isNullable = genericTypeInfo.IsNullable();
|
||
|
var nullableElementType = isNullable ? ti.GenericTypeArguments[0] : null;
|
||
|
|
||
|
if (genericType == typeof(KeyValuePair<,>))
|
||
|
{
|
||
|
return CreateInstance(typeof(KeyValuePairFormatter<,>), ti.GenericTypeArguments);
|
||
|
}
|
||
|
else if (isNullable && nullableElementType.GetTypeInfo().IsConstructedGenericType() && nullableElementType.GetGenericTypeDefinition() == typeof(KeyValuePair<,>))
|
||
|
{
|
||
|
return CreateInstance(typeof(NullableFormatter<>), new[] { nullableElementType });
|
||
|
}
|
||
|
|
||
|
#if NETSTANDARD
|
||
|
|
||
|
// ValueTask
|
||
|
else if (genericType == typeof(ValueTask<>))
|
||
|
{
|
||
|
return CreateInstance(typeof(ValueTaskFormatter<>), ti.GenericTypeArguments);
|
||
|
}
|
||
|
else if (isNullable && nullableElementType.IsConstructedGenericType && nullableElementType.GetGenericTypeDefinition() == typeof(ValueTask<>))
|
||
|
{
|
||
|
return CreateInstance(typeof(NullableFormatter<>), new[] { nullableElementType });
|
||
|
}
|
||
|
|
||
|
// Tuple
|
||
|
else if (ti.FullName.StartsWith("System.Tuple"))
|
||
|
{
|
||
|
Type tupleFormatterType = null;
|
||
|
switch (ti.GenericTypeArguments.Length)
|
||
|
{
|
||
|
case 1:
|
||
|
tupleFormatterType = typeof(TupleFormatter<>);
|
||
|
break;
|
||
|
case 2:
|
||
|
tupleFormatterType = typeof(TupleFormatter<,>);
|
||
|
break;
|
||
|
case 3:
|
||
|
tupleFormatterType = typeof(TupleFormatter<,,>);
|
||
|
break;
|
||
|
case 4:
|
||
|
tupleFormatterType = typeof(TupleFormatter<,,,>);
|
||
|
break;
|
||
|
case 5:
|
||
|
tupleFormatterType = typeof(TupleFormatter<,,,,>);
|
||
|
break;
|
||
|
case 6:
|
||
|
tupleFormatterType = typeof(TupleFormatter<,,,,,>);
|
||
|
break;
|
||
|
case 7:
|
||
|
tupleFormatterType = typeof(TupleFormatter<,,,,,,>);
|
||
|
break;
|
||
|
case 8:
|
||
|
tupleFormatterType = typeof(TupleFormatter<,,,,,,,>);
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return CreateInstance(tupleFormatterType, ti.GenericTypeArguments);
|
||
|
}
|
||
|
|
||
|
// ValueTuple
|
||
|
else if (ti.FullName.StartsWith("System.ValueTuple"))
|
||
|
{
|
||
|
Type tupleFormatterType = null;
|
||
|
switch (ti.GenericTypeArguments.Length)
|
||
|
{
|
||
|
case 1:
|
||
|
tupleFormatterType = typeof(ValueTupleFormatter<>);
|
||
|
break;
|
||
|
case 2:
|
||
|
tupleFormatterType = typeof(ValueTupleFormatter<,>);
|
||
|
break;
|
||
|
case 3:
|
||
|
tupleFormatterType = typeof(ValueTupleFormatter<,,>);
|
||
|
break;
|
||
|
case 4:
|
||
|
tupleFormatterType = typeof(ValueTupleFormatter<,,,>);
|
||
|
break;
|
||
|
case 5:
|
||
|
tupleFormatterType = typeof(ValueTupleFormatter<,,,,>);
|
||
|
break;
|
||
|
case 6:
|
||
|
tupleFormatterType = typeof(ValueTupleFormatter<,,,,,>);
|
||
|
break;
|
||
|
case 7:
|
||
|
tupleFormatterType = typeof(ValueTupleFormatter<,,,,,,>);
|
||
|
break;
|
||
|
case 8:
|
||
|
tupleFormatterType = typeof(ValueTupleFormatter<,,,,,,,>);
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return CreateInstance(tupleFormatterType, ti.GenericTypeArguments);
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
// ArraySegement
|
||
|
else if (genericType == typeof(ArraySegment<>))
|
||
|
{
|
||
|
if (ti.GenericTypeArguments[0] == typeof(byte))
|
||
|
{
|
||
|
return ByteArraySegmentFormatter.Instance;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return CreateInstance(typeof(ArraySegmentFormatter<>), ti.GenericTypeArguments);
|
||
|
}
|
||
|
}
|
||
|
else if (isNullable && nullableElementType.GetTypeInfo().IsConstructedGenericType() && nullableElementType.GetGenericTypeDefinition() == typeof(ArraySegment<>))
|
||
|
{
|
||
|
if (nullableElementType == typeof(ArraySegment<byte>))
|
||
|
{
|
||
|
return new StaticNullableFormatter<ArraySegment<byte>>(ByteArraySegmentFormatter.Instance);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return CreateInstance(typeof(NullableFormatter<>), new[] { nullableElementType });
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Mapped formatter
|
||
|
else
|
||
|
{
|
||
|
Type formatterType;
|
||
|
if (formatterMap.TryGetValue(genericType, out formatterType))
|
||
|
{
|
||
|
return CreateInstance(formatterType, ti.GenericTypeArguments);
|
||
|
}
|
||
|
|
||
|
// generic collection
|
||
|
else if (ti.GenericTypeArguments.Length == 1
|
||
|
&& ti.ImplementedInterfaces.Any(x => x.GetTypeInfo().IsConstructedGenericType() && x.GetGenericTypeDefinition() == typeof(ICollection<>))
|
||
|
&& ti.DeclaredConstructors.Any(x => x.GetParameters().Length == 0))
|
||
|
{
|
||
|
var elemType = ti.GenericTypeArguments[0];
|
||
|
return CreateInstance(typeof(GenericCollectionFormatter<,>), new[] { elemType, t });
|
||
|
}
|
||
|
// generic dictionary
|
||
|
else if (ti.GenericTypeArguments.Length == 2
|
||
|
&& ti.ImplementedInterfaces.Any(x => x.GetTypeInfo().IsConstructedGenericType() && x.GetGenericTypeDefinition() == typeof(IDictionary<,>))
|
||
|
&& ti.DeclaredConstructors.Any(x => x.GetParameters().Length == 0))
|
||
|
{
|
||
|
var keyType = ti.GenericTypeArguments[0];
|
||
|
var valueType = ti.GenericTypeArguments[1];
|
||
|
return CreateInstance(typeof(GenericDictionaryFormatter<,,>), new[] { keyType, valueType, t });
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// NonGeneric Collection
|
||
|
if (t == typeof(IList))
|
||
|
{
|
||
|
return NonGenericInterfaceListFormatter.Instance;
|
||
|
}
|
||
|
else if (t == typeof(IDictionary))
|
||
|
{
|
||
|
return NonGenericInterfaceDictionaryFormatter.Instance;
|
||
|
}
|
||
|
if (typeof(IList).GetTypeInfo().IsAssignableFrom(ti) && ti.DeclaredConstructors.Any(x => x.GetParameters().Length == 0))
|
||
|
{
|
||
|
return Activator.CreateInstance(typeof(NonGenericListFormatter<>).MakeGenericType(t));
|
||
|
}
|
||
|
else if (typeof(IDictionary).GetTypeInfo().IsAssignableFrom(ti) && ti.DeclaredConstructors.Any(x => x.GetParameters().Length == 0))
|
||
|
{
|
||
|
return Activator.CreateInstance(typeof(NonGenericDictionaryFormatter<>).MakeGenericType(t));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
static object CreateInstance(Type genericType, Type[] genericTypeArguments, params object[] arguments)
|
||
|
{
|
||
|
return Activator.CreateInstance(genericType.MakeGenericType(genericTypeArguments), arguments);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|