mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
Add frozen collections to sandbox and add yaml type serializers (#4721)
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Frozen;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
@@ -35,7 +36,7 @@ public sealed class UITheme : IPrototype
|
||||
private ResPath _path;
|
||||
|
||||
[DataField("colors", readOnly: true)] // This is a prototype, why is this readonly??
|
||||
public Dictionary<string, Color>? Colors { get; }
|
||||
public FrozenDictionary<string, Color>? Colors { get; }
|
||||
public ResPath Path => _path == default ? new ResPath(DefaultPath+"/"+ID) : _path;
|
||||
|
||||
private void ValidateFilePath(IResourceManager manager)
|
||||
|
||||
@@ -280,6 +280,11 @@ Types:
|
||||
SortedList`2: { All: True }
|
||||
SortedSet`1: { All: True }
|
||||
Stack`1: { All: True }
|
||||
System.Collections.Frozen:
|
||||
FrozenDictionary: { All: True }
|
||||
FrozenSet: { All: True }
|
||||
FrozenDictionary`2: { All: True }
|
||||
FrozenSet`1: { All: True }
|
||||
System.Collections.Immutable:
|
||||
IImmutableDictionary`2: { All: True }
|
||||
IImmutableList`1: { All: True }
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Frozen;
|
||||
using System.Linq.Expressions;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Robust.Shared.Serialization.Manager.Definition;
|
||||
@@ -80,6 +81,14 @@ public sealed partial class SerializationManager
|
||||
Expression call;
|
||||
var sameType = baseType == actualType;
|
||||
|
||||
if (baseType.IsGenericType)
|
||||
{
|
||||
// Frozen dictionaries/sets are abstract and have a bunch of implementations, but we always serialize them as their abstract type.
|
||||
var t = baseType.GetGenericTypeDefinition();
|
||||
if (t == typeof(FrozenDictionary<,>) || t == typeof(FrozenSet<>))
|
||||
actualType = baseType;
|
||||
}
|
||||
|
||||
var targetVar = sameType ? targetParam : Expression.Variable(actualType);
|
||||
Expression sourceVar = sameType ? sourceParam : Expression.Convert(sourceParam, actualType);
|
||||
if (manager._regularSerializerProvider.TryGetTypeSerializer(typeof(ITypeCopier<>), actualType, out var copier))
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Frozen;
|
||||
using System.Globalization;
|
||||
using System.Linq.Expressions;
|
||||
using Robust.Shared.Serialization.Manager.Definition;
|
||||
@@ -74,6 +75,14 @@ public sealed partial class SerializationManager
|
||||
? Expression.Convert(objParam, sameType ? baseType.EnsureNotNullableType() : actualType)
|
||||
: sameType ? objParam : Expression.Convert(objParam, actualType);
|
||||
|
||||
if (baseType.IsGenericType)
|
||||
{
|
||||
// Frozen dictionaries/sets are abstract and have a bunch of implementations, but we always serialize them as their abstract type.
|
||||
var t = baseType.GetGenericTypeDefinition();
|
||||
if (t == typeof(FrozenDictionary<,>) || t == typeof(FrozenSet<>))
|
||||
actualType = baseType;
|
||||
}
|
||||
|
||||
Expression call;
|
||||
if (serializationManager._regularSerializerProvider.TryGetTypeSerializer(typeof(ITypeWriter<>), actualType, out var serializer))
|
||||
{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Collections.Frozen;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Robust.Shared.IoC;
|
||||
@@ -16,42 +17,19 @@ public sealed class DictionarySerializer<TKey, TValue> :
|
||||
ITypeSerializer<Dictionary<TKey, TValue>, MappingDataNode>,
|
||||
ITypeSerializer<IReadOnlyDictionary<TKey, TValue>, MappingDataNode>,
|
||||
ITypeSerializer<SortedDictionary<TKey, TValue>, MappingDataNode>,
|
||||
ITypeSerializer<FrozenDictionary<TKey, TValue>, MappingDataNode>,
|
||||
ITypeCopier<Dictionary<TKey, TValue>>,
|
||||
ITypeCopier<SortedDictionary<TKey, TValue>>,
|
||||
ITypeCopyCreator<IReadOnlyDictionary<TKey, TValue>>,
|
||||
ITypeCopier<SortedDictionary<TKey, TValue>> where TKey : notnull
|
||||
|
||||
ITypeCopyCreator<FrozenDictionary<TKey, TValue>>
|
||||
where TKey : notnull
|
||||
{
|
||||
private MappingDataNode InterfaceWrite(
|
||||
ISerializationManager serializationManager,
|
||||
IDictionary<TKey, TValue> value,
|
||||
bool alwaysWrite = false,
|
||||
ISerializationContext? context = null)
|
||||
#region Validate
|
||||
|
||||
public ValidationNode Validate(ISerializationManager serializationManager, MappingDataNode node,
|
||||
IDependencyCollection dependencies, ISerializationContext? context = null)
|
||||
{
|
||||
var mappingNode = new MappingDataNode();
|
||||
|
||||
foreach (var (key, val) in value)
|
||||
{
|
||||
mappingNode.Add(
|
||||
serializationManager.WriteValue(key, alwaysWrite, context),
|
||||
serializationManager.WriteValue(val, alwaysWrite, context));
|
||||
}
|
||||
|
||||
return mappingNode;
|
||||
}
|
||||
|
||||
public Dictionary<TKey, TValue> Read(ISerializationManager serializationManager,
|
||||
MappingDataNode node, IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context,
|
||||
ISerializationManager.InstantiationDelegate<Dictionary<TKey, TValue>>? instanceProvider)
|
||||
{
|
||||
var dict = instanceProvider != null ? instanceProvider() : new Dictionary<TKey, TValue>();
|
||||
|
||||
foreach (var (key, value) in node.Children)
|
||||
{
|
||||
dict.Add(serializationManager.Read<TKey>(key, hookCtx, context),
|
||||
serializationManager.Read<TValue>(value, hookCtx, context));
|
||||
}
|
||||
|
||||
return dict;
|
||||
return Validate(serializationManager, node, context);
|
||||
}
|
||||
|
||||
ValidationNode ITypeValidator<SortedDictionary<TKey, TValue>, MappingDataNode>.Validate(
|
||||
@@ -88,6 +66,34 @@ public sealed class DictionarySerializer<TKey, TValue> :
|
||||
return new ValidatedMappingNode(mapping);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Write
|
||||
|
||||
private MappingDataNode InterfaceWrite(
|
||||
ISerializationManager serializationManager,
|
||||
IReadOnlyDictionary<TKey, TValue> value,
|
||||
bool alwaysWrite = false,
|
||||
ISerializationContext? context = null)
|
||||
{
|
||||
var mappingNode = new MappingDataNode();
|
||||
foreach (var (key, val) in value)
|
||||
{
|
||||
mappingNode.Add(
|
||||
serializationManager.WriteValue(key, alwaysWrite, context),
|
||||
serializationManager.WriteValue(val, alwaysWrite, context));
|
||||
}
|
||||
|
||||
return mappingNode;
|
||||
}
|
||||
|
||||
|
||||
public DataNode Write(ISerializationManager serializationManager, FrozenDictionary<TKey, TValue> value, IDependencyCollection dependencies,
|
||||
bool alwaysWrite = false, ISerializationContext? context = null)
|
||||
{
|
||||
return InterfaceWrite(serializationManager, value, alwaysWrite, context);
|
||||
}
|
||||
|
||||
public DataNode Write(ISerializationManager serializationManager, Dictionary<TKey, TValue> value,
|
||||
IDependencyCollection dependencies,
|
||||
bool alwaysWrite = false,
|
||||
@@ -112,6 +118,48 @@ public sealed class DictionarySerializer<TKey, TValue> :
|
||||
return InterfaceWrite(serializationManager, value.ToDictionary(k => k.Key, v => v.Value), alwaysWrite, context);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Read
|
||||
|
||||
public Dictionary<TKey, TValue> Read(ISerializationManager serializationManager,
|
||||
MappingDataNode node, IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context,
|
||||
ISerializationManager.InstantiationDelegate<Dictionary<TKey, TValue>>? instanceProvider)
|
||||
{
|
||||
var dict = instanceProvider != null ? instanceProvider() : new Dictionary<TKey, TValue>();
|
||||
|
||||
foreach (var (key, value) in node.Children)
|
||||
{
|
||||
dict.Add(serializationManager.Read<TKey>(key, hookCtx, context),
|
||||
serializationManager.Read<TValue>(value, hookCtx, context));
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
public FrozenDictionary<TKey, TValue> Read(ISerializationManager serializationManager, MappingDataNode node,
|
||||
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null,
|
||||
ISerializationManager.InstantiationDelegate<FrozenDictionary<TKey, TValue>>? instanceProvider = null)
|
||||
{
|
||||
if (instanceProvider != null)
|
||||
{
|
||||
Logger.Warning(
|
||||
$"Provided value to a Read-call for a {nameof(FrozenDictionary<TKey, TValue>)}. Ignoring...");
|
||||
}
|
||||
|
||||
var array = new KeyValuePair<TKey, TValue>[node.Children.Count];
|
||||
int i = 0;
|
||||
foreach (var (key, value) in node.Children)
|
||||
{
|
||||
var k = serializationManager.Read<TKey>(key, hookCtx, context);
|
||||
var v = serializationManager.Read<TValue>(value, hookCtx, context);
|
||||
array[i++] = new(k,v);
|
||||
}
|
||||
|
||||
return array.ToFrozenDictionary();
|
||||
}
|
||||
|
||||
|
||||
IReadOnlyDictionary<TKey, TValue> ITypeReader<IReadOnlyDictionary<TKey, TValue>, MappingDataNode>.Read(
|
||||
ISerializationManager serializationManager, MappingDataNode node,
|
||||
IDependencyCollection dependencies,
|
||||
@@ -152,6 +200,10 @@ public sealed class DictionarySerializer<TKey, TValue> :
|
||||
return dict;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Copy
|
||||
|
||||
public void CopyTo(ISerializationManager serializationManager, Dictionary<TKey, TValue> source, ref Dictionary<TKey, TValue> target,
|
||||
IDependencyCollection dependencies,
|
||||
SerializationHookContext hookCtx,
|
||||
@@ -182,8 +234,7 @@ public sealed class DictionarySerializer<TKey, TValue> :
|
||||
public IReadOnlyDictionary<TKey, TValue> CreateCopy(ISerializationManager serializationManager, IReadOnlyDictionary<TKey, TValue> source,
|
||||
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null)
|
||||
{
|
||||
var target = new Dictionary<TKey, TValue>();
|
||||
target.EnsureCapacity(source.Count);
|
||||
var target = new Dictionary<TKey, TValue>(source.Count);
|
||||
foreach (var value in source)
|
||||
{
|
||||
target.Add(
|
||||
@@ -193,4 +244,21 @@ public sealed class DictionarySerializer<TKey, TValue> :
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
public FrozenDictionary<TKey, TValue> CreateCopy(ISerializationManager serializationManager, FrozenDictionary<TKey, TValue> source,
|
||||
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null)
|
||||
{
|
||||
var array = new KeyValuePair<TKey, TValue>[source.Count];
|
||||
int i = 0;
|
||||
foreach (var value in source)
|
||||
{
|
||||
var k = serializationManager.CreateCopy(value.Key, hookCtx, context);
|
||||
var v = serializationManager.CreateCopy(value.Value, hookCtx, context);
|
||||
array[i++] = new(k, v);
|
||||
}
|
||||
|
||||
return array.ToFrozenDictionary();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Collections.Frozen;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
@@ -15,10 +16,14 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
|
||||
[TypeSerializer]
|
||||
public sealed class HashSetSerializer<T> :
|
||||
ITypeSerializer<HashSet<T>, SequenceDataNode>,
|
||||
ITypeSerializer<FrozenSet<T>, SequenceDataNode>,
|
||||
ITypeSerializer<ImmutableHashSet<T>, SequenceDataNode>,
|
||||
ITypeCopier<HashSet<T>>,
|
||||
ITypeCopyCreator<ImmutableHashSet<T>>
|
||||
ITypeCopyCreator<ImmutableHashSet<T>>,
|
||||
ITypeCopyCreator<FrozenSet<T>>
|
||||
{
|
||||
#region Read
|
||||
|
||||
HashSet<T> ITypeReader<HashSet<T>, SequenceDataNode>.Read(ISerializationManager serializationManager,
|
||||
SequenceDataNode node,
|
||||
IDependencyCollection dependencies,
|
||||
@@ -36,6 +41,51 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
|
||||
return set;
|
||||
}
|
||||
|
||||
public FrozenSet<T> Read(ISerializationManager serializationManager, SequenceDataNode node, IDependencyCollection dependencies,
|
||||
SerializationHookContext hookCtx, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<FrozenSet<T>>? instanceProvider = null)
|
||||
{
|
||||
if (instanceProvider != null)
|
||||
Logger.Warning($"Provided value to a Read-call for a {nameof(FrozenSet<T>)}. Ignoring...");
|
||||
|
||||
var array = new T[node.Sequence.Count];
|
||||
var i = 0;
|
||||
foreach (var dataNode in node.Sequence)
|
||||
{
|
||||
array[i++] = serializationManager.Read<T>(dataNode, hookCtx, context);
|
||||
}
|
||||
return array.ToFrozenSet();
|
||||
}
|
||||
|
||||
ImmutableHashSet<T> ITypeReader<ImmutableHashSet<T>, SequenceDataNode>.Read(
|
||||
ISerializationManager serializationManager,
|
||||
SequenceDataNode node,
|
||||
IDependencyCollection dependencies,
|
||||
SerializationHookContext hookCtx,
|
||||
ISerializationContext? context,
|
||||
ISerializationManager.InstantiationDelegate<ImmutableHashSet<T>>? instanceProvider)
|
||||
{
|
||||
if (instanceProvider != null)
|
||||
Logger.Warning($"Provided value to a Read-call for a {nameof(ImmutableHashSet<T>)}. Ignoring...");
|
||||
var set = ImmutableHashSet.CreateBuilder<T>();
|
||||
|
||||
foreach (var dataNode in node.Sequence)
|
||||
{
|
||||
set.Add(serializationManager.Read<T>(dataNode, hookCtx, context));
|
||||
}
|
||||
|
||||
return set.ToImmutable();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Validate
|
||||
|
||||
public ValidationNode Validate(ISerializationManager serializationManager, SequenceDataNode node,
|
||||
IDependencyCollection dependencies, ISerializationContext? context = null)
|
||||
{
|
||||
return Validate(serializationManager, node, context);
|
||||
}
|
||||
|
||||
ValidationNode ITypeValidator<ImmutableHashSet<T>, SequenceDataNode>.Validate(
|
||||
ISerializationManager serializationManager,
|
||||
SequenceDataNode node, IDependencyCollection dependencies, ISerializationContext? context)
|
||||
@@ -61,6 +111,10 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
|
||||
return new ValidatedSequenceNode(list);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Write
|
||||
|
||||
public DataNode Write(ISerializationManager serializationManager, ImmutableHashSet<T> value,
|
||||
IDependencyCollection dependencies,
|
||||
bool alwaysWrite = false,
|
||||
@@ -69,6 +123,12 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
|
||||
return Write(serializationManager, value.ToHashSet(), dependencies, alwaysWrite, context);
|
||||
}
|
||||
|
||||
public DataNode Write(ISerializationManager serializationManager, FrozenSet<T> value, IDependencyCollection dependencies,
|
||||
bool alwaysWrite = false, ISerializationContext? context = null)
|
||||
{
|
||||
return Write(serializationManager, value.ToHashSet(), dependencies, alwaysWrite, context);
|
||||
}
|
||||
|
||||
public DataNode Write(ISerializationManager serializationManager, HashSet<T> value,
|
||||
IDependencyCollection dependencies, bool alwaysWrite = false,
|
||||
ISerializationContext? context = null)
|
||||
@@ -83,25 +143,9 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
|
||||
return sequence;
|
||||
}
|
||||
|
||||
ImmutableHashSet<T> ITypeReader<ImmutableHashSet<T>, SequenceDataNode>.Read(
|
||||
ISerializationManager serializationManager,
|
||||
SequenceDataNode node,
|
||||
IDependencyCollection dependencies,
|
||||
SerializationHookContext hookCtx,
|
||||
ISerializationContext? context,
|
||||
ISerializationManager.InstantiationDelegate<ImmutableHashSet<T>>? instanceProvider)
|
||||
{
|
||||
if (instanceProvider != null)
|
||||
Logger.Warning($"Provided value to a Read-call for a {nameof(ImmutableHashSet<T>)}. Ignoring...");
|
||||
var set = ImmutableHashSet.CreateBuilder<T>();
|
||||
#endregion
|
||||
|
||||
foreach (var dataNode in node.Sequence)
|
||||
{
|
||||
set.Add(serializationManager.Read<T>(dataNode, hookCtx, context));
|
||||
}
|
||||
|
||||
return set.ToImmutable();
|
||||
}
|
||||
#region Copy
|
||||
|
||||
public void CopyTo(ISerializationManager serializationManager, HashSet<T> source, ref HashSet<T> target,
|
||||
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null)
|
||||
@@ -118,8 +162,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
|
||||
public ImmutableHashSet<T> CreateCopy(ISerializationManager serializationManager, ImmutableHashSet<T> source,
|
||||
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null)
|
||||
{
|
||||
var target = new HashSet<T>();
|
||||
target.EnsureCapacity(source.Count);
|
||||
var target = new HashSet<T>(source.Count);
|
||||
|
||||
foreach (var val in source)
|
||||
{
|
||||
@@ -128,5 +171,19 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
|
||||
|
||||
return target.ToImmutableHashSet();
|
||||
}
|
||||
|
||||
public FrozenSet<T> CreateCopy(ISerializationManager serializationManager, FrozenSet<T> source, IDependencyCollection dependencies,
|
||||
SerializationHookContext hookCtx, ISerializationContext? context = null)
|
||||
{
|
||||
var array = new T[source.Count];
|
||||
var i = 0;
|
||||
foreach (var val in source)
|
||||
{
|
||||
array[i++] = serializationManager.CreateCopy(val, hookCtx, context);
|
||||
}
|
||||
return array.ToFrozenSet();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user