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
#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 |