using System.Collections; using System.Diagnostics.CodeAnalysis; namespace Nbt.Tag; public interface INbtCompound : INbtTag, IEnumerable { int Count { get; } new INbtTag this[string tagName] { get; set; } void Add(NamedTag namedTag); void Add(string tagName, INbtTag tag); void Set(NamedTag namedTag); void Set(string tagName, INbtTag tag); INbtTag Get(string tagName); T Get(string tagName) where T : INbtTag; bool TryGet(string tagName, [MaybeNullWhen(false)] out INbtTag tag); bool TryGet(string tagName, [MaybeNullWhen(false)] out T tag) where T : INbtTag; bool ContainsKey(string tagName); bool Contains(NamedTag namedTag); bool Contains(string tagName, INbtTag tag); bool Remove(string tagName); bool Remove(NamedTag namedTag); bool Remove(string tagName, INbtTag tag); bool Remove(string tagName, [MaybeNullWhen(false)] out INbtTag tag); void Clear(); } public class NbtCompound : INbtCompound { private readonly Dictionary entries = []; private static string EnsureName(string tagName) => tagName ?? throw new ArgumentNullException(nameof(tagName)); private static INbtTag EnsureValue(INbtTag tag) => tag ?? throw new ArgumentNullException(nameof(tag)); public NbtTagType Type => NbtTagType.Compound; INbtCompound INbtTag.AsCompound() => this; INbtTag INbtTag.Copy() => Copy(); public NbtCompound Copy() { var copy = new NbtCompound(); foreach (var e in entries) { copy.entries[e.Key] = e.Value.Copy(); } return copy; } public int Count => entries.Count; public INbtTag this[string tagName] { get => entries[tagName]; set => entries[EnsureName(tagName)] = EnsureValue(value); } INbtTag INbtTag.this[INbtPathElement tagPath] { get => tagPath is NbtName tagName ? this[tagName] : throw new UnsupportedPathElementException(); set => this[tagPath is NbtName tagName ? tagName : throw new UnsupportedPathElementException()] = value; } public void Add(NamedTag namedTag) => Add(namedTag.Name, namedTag.Tag); public void Add(string tagName, INbtTag tag) => entries.Add(EnsureName(tagName), EnsureValue(tag)); public void Set(NamedTag namedTag) => Set(namedTag.Name, namedTag.Tag); public void Set(string tagName, INbtTag tag) => this[tagName] = tag; public INbtTag Get(string tagName) => this[tagName]; public T Get(string tagName) where T : INbtTag => (T)Get(tagName); public bool TryGet(string tagName, [MaybeNullWhen(false)] out INbtTag tag) => entries.TryGetValue(tagName, out tag); public bool TryGet(string tagName, [MaybeNullWhen(false)] out T tag) where T : INbtTag { if (TryGet(tagName, out var t)) { tag = (T)t; return true; } tag = default; return false; } public bool ContainsKey(string tagName) => entries.ContainsKey(tagName); public bool Contains(NamedTag namedTag) => Contains(namedTag.Name, namedTag.Tag); public bool Contains(string tagName, INbtTag tag) => entries.Contains(KeyValuePair.Create(tagName, tag)); public bool Remove(string tagName) => entries.Remove(tagName); public bool Remove(NamedTag namedTag) => Remove(namedTag.Name, namedTag.Tag); public bool Remove(string tagName, INbtTag tag) => ((IDictionary)entries).Remove(KeyValuePair.Create(tagName, tag)); public bool Remove(string tagName, [MaybeNullWhen(false)] out INbtTag tag) => entries.Remove(tagName, out tag); public void Clear() => entries.Clear(); public bool Equals(INbtTag? other) => ReferenceEquals(other, this) || other is NbtCompound o && Utils.DictionaryEquals(entries, o.entries); public override bool Equals(object? obj) => ReferenceEquals(obj, this) || obj is INbtCompound other && Equals(other); public override int GetHashCode() => entries.GetHashCode(); public IEnumerator GetEnumerator() => entries.Select(e => new NamedTag(e.Key, e.Value)).GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)entries).GetEnumerator(); }