mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-09-15 14:52:35 +02:00
Make SerializationManager.TryGetTypeNodeSerializer 65 times faster
This commit is contained in:
@@ -372,7 +372,7 @@ public sealed partial class SerializationManager
|
||||
var generated = Unsafe.As<ISerializationGenerated<T>>(source);
|
||||
var target = generated.Instantiate();
|
||||
generated.Copy(ref target, this, hookCtx, context);
|
||||
RunAfterHook(target, hookCtx);
|
||||
TryRunAfterHook(target, hookCtx);
|
||||
return target;
|
||||
}
|
||||
else
|
||||
@@ -474,7 +474,7 @@ public sealed partial class SerializationManager
|
||||
var generated = Unsafe.As<ISerializationGenerated<T>>(source);
|
||||
target ??= generated.Instantiate();
|
||||
generated.Copy(ref target, this, hookCtx, context);
|
||||
RunAfterHook(target, hookCtx);
|
||||
TryRunAfterHook(target, hookCtx);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -489,7 +489,7 @@ public sealed partial class SerializationManager
|
||||
target = CreateCopy(source, hookCtx, context);
|
||||
}
|
||||
|
||||
RunAfterHook(target, hookCtx);
|
||||
TryRunAfterHook(target, hookCtx);
|
||||
}
|
||||
|
||||
public void CopyTo<T>(ITypeCopier<T> copier, T source, ref T target, ISerializationContext? context = null,
|
||||
@@ -534,7 +534,7 @@ public sealed partial class SerializationManager
|
||||
}
|
||||
|
||||
copier.CopyTo(this, source, ref target, DependencyCollection, hookCtx, context);
|
||||
RunAfterHook(target, hookCtx);
|
||||
TryRunAfterHook(target, hookCtx);
|
||||
}
|
||||
|
||||
public void CopyTo<T, TCopier>(T source, ref T target, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false)
|
||||
@@ -607,13 +607,13 @@ public sealed partial class SerializationManager
|
||||
var generated = Unsafe.As<ISerializationGenerated<T>>(source);
|
||||
var target = generated.Instantiate();
|
||||
generated.Copy(ref target, this, hookCtx, context);
|
||||
RunAfterHook(target, hookCtx);
|
||||
TryRunAfterHook(target, hookCtx);
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
var res = GetOrCreateCreateCopyGenericDelegate<T>()(source, hookCtx, context);
|
||||
RunAfterHook(res, hookCtx);
|
||||
TryRunAfterHook(res, hookCtx);
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -643,7 +643,7 @@ public sealed partial class SerializationManager
|
||||
}
|
||||
|
||||
var res = copyCreator.CreateCopy(this, source, DependencyCollection, hookCtx, context);
|
||||
RunAfterHook(res, hookCtx);
|
||||
TryRunAfterHook(res, hookCtx);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -193,6 +193,7 @@ namespace Robust.Shared.Serialization.Manager
|
||||
{
|
||||
var baseType = typeof(T);
|
||||
var nullable = baseType.IsNullable();
|
||||
var isArray = ReadTypeMetadata<T>.IsArray;
|
||||
|
||||
T val = default!;
|
||||
|
||||
@@ -321,7 +322,7 @@ namespace Robust.Shared.Serialization.Manager
|
||||
|
||||
if (!hasSerializer)
|
||||
{
|
||||
if (baseType.IsArray)
|
||||
if (isArray)
|
||||
{
|
||||
val = node switch
|
||||
{
|
||||
@@ -381,7 +382,7 @@ namespace Robust.Shared.Serialization.Manager
|
||||
throw new ArgumentException($"No mapping or value node provided for type {baseType}.");
|
||||
}
|
||||
|
||||
RunAfterHook(val, hookCtx);
|
||||
TryRunAfterHook(val, hookCtx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -581,7 +582,8 @@ namespace Robust.Shared.Serialization.Manager
|
||||
}
|
||||
|
||||
var baseType = typeof(T);
|
||||
if (baseType.IsEnum || baseType.IsArray ||
|
||||
if (baseType.IsEnum ||
|
||||
ReadTypeMetadata<T>.IsArray ||
|
||||
(baseType.IsGenericType && baseType.GetGenericTypeDefinition() == typeof(Nullable<>)))
|
||||
{
|
||||
return ((ReadGenericDelegate<T>)_readGenericDelegates.GetOrAdd((typeof(T), node.GetType()!, notNullableOverride),
|
||||
@@ -771,7 +773,7 @@ namespace Robust.Shared.Serialization.Manager
|
||||
throw new ArgumentException($"No mapping or value node provided for type {baseType}.");
|
||||
}
|
||||
|
||||
RunAfterHook(val, hookCtx);
|
||||
TryRunAfterHook(val, hookCtx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -992,7 +994,7 @@ namespace Robust.Shared.Serialization.Manager
|
||||
throw new ArgumentException($"No mapping or value node provided for type {baseType}.");
|
||||
}
|
||||
|
||||
RunAfterHook(val, hookCtx);
|
||||
TryRunAfterHook(val, hookCtx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1427,7 +1429,7 @@ namespace Robust.Shared.Serialization.Manager
|
||||
throw new ArgumentException($"No mapping node provided for type {type} at line: {node.Start.Line}");
|
||||
}
|
||||
|
||||
RunAfterHook(instance, hookCtx);
|
||||
TryRunAfterHook(instance, hookCtx);
|
||||
|
||||
return instance;
|
||||
}
|
||||
@@ -1447,7 +1449,7 @@ namespace Robust.Shared.Serialization.Manager
|
||||
|
||||
definition.Populate(ref instance, node, this, hookCtx, context);
|
||||
|
||||
RunAfterHook(instance, hookCtx);
|
||||
TryRunAfterHook(instance, hookCtx);
|
||||
|
||||
return instance;
|
||||
}
|
||||
@@ -1456,5 +1458,16 @@ namespace Robust.Shared.Serialization.Manager
|
||||
{
|
||||
throw new ArgumentException($"No type serializer or data definition found for type {typeof(TValue)} with node type {node.GetType()} when reading");
|
||||
}
|
||||
|
||||
private static class ReadTypeMetadata<T>
|
||||
{
|
||||
// ReSharper disable once StaticMemberInGenericType
|
||||
public static bool IsArray;
|
||||
|
||||
static ReadTypeMetadata()
|
||||
{
|
||||
IsArray = typeof(T).IsArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
@@ -10,6 +11,9 @@ using Robust.Shared.Log;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.Serialization.Manager.Exceptions;
|
||||
using Robust.Shared.Serialization.Markdown;
|
||||
using Robust.Shared.Serialization.Markdown.Mapping;
|
||||
using Robust.Shared.Serialization.Markdown.Sequence;
|
||||
using Robust.Shared.Serialization.Markdown.Value;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Interfaces;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
@@ -31,6 +35,28 @@ public sealed partial class SerializationManager
|
||||
typeof(ITypeWriter<>)
|
||||
}.ToImmutableArray();
|
||||
|
||||
private static readonly ImmutableArray<Type> Nodes = new[]
|
||||
{
|
||||
typeof(MappingDataNode),
|
||||
typeof(SequenceDataNode),
|
||||
typeof(ValueDataNode),
|
||||
}.ToImmutableArray();
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="SerializerInterfaces"/>
|
||||
/// </summary>
|
||||
private const int ReaderIndex = 0;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="SerializerInterfaces"/>
|
||||
/// </summary>
|
||||
private const int InheritanceHandlerIndex = 1;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="SerializerInterfaces"/>
|
||||
/// </summary>
|
||||
private const int ValidatorIndex = 2;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="SerializerInterfaces"/>
|
||||
/// </summary>
|
||||
@@ -41,12 +67,42 @@ public sealed partial class SerializationManager
|
||||
/// </summary>
|
||||
private const int CopierIndex = 4;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="SerializerInterfaces"/>
|
||||
/// </summary>
|
||||
private const int WriterIndex = 5;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="Nodes"/>
|
||||
/// </summary>
|
||||
private const int MappingIndex = 0;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="Nodes"/>
|
||||
/// </summary>
|
||||
private const int SequenceIndex = 1;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="Nodes"/>
|
||||
/// </summary>
|
||||
private const int ValueIndex = 2;
|
||||
|
||||
private SerializerProvider _regularSerializerProvider = default!;
|
||||
|
||||
private ISawmill _serializerSawmill = default!;
|
||||
|
||||
private void InitializeTypeSerializers(IEnumerable<Type> typeSerializers)
|
||||
{
|
||||
DebugTools.AssertEqual(ReaderIndex, SerializerInterfaces.IndexOf(typeof(ITypeReader<,>)));
|
||||
DebugTools.AssertEqual(InheritanceHandlerIndex, SerializerInterfaces.IndexOf(typeof(ITypeInheritanceHandler<,>)));
|
||||
DebugTools.AssertEqual(ValidatorIndex, SerializerInterfaces.IndexOf(typeof(ITypeValidator<,>)));
|
||||
DebugTools.AssertEqual(CopyCreatorIndex, SerializerInterfaces.IndexOf(typeof(ITypeCopyCreator<>)));
|
||||
DebugTools.AssertEqual(CopierIndex, SerializerInterfaces.IndexOf(typeof(ITypeCopier<>)));
|
||||
|
||||
DebugTools.AssertEqual(MappingIndex, Nodes.IndexOf(typeof(MappingDataNode)));
|
||||
DebugTools.AssertEqual(SequenceIndex, Nodes.IndexOf(typeof(SequenceDataNode)));
|
||||
DebugTools.AssertEqual(ValueIndex, Nodes.IndexOf(typeof(ValueDataNode)));
|
||||
|
||||
_regularSerializerProvider = new(this, typeSerializers);
|
||||
}
|
||||
|
||||
@@ -62,6 +118,10 @@ public sealed partial class SerializationManager
|
||||
ser.SerMan = this;
|
||||
ser.Log = _serializerSawmill;
|
||||
}
|
||||
|
||||
if (result is IPostInjectInit postInject)
|
||||
postInject.PostInject();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -102,7 +162,7 @@ public sealed partial class SerializationManager
|
||||
|
||||
public sealed class SerializerProvider
|
||||
{
|
||||
private SerializationManager _ser;
|
||||
private readonly SerializationManager _ser;
|
||||
|
||||
public SerializerProvider(ISerializationManager ser, IEnumerable<Type> typeSerializers) : this(ser)
|
||||
{
|
||||
@@ -122,8 +182,9 @@ public sealed partial class SerializationManager
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<Type, Dictionary<(Type ObjectType, Type NodeType), object>> _typeNodeSerializers = new();
|
||||
private Dictionary<Type, Dictionary<Type, object>> _typeSerializers = new();
|
||||
private (object? Regular, object? Generic, bool Init)[] _typeNodeSerializersArray = [];
|
||||
private readonly ConcurrentDictionary<Type, ConcurrentDictionary<(Type ObjectType, Type NodeType), object>> _typeNodeSerializers = new();
|
||||
private readonly ConcurrentDictionary<Type, ConcurrentDictionary<Type, object>> _typeSerializers = new();
|
||||
|
||||
// TODO make this a 1d array containing the 6 interfaces
|
||||
/// <summary>
|
||||
@@ -131,15 +192,15 @@ public sealed partial class SerializationManager
|
||||
/// that they serialize.
|
||||
/// <see cref="SerializationManager.SerializerInterfaces"/> for the first index.
|
||||
/// </summary>
|
||||
private (object? Regular, object? Generic)[]?[] _typeSerializersArray = new (object? Regular, object? Generic)[]?[] { };
|
||||
private (object? Regular, object? Generic)[]?[] _typeSerializersArray = [];
|
||||
|
||||
private Dictionary<Type, Dictionary<(Type ObjectType, Type NodeType), Type>> _genericTypeNodeSerializers = new();
|
||||
private Dictionary<Type, Dictionary<Type, Type>> _genericTypeSerializers = new();
|
||||
private readonly ConcurrentDictionary<Type, ConcurrentDictionary<(Type ObjectType, Type NodeType), Type>> _genericTypeNodeSerializers = new();
|
||||
private readonly ConcurrentDictionary<Type, ConcurrentDictionary<Type, Type>> _genericTypeSerializers = new();
|
||||
|
||||
private List<Type> _typeNodeInterfaces = new();
|
||||
private List<Type> _typeInterfaces = new();
|
||||
private readonly List<Type> _typeNodeInterfaces = new();
|
||||
private readonly List<Type> _typeInterfaces = new();
|
||||
|
||||
private readonly object _lock = new();
|
||||
private readonly Lock _lock = new();
|
||||
|
||||
#region GetSerializerMethods
|
||||
|
||||
@@ -148,11 +209,51 @@ public sealed partial class SerializationManager
|
||||
where TNode : DataNode
|
||||
{
|
||||
serializer = default;
|
||||
if (!TryGetTypeNodeSerializer(typeof(TInterface).GetGenericTypeDefinition(), typeof(TType), typeof(TNode), out var rawSerializer))
|
||||
return false;
|
||||
object? rawSerializer;
|
||||
var index = TypeSerializerType<TInterface, TType, TNode>.Index;
|
||||
if (index < _typeNodeSerializersArray.Length)
|
||||
{
|
||||
ref var serializers = ref _typeNodeSerializersArray[index];
|
||||
if (serializers.Init)
|
||||
{
|
||||
if (serializers.Regular != null)
|
||||
{
|
||||
serializer = (TInterface) serializers.Regular;
|
||||
return true;
|
||||
}
|
||||
|
||||
serializer = (TInterface)rawSerializer;
|
||||
return true;
|
||||
if (serializers.Generic != null)
|
||||
{
|
||||
serializer = (TInterface) serializers.Generic;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TryGetTypeNodeSerializer(typeof(TInterface).GetGenericTypeDefinition(),
|
||||
typeof(TType),
|
||||
typeof(TNode),
|
||||
out rawSerializer))
|
||||
{
|
||||
serializer = (TInterface) rawSerializer;
|
||||
return true;
|
||||
}
|
||||
|
||||
serializers.Init = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TryGetTypeNodeSerializer(typeof(TInterface).GetGenericTypeDefinition(),
|
||||
typeof(TType),
|
||||
typeof(TNode),
|
||||
out rawSerializer))
|
||||
{
|
||||
serializer = (TInterface) rawSerializer;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal bool TryGetTypeNodeSerializerArray<TInterface, TType, TNode>([NotNullWhen(true)] out TInterface? serializer)
|
||||
@@ -169,30 +270,28 @@ public sealed partial class SerializationManager
|
||||
|
||||
public bool TryGetTypeNodeSerializer(Type interfaceType, Type objectType, Type nodeType, [NotNullWhen(true)] out object? serializer)
|
||||
{
|
||||
lock (_lock)
|
||||
if (_typeNodeSerializers.TryGetValue(interfaceType, out var typeNodeSerializers) &&
|
||||
typeNodeSerializers.TryGetValue((objectType, nodeType), out serializer))
|
||||
return true;
|
||||
|
||||
if (_genericTypeNodeSerializers.TryGetValue(interfaceType, out var genericTypeNodeSerializers) &&
|
||||
objectType.IsGenericType)
|
||||
{
|
||||
if (_typeNodeSerializers.TryGetValue(interfaceType, out var typeNodeSerializers) &&
|
||||
typeNodeSerializers.TryGetValue((objectType, nodeType), out serializer))
|
||||
return true;
|
||||
|
||||
if (_genericTypeNodeSerializers.TryGetValue(interfaceType, out var genericTypeNodeSerializers) &&
|
||||
objectType.IsGenericType)
|
||||
var typeDef = objectType.GetGenericTypeDefinition();
|
||||
foreach (var (key, val) in genericTypeNodeSerializers)
|
||||
{
|
||||
var typeDef = objectType.GetGenericTypeDefinition();
|
||||
foreach (var (key, val) in genericTypeNodeSerializers)
|
||||
{
|
||||
if (typeDef.HasSameMetadataDefinitionAs(key.ObjectType) && nodeType == key.NodeType)
|
||||
{
|
||||
var serializerType = val.MakeGenericType(objectType.GetGenericArguments());
|
||||
serializer = RegisterSerializer(serializerType)!;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!typeDef.HasSameMetadataDefinitionAs(key.ObjectType) || nodeType != key.NodeType)
|
||||
continue;
|
||||
|
||||
serializer = null;
|
||||
return false;
|
||||
var serializerType = val.MakeGenericType(objectType.GetGenericArguments());
|
||||
serializer = RegisterSerializer(serializerType)!;
|
||||
RegisterIndexedNodeSerializer(interfaceType, objectType, key.NodeType, serializer, false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
serializer = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public TInterface GetTypeNodeSerializer<TInterface, TType, TNode>()
|
||||
@@ -226,31 +325,34 @@ public sealed partial class SerializationManager
|
||||
|
||||
public bool TryGetTypeSerializer(Type interfaceType, Type objectType, [NotNullWhen(true)] out object? serializer)
|
||||
{
|
||||
lock (_lock)
|
||||
if (_typeSerializers.TryGetValue(interfaceType, out var typeSerializers) &&
|
||||
typeSerializers.TryGetValue(objectType, out serializer))
|
||||
return true;
|
||||
|
||||
if (_genericTypeSerializers.TryGetValue(interfaceType, out var genericTypeSerializers) &&
|
||||
objectType.IsGenericType)
|
||||
{
|
||||
if (_typeSerializers.TryGetValue(interfaceType, out var typeSerializers) &&
|
||||
typeSerializers.TryGetValue(objectType, out serializer))
|
||||
return true;
|
||||
|
||||
if (_genericTypeSerializers.TryGetValue(interfaceType, out var genericTypeSerializers) &&
|
||||
objectType.IsGenericType)
|
||||
var typeDef = objectType.GetGenericTypeDefinition();
|
||||
foreach (var (key, val) in genericTypeSerializers)
|
||||
{
|
||||
var typeDef = objectType.GetGenericTypeDefinition();
|
||||
foreach (var (key, val) in genericTypeSerializers)
|
||||
{
|
||||
if (typeDef.HasSameMetadataDefinitionAs(key))
|
||||
{
|
||||
var serializerType = val.MakeGenericType(objectType.GetGenericArguments());
|
||||
serializer = RegisterSerializer(serializerType)!;
|
||||
RegisterIndexedSerializer(objectType, SerializerInterfaces.IndexOf(interfaceType), serializer, false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!typeDef.HasSameMetadataDefinitionAs(key))
|
||||
continue;
|
||||
|
||||
serializer = null;
|
||||
return false;
|
||||
var serializerType = val.MakeGenericType(objectType.GetGenericArguments());
|
||||
serializer = RegisterSerializer(serializerType)!;
|
||||
RegisterIndexedSerializer(
|
||||
objectType,
|
||||
SerializerInterfaces.IndexOf(interfaceType),
|
||||
serializer,
|
||||
false
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
serializer = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
internal bool TryGetCopierOrCreator<TType>(out ITypeCopier<TType>? copier, out ITypeCopyCreator<TType>? copyCreator)
|
||||
@@ -311,95 +413,100 @@ public sealed partial class SerializationManager
|
||||
|
||||
private object RegisterSerializer(Type type, object obj)
|
||||
{
|
||||
lock (_lock)
|
||||
foreach (var @interface in type.GetInterfaces())
|
||||
{
|
||||
foreach (var @interface in type.GetInterfaces())
|
||||
if (!@interface.IsGenericType) continue;
|
||||
|
||||
foreach (var typeInterface in _typeInterfaces)
|
||||
{
|
||||
if (!@interface.IsGenericType) continue;
|
||||
if (!@interface.GetGenericTypeDefinition().HasSameMetadataDefinitionAs(typeInterface))
|
||||
continue;
|
||||
|
||||
for (var i = 0; i < _typeInterfaces.Count; i++)
|
||||
{
|
||||
var typeInterface = _typeInterfaces[i];
|
||||
if (@interface.GetGenericTypeDefinition().HasSameMetadataDefinitionAs(typeInterface))
|
||||
{
|
||||
var arguments = @interface.GetGenericArguments();
|
||||
if (arguments.Length != 1)
|
||||
throw new InvalidGenericParameterCountException();
|
||||
_typeSerializers.GetOrNew(typeInterface).Add(arguments[0], obj);
|
||||
RegisterIndexedSerializer(arguments[0], SerializerInterfaces.IndexOf(typeInterface), obj, true);
|
||||
}
|
||||
}
|
||||
var arguments = @interface.GetGenericArguments();
|
||||
if (arguments.Length != 1)
|
||||
throw new InvalidGenericParameterCountException();
|
||||
|
||||
foreach (var typeInterface in _typeNodeInterfaces)
|
||||
{
|
||||
if (@interface.GetGenericTypeDefinition().HasSameMetadataDefinitionAs(typeInterface))
|
||||
{
|
||||
var arguments = @interface.GetGenericArguments();
|
||||
if (arguments.Length != 2)
|
||||
throw new InvalidGenericParameterCountException();
|
||||
_typeNodeSerializers.GetOrNew(typeInterface).Add((arguments[0], arguments[1]), obj);
|
||||
}
|
||||
}
|
||||
_typeSerializers.GetOrNew(typeInterface).TryAdd(arguments[0], obj);
|
||||
RegisterIndexedSerializer(
|
||||
arguments[0],
|
||||
SerializerInterfaces.IndexOf(typeInterface),
|
||||
obj,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
return obj;
|
||||
foreach (var typeInterface in _typeNodeInterfaces)
|
||||
{
|
||||
if (!@interface.GetGenericTypeDefinition().HasSameMetadataDefinitionAs(typeInterface))
|
||||
continue;
|
||||
|
||||
var arguments = @interface.GetGenericArguments();
|
||||
if (arguments.Length != 2)
|
||||
throw new InvalidGenericParameterCountException();
|
||||
|
||||
_typeNodeSerializers.GetOrAdd(typeInterface, _ => new())
|
||||
.TryAdd((arguments[0], arguments[1]), obj);
|
||||
RegisterIndexedNodeSerializer(
|
||||
typeInterface,
|
||||
arguments[0],
|
||||
arguments[1],
|
||||
obj,
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
public T? RegisterSerializer<T>() => (T?)RegisterSerializer(typeof(T));
|
||||
|
||||
public object? RegisterSerializer(Type type)
|
||||
{
|
||||
lock (_lock)
|
||||
if (!type.IsGenericTypeDefinition)
|
||||
return RegisterSerializer(type, _ser.CreateSerializer(type));
|
||||
|
||||
var typeArguments = type.GetGenericArguments();
|
||||
foreach (var @interface in type.GetInterfaces())
|
||||
{
|
||||
if (type.IsGenericTypeDefinition)
|
||||
foreach (var typeInterface in _typeInterfaces)
|
||||
{
|
||||
var typeArguments = type.GetGenericArguments();
|
||||
foreach (var @interface in type.GetInterfaces())
|
||||
if (!@interface.GetGenericTypeDefinition().HasSameMetadataDefinitionAs(typeInterface))
|
||||
continue;
|
||||
|
||||
var arguments = @interface.GetGenericArguments();
|
||||
if (arguments.Length != 1)
|
||||
throw new InvalidGenericParameterCountException();
|
||||
var objArguments = arguments[0].GetGenericArguments();
|
||||
for (var i = 0; i < typeArguments.Length; i++)
|
||||
{
|
||||
foreach (var typeInterface in _typeInterfaces)
|
||||
{
|
||||
if (@interface.GetGenericTypeDefinition().HasSameMetadataDefinitionAs(typeInterface))
|
||||
{
|
||||
var arguments = @interface.GetGenericArguments();
|
||||
if (arguments.Length != 1)
|
||||
throw new InvalidGenericParameterCountException();
|
||||
var objArguments = arguments[0].GetGenericArguments();
|
||||
for (int i = 0; i < typeArguments.Length; i++)
|
||||
{
|
||||
if (typeArguments[i] != objArguments[i])
|
||||
throw new GenericParameterMismatchException();
|
||||
}
|
||||
|
||||
_genericTypeSerializers.GetOrNew(typeInterface).Add(arguments[0], type);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var typeInterface in _typeNodeInterfaces)
|
||||
{
|
||||
if (@interface.GetGenericTypeDefinition().HasSameMetadataDefinitionAs(typeInterface))
|
||||
{
|
||||
var arguments = @interface.GetGenericArguments();
|
||||
if (arguments.Length != 2)
|
||||
throw new InvalidGenericParameterCountException();
|
||||
var objArguments = arguments[0].GetGenericArguments();
|
||||
for (int i = 0; i < typeArguments.Length; i++)
|
||||
{
|
||||
if (typeArguments[i] != objArguments[i])
|
||||
throw new GenericParameterMismatchException();
|
||||
}
|
||||
|
||||
_genericTypeNodeSerializers.GetOrNew(typeInterface)
|
||||
.Add((arguments[0], arguments[1]), type);
|
||||
}
|
||||
}
|
||||
if (typeArguments[i] != objArguments[i])
|
||||
throw new GenericParameterMismatchException();
|
||||
}
|
||||
|
||||
return null;
|
||||
_genericTypeSerializers.GetOrNew(typeInterface).TryAdd(arguments[0], type);
|
||||
}
|
||||
|
||||
return RegisterSerializer(type, _ser.CreateSerializer(type));
|
||||
foreach (var typeInterface in _typeNodeInterfaces)
|
||||
{
|
||||
if (!@interface.GetGenericTypeDefinition().HasSameMetadataDefinitionAs(typeInterface))
|
||||
continue;
|
||||
|
||||
var arguments = @interface.GetGenericArguments();
|
||||
if (arguments.Length != 2)
|
||||
throw new InvalidGenericParameterCountException();
|
||||
var objArguments = arguments[0].GetGenericArguments();
|
||||
for (var i = 0; i < typeArguments.Length; i++)
|
||||
{
|
||||
if (typeArguments[i] != objArguments[i])
|
||||
throw new GenericParameterMismatchException();
|
||||
}
|
||||
|
||||
_genericTypeNodeSerializers.GetOrNew(typeInterface).TryAdd((arguments[0], arguments[1]), type);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
//todo paul serv3 is there a better way than comparing names here?
|
||||
@@ -420,7 +527,7 @@ public sealed partial class SerializationManager
|
||||
if (genericInterface.HasSameMetadataDefinitionAs(genericTypeNode))
|
||||
{
|
||||
var genericInterfaceParams = genericInterface.GetGenericArguments();
|
||||
for (int i = 0; i < genericParams.Length; i++)
|
||||
for (var i = 0; i < genericParams.Length; i++)
|
||||
{
|
||||
if (genericParams[i].Name != genericInterfaceParams[i].Name)
|
||||
throw new GenericParameterMismatchException();
|
||||
@@ -431,7 +538,7 @@ public sealed partial class SerializationManager
|
||||
else if (genericInterface.HasSameMetadataDefinitionAs(genericType))
|
||||
{
|
||||
var genericInterfaceParams = genericInterface.GetGenericArguments();
|
||||
for (int i = 0; i < genericParams.Length; i++)
|
||||
for (var i = 0; i < genericParams.Length; i++)
|
||||
{
|
||||
if (genericParams[i].Name != genericInterfaceParams[i].Name)
|
||||
throw new GenericParameterMismatchException();
|
||||
@@ -447,9 +554,7 @@ public sealed partial class SerializationManager
|
||||
{
|
||||
var id = SerializedType.GetId(elementType);
|
||||
if (id >= _typeSerializersArray.Length)
|
||||
{
|
||||
Array.Resize(ref _typeSerializersArray, (id + 1) * 2);
|
||||
}
|
||||
|
||||
var array = _typeSerializersArray[id];
|
||||
if (array == null)
|
||||
@@ -459,12 +564,26 @@ public sealed partial class SerializationManager
|
||||
}
|
||||
|
||||
if (regular)
|
||||
{
|
||||
array[interfaceIndex].Regular = serializer;
|
||||
}
|
||||
else
|
||||
{
|
||||
array[interfaceIndex].Generic = serializer;
|
||||
}
|
||||
|
||||
private void RegisterIndexedNodeSerializer(Type interfaceIndex, Type elementType, Type nodeType, object serializer, bool regular)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
var id = TypeSerializerType.GetId(interfaceIndex, elementType, nodeType);
|
||||
if (id >= _typeNodeSerializersArray.Length)
|
||||
Array.Resize(ref _typeNodeSerializersArray, (id + 1) * 2);
|
||||
|
||||
ref var tuple = ref _typeNodeSerializersArray[id];
|
||||
if (regular)
|
||||
tuple.Regular = serializer;
|
||||
else
|
||||
tuple.Generic = serializer;
|
||||
|
||||
tuple.Init = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -474,7 +593,7 @@ public sealed partial class SerializationManager
|
||||
private static class SerializedType
|
||||
{
|
||||
internal static int Id;
|
||||
private static readonly object Lock = new();
|
||||
private static readonly Lock Lock = new();
|
||||
|
||||
internal static int GetId(Type type)
|
||||
{
|
||||
@@ -515,4 +634,32 @@ public sealed partial class SerializationManager
|
||||
SerializationGenerated = serializationGenerated;
|
||||
}
|
||||
}
|
||||
|
||||
internal static class TypeSerializerType
|
||||
{
|
||||
internal static int GetId(Type typeInterface, Type type, Type typeNode)
|
||||
{
|
||||
var interfaceIndex = SerializerInterfaces.IndexOf(typeInterface.GetGenericTypeDefinition());
|
||||
if (interfaceIndex == -1)
|
||||
throw new ArgumentException($"Invalid type interface: {typeInterface}");
|
||||
|
||||
var nodeIndex = Nodes.IndexOf(typeNode);
|
||||
if (nodeIndex == -1)
|
||||
throw new ArgumentException($"Invalid node type: {typeInterface}");
|
||||
|
||||
return SerializedType.GetId(type) *
|
||||
(SerializerInterfaces.Length + Nodes.Length) +
|
||||
interfaceIndex +
|
||||
nodeIndex;
|
||||
}
|
||||
}
|
||||
|
||||
internal static class TypeSerializerType<TInterface, TType, TNode>
|
||||
{
|
||||
// ReSharper disable once StaticMemberInGenericType
|
||||
internal static readonly int Index = SerializedType<TType>.Information.Id *
|
||||
(SerializerInterfaces.Length + Nodes.Length) +
|
||||
SerializerInterfaces.IndexOf(typeof(TInterface).GetGenericTypeDefinition()) +
|
||||
Nodes.IndexOf(typeof(TNode));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,17 +371,17 @@ namespace Robust.Shared.Serialization.Manager
|
||||
}
|
||||
|
||||
#pragma warning disable CS0618
|
||||
private static void RunAfterHook<TValue>(TValue instance, SerializationHookContext ctx)
|
||||
{
|
||||
if (instance is ISerializationHooks hooks)
|
||||
RunAfterHookGenerated(hooks, ctx);
|
||||
}
|
||||
|
||||
private static void RunAfterHookGenerated<TValue>(TValue instance, SerializationHookContext ctx) where TValue : ISerializationHooks
|
||||
internal static void TryRunAfterHook<TValue>(TValue instance, SerializationHookContext ctx)
|
||||
{
|
||||
if (ctx.SkipHooks)
|
||||
return;
|
||||
|
||||
if (instance is ISerializationHooks hooks)
|
||||
ForceRunAfterHookGenerated(hooks, ctx);
|
||||
}
|
||||
|
||||
private static void ForceRunAfterHookGenerated<TValue>(TValue instance, SerializationHookContext ctx) where TValue : ISerializationHooks
|
||||
{
|
||||
DebugTools.Assert(!typeof(TValue).IsValueType, "ISerializationHooks must only be used on reference types");
|
||||
|
||||
if (ctx.DeferQueue != null)
|
||||
|
||||
Reference in New Issue
Block a user