1
0
Files
named-binary-tag/Nbt/NbtPath.cs
2024-03-15 14:44:21 +01:00

140 lines
4.5 KiB
C#
Executable File

using System.Collections;
namespace Nbt;
public static class NbtPath
{
public static readonly INbtPath Empty = new EmptyNbtPathImpl();
public static INbtPath CreatePath(INbtPathElement pathElement) => new NbtPathImpl([pathElement]);
public static INbtPath CreatePath(params INbtPathElement[] pathElements) => CreatePath(pathElements.AsEnumerable());
public static INbtPath CreatePath(IEnumerable<INbtPathElement> pathElements) => new NbtPathImpl(pathElements);
public static INbtPath CreatePath(params object[] pathElements) => CreatePath(pathElements.AsEnumerable());
public static INbtPath CreatePath(IEnumerable<object> pathElements) => CreatePath(pathElements.Select(WrapPathElement));
private static INbtPathElement WrapPathElement(object pathElement) => pathElement switch
{
null => throw new ArgumentNullException(nameof(pathElement)),
string name => new NbtName(name),
int index => new NbtIndex(index),
_ => throw new ArgumentException($"Invalid path element type: {pathElement.GetType().Name}", nameof(pathElement))
};
}
public interface INbtPath : IEnumerable<INbtPathElement>
{
int Count { get; }
bool IsEmpty { get; }
INbtPathElement PopFirst(out INbtPath rest);
INbtPathElement this[int index] { get; }
INbtPath Combine(INbtPath other);
INbtPath Append(INbtPathElement pathElement);
INbtPath Insert(int index, INbtPathElement pathElement);
INbtPath Replace(int index, INbtPathElement pathElement);
}
file class NbtPathImpl(IEnumerable<INbtPathElement> pathElements) : INbtPath
{
private readonly IList<INbtPathElement> _pathElements = pathElements.AsIList();
public int Count => _pathElements.Count;
public bool IsEmpty => Count == 0;
public INbtPathElement PopFirst(out INbtPath rest)
{
var count = Count;
if (count < 1)
{
throw new IndexOutOfRangeException();
}
rest = count > 1 ? new NbtPathImpl(_pathElements.Skip(1)) : NbtPath.Empty;
return _pathElements[0];
}
public INbtPathElement this[int index] => _pathElements[index];
public INbtPath Append(INbtPathElement pathElement) => new NbtPathImpl(_pathElements.Append(pathElement));
public INbtPath Insert(int index, INbtPathElement pathElement) => new NbtPathImpl(Utils.Insert(_pathElements, index, pathElement));
public INbtPath Replace(int index, INbtPathElement pathElement) => new NbtPathImpl(Utils.Replace(_pathElements, index, pathElement));
public INbtPath Combine(INbtPath other) => new NbtPathImpl(_pathElements.Concat(other));
public IEnumerator<INbtPathElement> GetEnumerator() => _pathElements.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
file class EmptyNbtPathImpl : INbtPath
{
public int Count => 0;
public bool IsEmpty => true;
public INbtPathElement PopFirst(out INbtPath rest) => throw new IndexOutOfRangeException();
public INbtPathElement this[int index] => throw new IndexOutOfRangeException();
public INbtPath Append(INbtPathElement pathElement) => new NbtPathImpl(pathElement.Yield());
public INbtPath Insert(int index, INbtPathElement pathElement)
{
ArgumentOutOfRangeException.ThrowIfNotEqual(index, 0);
return new NbtPathImpl(pathElement.Yield());
}
public INbtPath Replace(int index, INbtPathElement pathElement)
{
throw new ArgumentOutOfRangeException(nameof(index));
}
public INbtPath Combine(INbtPath other) => other;
public IEnumerator<INbtPathElement> GetEnumerator() => Enumerable.Empty<INbtPathElement>().GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
public interface INbtPathElement
{
object Key { get; }
}
public readonly struct NbtName(string name) : INbtPathElement
{
public string Name { get; } = name;
object INbtPathElement.Key => Name;
public static implicit operator NbtName(string tagName) => new(tagName);
public static implicit operator string(NbtName nbtName) => nbtName.Name;
}
public readonly struct NbtIndex(int index) : INbtPathElement
{
public int Index { get; } = index;
object INbtPathElement.Key => Index;
public static implicit operator NbtIndex(int tagIndex) => new(tagIndex);
public static implicit operator int(NbtIndex nbtIndex) => nbtIndex.Index;
}