mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-09-16 07:12:27 +02:00
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
208 lines
5.6 KiB
C#
208 lines
5.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using Robust.Shared.Serialization.Markdown.Value;
|
|
using Robust.Shared.Utility;
|
|
using YamlDotNet.RepresentationModel;
|
|
|
|
namespace Robust.Shared.Serialization.Markdown.Mapping
|
|
{
|
|
public sealed class MappingDataNode : DataNode<MappingDataNode>
|
|
{
|
|
// To fetch nodes by key name with YAML, we NEED a YamlScalarNode.
|
|
// We use a thread local one to avoid allocating one every fetch, since we just replace the inner value.
|
|
// Obviously thread local to avoid threading issues.
|
|
private static readonly ThreadLocal<ValueDataNode> FetchNode =
|
|
new(() => new ValueDataNode(""));
|
|
|
|
private readonly Dictionary<DataNode, DataNode> _children = new();
|
|
|
|
public IReadOnlyDictionary<DataNode, DataNode> Children => _children;
|
|
|
|
public MappingDataNode() : base(NodeMark.Invalid, NodeMark.Invalid)
|
|
{
|
|
}
|
|
|
|
public MappingDataNode(YamlMappingNode mapping) : base(mapping.Start, mapping.End)
|
|
{
|
|
foreach (var (key, val) in mapping.Children)
|
|
{
|
|
_children.Add(key.ToDataNode(), val.ToDataNode());
|
|
}
|
|
|
|
Tag = mapping.Tag;
|
|
}
|
|
|
|
public MappingDataNode(Dictionary<DataNode, DataNode> nodes) : this()
|
|
{
|
|
foreach (var (key, val) in nodes)
|
|
{
|
|
_children.Add(key, val);
|
|
}
|
|
}
|
|
|
|
public KeyValuePair<DataNode, DataNode> this[int key] => Children.ElementAt(key);
|
|
|
|
public DataNode this[string index]
|
|
{
|
|
get => Get(index);
|
|
set => Add(new ValueDataNode(index), value);
|
|
}
|
|
|
|
private static ValueDataNode GetFetchNode(string key)
|
|
{
|
|
var node = FetchNode.Value!;
|
|
node.Value = key;
|
|
return node;
|
|
}
|
|
|
|
public MappingDataNode Add(DataNode key, DataNode node)
|
|
{
|
|
_children.Add(key, node);
|
|
return this;
|
|
}
|
|
|
|
public DataNode Get(DataNode key)
|
|
{
|
|
return _children[key];
|
|
}
|
|
|
|
public DataNode Get(string key)
|
|
{
|
|
return Get(GetFetchNode(key));
|
|
}
|
|
|
|
public bool TryGet(DataNode key, [NotNullWhen(true)] out DataNode? node)
|
|
{
|
|
if (_children.TryGetValue(key, out node))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
node = null;
|
|
return false;
|
|
}
|
|
|
|
public bool TryGet(string key, [NotNullWhen(true)] out DataNode? node)
|
|
{
|
|
return TryGet(GetFetchNode(key), out node);
|
|
}
|
|
|
|
public bool Has(DataNode key)
|
|
{
|
|
return _children.ContainsKey(key);
|
|
}
|
|
|
|
public bool Has(string key)
|
|
{
|
|
return Has(GetFetchNode(key));
|
|
}
|
|
|
|
public MappingDataNode Remove(DataNode key)
|
|
{
|
|
_children.Remove(key);
|
|
return this;
|
|
}
|
|
|
|
public MappingDataNode Remove(string key)
|
|
{
|
|
return Remove(GetFetchNode(key));
|
|
}
|
|
|
|
public T Cast<T>(string index) where T : DataNode
|
|
{
|
|
return (T) this[index];
|
|
}
|
|
|
|
public YamlMappingNode ToYaml()
|
|
{
|
|
var mapping = new YamlMappingNode();
|
|
foreach (var (key, val) in _children)
|
|
{
|
|
mapping.Add(key.ToYamlNode(), val.ToYamlNode());
|
|
}
|
|
|
|
mapping.Tag = Tag;
|
|
|
|
return mapping;
|
|
}
|
|
|
|
public MappingDataNode Merge(MappingDataNode otherMapping)
|
|
{
|
|
var newMapping = Copy();
|
|
foreach (var (key, val) in otherMapping.Children)
|
|
{
|
|
// Intentionally raises an ArgumentException
|
|
newMapping.Add(key.Copy(), val.Copy());
|
|
}
|
|
|
|
// TODO Serialization: should prob make this smarter
|
|
newMapping.Tag = Tag;
|
|
newMapping.Start = Start;
|
|
newMapping.End = End;
|
|
|
|
return newMapping;
|
|
}
|
|
|
|
public override MappingDataNode Copy()
|
|
{
|
|
var newMapping = new MappingDataNode()
|
|
{
|
|
Tag = Tag,
|
|
Start = Start,
|
|
End = End
|
|
};
|
|
|
|
foreach (var (key, val) in _children)
|
|
{
|
|
newMapping.Add(key.Copy(), val.Copy());
|
|
}
|
|
|
|
return newMapping;
|
|
}
|
|
|
|
public override MappingDataNode? Except(MappingDataNode node)
|
|
{
|
|
var mappingNode = new MappingDataNode()
|
|
{
|
|
Tag = Tag,
|
|
Start = Start,
|
|
End = End
|
|
};
|
|
|
|
foreach (var (key, val) in _children)
|
|
{
|
|
var other = node._children.FirstOrNull(p => p.Key.Equals(key));
|
|
if (other == null)
|
|
{
|
|
mappingNode.Add(key.Copy(), val.Copy());
|
|
}
|
|
else
|
|
{
|
|
var newValue = val.Except(other.Value.Value);
|
|
if (newValue == null) continue;
|
|
mappingNode.Add(key.Copy(), newValue);
|
|
}
|
|
}
|
|
|
|
if (mappingNode._children.Count == 0) return null;
|
|
|
|
return mappingNode;
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
var code = new HashCode();
|
|
foreach (var (key, value) in _children)
|
|
{
|
|
code.Add(key);
|
|
code.Add(value);
|
|
}
|
|
|
|
return code.ToHashCode();
|
|
}
|
|
}
|
|
}
|