Begin implementing async IO
This commit is contained in:
617
Nbt/Serialization/NbtReader.cs
Executable file → Normal file
617
Nbt/Serialization/NbtReader.cs
Executable file → Normal file
@@ -1,249 +1,368 @@
|
||||
using System.Buffers;
|
||||
using System.Text;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Serialization;
|
||||
|
||||
public interface INbtReader : IDisposable
|
||||
{
|
||||
INbtTag ReadTag();
|
||||
|
||||
NamedTag ReadNamedTag();
|
||||
|
||||
NbtTagType ReadTagType();
|
||||
|
||||
sbyte ReadSByte();
|
||||
|
||||
short ReadShort();
|
||||
|
||||
int ReadInt();
|
||||
|
||||
long ReadLong();
|
||||
|
||||
float ReadFloat();
|
||||
|
||||
double ReadDouble();
|
||||
|
||||
string ReadString();
|
||||
}
|
||||
|
||||
public sealed class NbtReader(Stream stream, bool leaveOpen = false) : INbtReader
|
||||
{
|
||||
private readonly Stream stream = stream;
|
||||
private readonly bool leaveOpen = leaveOpen;
|
||||
|
||||
public Stream BaseStream => stream;
|
||||
|
||||
public static NbtReader Create(Stream stream, Compression compression = Compression.Auto, bool leaveOpen = false) => compression switch
|
||||
{
|
||||
Compression.Auto => CreateInflater(stream, leaveOpen),
|
||||
Compression.GZip => new(Utils.CreateGZipInflater(stream, leaveOpen), false),
|
||||
Compression.ZLib => new(Utils.CreateZLibInflater(stream, leaveOpen), false),
|
||||
Compression.LZ4 => new(Utils.CreateLZ4Deflater(stream, leaveOpen), false),
|
||||
_ => new(stream, leaveOpen)
|
||||
};
|
||||
|
||||
private static NbtReader CreateInflater(Stream stream, bool leaveOpen)
|
||||
{
|
||||
var cmf = stream.ReadByte();
|
||||
|
||||
if (cmf < 0)
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
|
||||
stream.Seek(-1, SeekOrigin.Current);
|
||||
|
||||
return cmf switch
|
||||
{
|
||||
0x1F => new(Utils.CreateGZipInflater(stream, leaveOpen), false),
|
||||
0x78 => new(Utils.CreateZLibInflater(stream, leaveOpen), false),
|
||||
_ => throw new UnknownCompressionSchemeException(cmf)
|
||||
};
|
||||
}
|
||||
|
||||
private int ReadBytes(byte[] buffer, int offset, int count) => stream.Read(buffer, offset, count);
|
||||
|
||||
private int ReadBytes(byte[] buffer) => ReadBytes(buffer, 0, buffer.Length);
|
||||
|
||||
private int ReadBytes(Span<byte> buffer) => stream.Read(buffer);
|
||||
|
||||
private void ReadAllBytes(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var bytesLeft = count;
|
||||
|
||||
do
|
||||
{
|
||||
var bytesRead = ReadBytes(buffer, offset + count - bytesLeft, bytesLeft);
|
||||
|
||||
if (bytesRead == 0)
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
|
||||
bytesLeft -= bytesRead;
|
||||
} while (bytesLeft > 0);
|
||||
}
|
||||
|
||||
private void ReadAllBytes(byte[] buffer) => ReadAllBytes(buffer, 0, buffer.Length);
|
||||
|
||||
private void ReadAllBytes(Span<byte> buffer)
|
||||
{
|
||||
var count = buffer.Length;
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var bytesLeft = count;
|
||||
|
||||
do
|
||||
{
|
||||
var bytesRead = ReadBytes(buffer.Slice(count - bytesLeft, bytesLeft));
|
||||
|
||||
if (bytesRead == 0)
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
|
||||
bytesLeft -= bytesRead;
|
||||
} while (bytesLeft > 0);
|
||||
}
|
||||
|
||||
private int Read() => stream.ReadByte();
|
||||
|
||||
private int ReadAndThrowIfEndOfStream()
|
||||
{
|
||||
var b = Read();
|
||||
return b < 0 ? throw new EndOfStreamException() : b;
|
||||
}
|
||||
|
||||
private void ReadEndian(Span<byte> buffer)
|
||||
{
|
||||
ReadAllBytes(buffer);
|
||||
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
buffer.Reverse();
|
||||
}
|
||||
}
|
||||
|
||||
private byte ReadByte() => (byte)ReadAndThrowIfEndOfStream();
|
||||
|
||||
public sbyte ReadSByte() => (sbyte)ReadAndThrowIfEndOfStream();
|
||||
|
||||
private ushort ReadUShort()
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(ushort)];
|
||||
ReadEndian(buffer);
|
||||
return BitConverter.ToUInt16(buffer);
|
||||
}
|
||||
|
||||
public short ReadShort()
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(short)];
|
||||
ReadEndian(buffer);
|
||||
return BitConverter.ToInt16(buffer);
|
||||
}
|
||||
|
||||
public int ReadInt()
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(int)];
|
||||
ReadEndian(buffer);
|
||||
return BitConverter.ToInt32(buffer);
|
||||
}
|
||||
|
||||
public long ReadLong()
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(long)];
|
||||
ReadEndian(buffer);
|
||||
return BitConverter.ToInt64(buffer);
|
||||
}
|
||||
|
||||
public float ReadFloat()
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(float)];
|
||||
ReadEndian(buffer);
|
||||
return BitConverter.ToSingle(buffer);
|
||||
}
|
||||
|
||||
public double ReadDouble()
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(double)];
|
||||
ReadEndian(buffer);
|
||||
return BitConverter.ToDouble(buffer);
|
||||
}
|
||||
|
||||
public string ReadString()
|
||||
{
|
||||
var len = ReadUShort();
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var buffer = ArrayPool<byte>.Shared.Rent(len);
|
||||
|
||||
try
|
||||
{
|
||||
ReadAllBytes(buffer, 0, len);
|
||||
return Encoding.UTF8.GetString(buffer, 0, len);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Array.Fill(buffer, (byte)0, 0, len);
|
||||
ArrayPool<byte>.Shared.Return(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public NbtTagType ReadTagType() => (NbtTagType)ReadByte();
|
||||
|
||||
public INbtTag ReadTag()
|
||||
{
|
||||
var tagType = NbtUtils.GetTagType(ReadTagType());
|
||||
return tagType.Read(this);
|
||||
}
|
||||
|
||||
public NamedTag ReadNamedTag()
|
||||
{
|
||||
var tagType = NbtUtils.GetTagType(ReadTagType());
|
||||
var tagName = ReadString();
|
||||
var tag = tagType.Read(this);
|
||||
return new(tagName, tag);
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
|
||||
private bool _disposedValue;
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (!_disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (!leaveOpen)
|
||||
{
|
||||
stream.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
_disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
using System.Buffers;
|
||||
using System.Text;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Serialization;
|
||||
|
||||
public interface INbtReader : IDisposable
|
||||
{
|
||||
INbtTag ReadTag();
|
||||
|
||||
NamedTag ReadNamedTag();
|
||||
|
||||
NbtTagType ReadTagType();
|
||||
|
||||
sbyte ReadSByte();
|
||||
|
||||
short ReadShort();
|
||||
|
||||
int ReadInt();
|
||||
|
||||
long ReadLong();
|
||||
|
||||
float ReadFloat();
|
||||
|
||||
double ReadDouble();
|
||||
|
||||
string ReadString();
|
||||
}
|
||||
|
||||
public interface INbtAsyncReader : IAsyncDisposable
|
||||
{
|
||||
ValueTask<INbtTag> ReadTagAsync(CancellationToken ct = default);
|
||||
|
||||
ValueTask<NamedTag> ReadNamedTagAsync(CancellationToken ct = default);
|
||||
|
||||
ValueTask<NbtTagType> ReadTagTypeAsync(CancellationToken ct = default);
|
||||
|
||||
ValueTask<sbyte> ReadSByteAsync(CancellationToken ct = default);
|
||||
|
||||
ValueTask<short> ReadShortAsync(CancellationToken ct = default);
|
||||
|
||||
ValueTask<int> ReadIntAsync(CancellationToken ct = default);
|
||||
|
||||
ValueTask<long> ReadLongAsync(CancellationToken ct = default);
|
||||
|
||||
ValueTask<float> ReadFloatAsync(CancellationToken ct = default);
|
||||
|
||||
ValueTask<double> ReadDoubleAsync(CancellationToken ct = default);
|
||||
|
||||
ValueTask<string> ReadStringAsync(CancellationToken ct = default);
|
||||
}
|
||||
|
||||
public sealed class NbtReader(Stream stream, bool leaveOpen = false) : INbtReader, INbtAsyncReader
|
||||
{
|
||||
private readonly Stream stream = stream;
|
||||
private readonly bool leaveOpen = leaveOpen;
|
||||
|
||||
public Stream BaseStream => stream;
|
||||
|
||||
public static NbtReader Create(Stream stream, Compression compression = Compression.Auto, bool leaveOpen = false) => compression switch
|
||||
{
|
||||
Compression.Auto => CreateInflater(stream, leaveOpen),
|
||||
Compression.GZip => new(Utils.CreateGZipInflater(stream, leaveOpen), false),
|
||||
Compression.ZLib => new(Utils.CreateZLibInflater(stream, leaveOpen), false),
|
||||
Compression.LZ4 => new(Utils.CreateLZ4Deflater(stream, leaveOpen), false),
|
||||
_ => new(stream, leaveOpen)
|
||||
};
|
||||
|
||||
private static NbtReader CreateInflater(Stream stream, bool leaveOpen)
|
||||
{
|
||||
if (!stream.CanSeek)
|
||||
{
|
||||
return new(stream, leaveOpen);
|
||||
}
|
||||
|
||||
var cmf = stream.ReadByte();
|
||||
|
||||
if (cmf < 0)
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
|
||||
stream.Seek(-1, SeekOrigin.Current);
|
||||
|
||||
return cmf switch
|
||||
{
|
||||
0x1F => new(Utils.CreateGZipInflater(stream, leaveOpen), false),
|
||||
0x78 => new(Utils.CreateZLibInflater(stream, leaveOpen), false),
|
||||
_ => new(stream, leaveOpen)
|
||||
};
|
||||
}
|
||||
|
||||
#region Sync
|
||||
|
||||
private int Read(byte[] buffer, int offset, int count) => stream.Read(buffer, offset, count);
|
||||
|
||||
private int Read(Span<byte> buffer) => stream.Read(buffer);
|
||||
|
||||
private void ReadExactly(byte[] buffer, int offset, int count) => stream.ReadExactly(buffer, offset, count);
|
||||
|
||||
private void ReadExactly(Span<byte> buffer) => stream.ReadExactly(buffer);
|
||||
|
||||
private byte ReadByte()
|
||||
{
|
||||
var b = new byte[1];
|
||||
ReadExactly(b);
|
||||
return b[0];
|
||||
}
|
||||
|
||||
private void ReadEndian(Span<byte> buffer)
|
||||
{
|
||||
ReadExactly(buffer);
|
||||
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
buffer.Reverse();
|
||||
}
|
||||
}
|
||||
|
||||
public sbyte ReadSByte() => (sbyte)ReadByte();
|
||||
|
||||
private ushort ReadUShort()
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(ushort)];
|
||||
ReadEndian(buffer);
|
||||
return BitConverter.ToUInt16(buffer);
|
||||
}
|
||||
|
||||
public short ReadShort()
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(short)];
|
||||
ReadEndian(buffer);
|
||||
return BitConverter.ToInt16(buffer);
|
||||
}
|
||||
|
||||
public int ReadInt()
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(int)];
|
||||
ReadEndian(buffer);
|
||||
return BitConverter.ToInt32(buffer);
|
||||
}
|
||||
|
||||
public long ReadLong()
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(long)];
|
||||
ReadEndian(buffer);
|
||||
return BitConverter.ToInt64(buffer);
|
||||
}
|
||||
|
||||
public float ReadFloat()
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(float)];
|
||||
ReadEndian(buffer);
|
||||
return BitConverter.ToSingle(buffer);
|
||||
}
|
||||
|
||||
public double ReadDouble()
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(double)];
|
||||
ReadEndian(buffer);
|
||||
return BitConverter.ToDouble(buffer);
|
||||
}
|
||||
|
||||
public string ReadString()
|
||||
{
|
||||
var len = ReadUShort();
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var buffer = ArrayPool<byte>.Shared.Rent(len);
|
||||
|
||||
try
|
||||
{
|
||||
ReadExactly(buffer, 0, len);
|
||||
return Encoding.UTF8.GetString(buffer, 0, len);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Array.Fill(buffer, (byte)0, 0, len);
|
||||
ArrayPool<byte>.Shared.Return(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public NbtTagType ReadTagType() => (NbtTagType)ReadByte();
|
||||
|
||||
public INbtTag ReadTag()
|
||||
{
|
||||
var tagType = NbtUtils.GetTagType(ReadTagType());
|
||||
return tagType.Read(this);
|
||||
}
|
||||
|
||||
public NamedTag ReadNamedTag()
|
||||
{
|
||||
var tagType = NbtUtils.GetTagType(ReadTagType());
|
||||
var tagName = ReadString();
|
||||
var tag = tagType.Read(this);
|
||||
return new(tagName, tag);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Async
|
||||
|
||||
private ValueTask<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken ct) => new(stream.ReadAsync(buffer, offset, count, ct));
|
||||
|
||||
private ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken ct) => stream.ReadAsync(buffer, ct);
|
||||
|
||||
private ValueTask ReadExactlyAsync(byte[] buffer, int offset, int count, CancellationToken ct) => stream.ReadExactlyAsync(buffer, offset, count, ct);
|
||||
|
||||
private ValueTask ReadExactlyAsync(Memory<byte> buffer, CancellationToken ct) => stream.ReadExactlyAsync(buffer, ct);
|
||||
|
||||
private async ValueTask<int> ReadByteAsync(CancellationToken ct)
|
||||
{
|
||||
var b = new byte[1];
|
||||
await ReadExactlyAsync(b, ct);
|
||||
return b[0];
|
||||
}
|
||||
|
||||
private async ValueTask ReadEndianAsync(Memory<byte> buffer, CancellationToken ct)
|
||||
{
|
||||
await ReadExactlyAsync(buffer, ct);
|
||||
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
buffer.Span.Reverse();
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<sbyte> ReadSByteAsync(CancellationToken ct = default) => (sbyte)await ReadByteAsync(ct);
|
||||
|
||||
public async ValueTask<ushort> ReadUShortAsync(CancellationToken ct)
|
||||
{
|
||||
var buffer = new byte[sizeof(ushort)];
|
||||
await ReadEndianAsync(buffer, ct);
|
||||
return BitConverter.ToUInt16(buffer);
|
||||
}
|
||||
|
||||
public async ValueTask<short> ReadShortAsync(CancellationToken ct = default)
|
||||
{
|
||||
var buffer = new byte[sizeof(short)];
|
||||
await ReadEndianAsync(buffer, ct);
|
||||
return BitConverter.ToInt16(buffer);
|
||||
}
|
||||
|
||||
public async ValueTask<int> ReadIntAsync(CancellationToken ct = default)
|
||||
{
|
||||
var buffer = new byte[sizeof(int)];
|
||||
await ReadEndianAsync(buffer, ct);
|
||||
return BitConverter.ToInt32(buffer);
|
||||
}
|
||||
|
||||
public async ValueTask<long> ReadLongAsync(CancellationToken ct = default)
|
||||
{
|
||||
var buffer = new byte[sizeof(long)];
|
||||
await ReadEndianAsync(buffer, ct);
|
||||
return BitConverter.ToInt64(buffer);
|
||||
}
|
||||
|
||||
public async ValueTask<float> ReadFloatAsync(CancellationToken ct = default)
|
||||
{
|
||||
var buffer = new byte[sizeof(float)];
|
||||
await ReadEndianAsync(buffer, ct);
|
||||
return BitConverter.ToSingle(buffer);
|
||||
}
|
||||
|
||||
public async ValueTask<double> ReadDoubleAsync(CancellationToken ct = default)
|
||||
{
|
||||
var buffer = new byte[sizeof(double)];
|
||||
await ReadEndianAsync(buffer, ct);
|
||||
return BitConverter.ToDouble(buffer);
|
||||
}
|
||||
|
||||
public async ValueTask<string> ReadStringAsync(CancellationToken ct = default)
|
||||
{
|
||||
var len = await ReadUShortAsync(ct);
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var buffer = ArrayPool<byte>.Shared.Rent(len);
|
||||
|
||||
try
|
||||
{
|
||||
await ReadExactlyAsync(buffer, 0, len, ct);
|
||||
return Encoding.UTF8.GetString(buffer, 0, len);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Array.Fill(buffer, (byte)0, 0, len);
|
||||
ArrayPool<byte>.Shared.Return(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<NbtTagType> ReadTagTypeAsync(CancellationToken ct = default) => (NbtTagType)await ReadByteAsync(ct);
|
||||
|
||||
public async ValueTask<INbtTag> ReadTagAsync(CancellationToken ct = default)
|
||||
{
|
||||
var tagType = await ReadTagTypeAsync(ct);
|
||||
var type = NbtUtils.GetTagType(tagType);
|
||||
return await type.ReadAsync(this, ct);
|
||||
}
|
||||
|
||||
public async ValueTask<NamedTag> ReadNamedTagAsync(CancellationToken ct = default)
|
||||
{
|
||||
var tagType = await ReadTagTypeAsync(ct);
|
||||
var type = NbtUtils.GetTagType(tagType);
|
||||
var tagName = await ReadStringAsync(ct);
|
||||
var tag = await type.ReadAsync(this, ct);
|
||||
return new(tagName, tag);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
|
||||
private bool _disposedValue;
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (!_disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (!leaveOpen)
|
||||
{
|
||||
stream.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
_disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private async ValueTask DisposeAsync(bool disposing)
|
||||
{
|
||||
if (!_disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (!leaveOpen)
|
||||
{
|
||||
await stream.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
_disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
await DisposeAsync(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
524
Nbt/Serialization/NbtWriter.cs
Executable file → Normal file
524
Nbt/Serialization/NbtWriter.cs
Executable file → Normal file
@@ -1,185 +1,341 @@
|
||||
using System.Text;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Serialization;
|
||||
|
||||
public interface INbtWriter : IDisposable
|
||||
{
|
||||
void WriteNamedTag(NamedTag namedTag);
|
||||
|
||||
void WriteTag(INbtTag tag);
|
||||
|
||||
void WriteTagType(NbtTagType tagType);
|
||||
|
||||
void WriteSByte(sbyte b);
|
||||
|
||||
void WriteShort(short s);
|
||||
|
||||
void WriteInt(int i);
|
||||
|
||||
void WriteLong(long l);
|
||||
|
||||
void WriteFloat(float f);
|
||||
|
||||
void WriteDouble(double d);
|
||||
|
||||
void WriteString(string s);
|
||||
}
|
||||
|
||||
public sealed class NbtWriter(Stream stream, bool leaveOpen = false) : INbtWriter
|
||||
{
|
||||
private readonly Stream stream = stream;
|
||||
private readonly bool leaveOpen = leaveOpen;
|
||||
|
||||
public Stream BaseStream => stream;
|
||||
|
||||
public static NbtWriter Create(Stream stream, Compression compression = Compression.None, bool leaveOpen = false) => compression switch
|
||||
{
|
||||
Compression.GZip => new(Utils.CreateGZipDeflater(stream, leaveOpen), false),
|
||||
Compression.ZLib => new(Utils.CreateZLibDeflater(stream, leaveOpen), false),
|
||||
Compression.LZ4 => new(Utils.CreateLZ4Deflater(stream, leaveOpen), false),
|
||||
Compression.Auto => throw new ArgumentException($"{nameof(Compression.Auto)} is invalid for a writer", nameof(compression)),
|
||||
_ => new(stream, leaveOpen)
|
||||
};
|
||||
|
||||
public void Flush() => stream.Flush();
|
||||
|
||||
public void WriteBytes(byte[] buffer, int offset, int count) => stream.Write(buffer, offset, count);
|
||||
|
||||
public void WriteBytes(byte[] buffer) => stream.Write(buffer, 0, buffer.Length);
|
||||
|
||||
public void WriteBytes(ReadOnlySpan<byte> buffer) => stream.Write(buffer);
|
||||
|
||||
public void WriteByte(byte b) => stream.WriteByte(b);
|
||||
|
||||
private void WriteEndian(Span<byte> buffer)
|
||||
{
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
for (var i = buffer.Length - 1; i >= 0; i--)
|
||||
{
|
||||
WriteByte(buffer[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteBytes(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteSByte(sbyte b)
|
||||
{
|
||||
WriteByte((byte)b);
|
||||
}
|
||||
|
||||
public void WriteUShort(ushort s)
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(ushort)];
|
||||
BitConverter.TryWriteBytes(buffer, s);
|
||||
WriteEndian(buffer);
|
||||
}
|
||||
|
||||
public void WriteShort(short s)
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(short)];
|
||||
BitConverter.TryWriteBytes(buffer, s);
|
||||
WriteEndian(buffer);
|
||||
}
|
||||
|
||||
public void WriteUInt(uint i)
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(uint)];
|
||||
BitConverter.TryWriteBytes(buffer, i);
|
||||
WriteEndian(buffer);
|
||||
}
|
||||
|
||||
public void WriteInt(int i)
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(int)];
|
||||
BitConverter.TryWriteBytes(buffer, i);
|
||||
WriteEndian(buffer);
|
||||
}
|
||||
|
||||
public void WriteULong(ulong l)
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(ulong)];
|
||||
BitConverter.TryWriteBytes(buffer, l);
|
||||
WriteEndian(buffer);
|
||||
}
|
||||
|
||||
public void WriteLong(long l)
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(long)];
|
||||
BitConverter.TryWriteBytes(buffer, l);
|
||||
WriteEndian(buffer);
|
||||
}
|
||||
|
||||
public void WriteFloat(float f)
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(float)];
|
||||
BitConverter.TryWriteBytes(buffer, f);
|
||||
WriteEndian(buffer);
|
||||
}
|
||||
|
||||
public void WriteDouble(double d)
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(double)];
|
||||
BitConverter.TryWriteBytes(buffer, d);
|
||||
WriteEndian(buffer);
|
||||
}
|
||||
|
||||
public void WriteString(string s)
|
||||
{
|
||||
WriteUShort((ushort)s.Length);
|
||||
|
||||
var buffer = Encoding.UTF8.GetBytes(s);
|
||||
WriteBytes(buffer);
|
||||
}
|
||||
|
||||
public void WriteNamedTag(NamedTag namedTag) => WriteNamedTag(namedTag.Name, namedTag.Tag);
|
||||
|
||||
public void WriteNamedTag(string tagName, INbtTag tag)
|
||||
{
|
||||
var tagType = NbtUtils.GetTagType(tag.Type);
|
||||
WriteTagType(tag.Type);
|
||||
WriteString(tagName);
|
||||
tagType.Write(this, tag);
|
||||
}
|
||||
|
||||
public void WriteTag(INbtTag tag)
|
||||
{
|
||||
var tagType = NbtUtils.GetTagType(tag.Type);
|
||||
WriteTagType(tag.Type);
|
||||
tagType.Write(this, tag);
|
||||
}
|
||||
|
||||
public void WriteTagType(NbtTagType tagType) => WriteByte((byte)tagType);
|
||||
|
||||
#region IDisposable
|
||||
|
||||
private bool _disposedValue;
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (!_disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (!leaveOpen)
|
||||
{
|
||||
stream.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
_disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
using System.Text;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Serialization;
|
||||
|
||||
public interface INbtWriter : IDisposable
|
||||
{
|
||||
void WriteNamedTag(NamedTag namedTag);
|
||||
|
||||
void WriteTag(INbtTag tag);
|
||||
|
||||
void WriteTagType(NbtTagType tagType);
|
||||
|
||||
void WriteSByte(sbyte b);
|
||||
|
||||
void WriteShort(short s);
|
||||
|
||||
void WriteInt(int i);
|
||||
|
||||
void WriteLong(long l);
|
||||
|
||||
void WriteFloat(float f);
|
||||
|
||||
void WriteDouble(double d);
|
||||
|
||||
void WriteString(string s);
|
||||
}
|
||||
|
||||
public interface INbtAsyncWriter : IAsyncDisposable
|
||||
{
|
||||
ValueTask WriteNamedTagAsync(NamedTag namedTag, CancellationToken ct = default);
|
||||
|
||||
ValueTask WriteTagAsync(INbtTag tag, CancellationToken ct = default);
|
||||
|
||||
ValueTask WriteTagTypeAsync(NbtTagType tagType, CancellationToken ct = default);
|
||||
|
||||
ValueTask WriteSByteAsync(sbyte b, CancellationToken ct = default);
|
||||
|
||||
ValueTask WriteShortAsync(short s, CancellationToken ct = default);
|
||||
|
||||
ValueTask WriteIntAsync(int i, CancellationToken ct = default);
|
||||
|
||||
ValueTask WriteLongAsync(long l, CancellationToken ct = default);
|
||||
|
||||
ValueTask WriteFloatAsync(float f, CancellationToken ct = default);
|
||||
|
||||
ValueTask WriteDoubleAsync(double d, CancellationToken ct = default);
|
||||
|
||||
ValueTask WriteStringAsync(string s, CancellationToken ct = default);
|
||||
}
|
||||
|
||||
public sealed class NbtWriter(Stream stream, bool leaveOpen = false) : INbtWriter, INbtAsyncWriter
|
||||
{
|
||||
private readonly Stream stream = stream;
|
||||
private readonly bool leaveOpen = leaveOpen;
|
||||
|
||||
public Stream BaseStream => stream;
|
||||
|
||||
public static NbtWriter Create(Stream stream, Compression compression = Compression.None, bool leaveOpen = false) => compression switch
|
||||
{
|
||||
Compression.GZip => new(Utils.CreateGZipDeflater(stream, leaveOpen), false),
|
||||
Compression.ZLib => new(Utils.CreateZLibDeflater(stream, leaveOpen), false),
|
||||
Compression.LZ4 => new(Utils.CreateLZ4Deflater(stream, leaveOpen), false),
|
||||
Compression.Auto => throw new ArgumentException($"{nameof(Compression.Auto)} is invalid for a writer", nameof(compression)),
|
||||
_ => new(stream, leaveOpen)
|
||||
};
|
||||
|
||||
#region Sync
|
||||
|
||||
private void Flush() => stream.Flush();
|
||||
|
||||
private void Write(byte[] buffer, int offset, int count) => stream.Write(buffer, offset, count);
|
||||
|
||||
private void Write(ReadOnlySpan<byte> buffer) => stream.Write(buffer);
|
||||
|
||||
private void WriteByte(byte b) => stream.WriteByte(b);
|
||||
|
||||
private void WriteEndian(Span<byte> buffer)
|
||||
{
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
for (var i = buffer.Length - 1; i >= 0; i--)
|
||||
{
|
||||
WriteByte(buffer[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteSByte(sbyte b) => WriteByte((byte)b);
|
||||
|
||||
public void WriteUShort(ushort s)
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(ushort)];
|
||||
BitConverter.TryWriteBytes(buffer, s);
|
||||
WriteEndian(buffer);
|
||||
}
|
||||
|
||||
public void WriteShort(short s)
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(short)];
|
||||
BitConverter.TryWriteBytes(buffer, s);
|
||||
WriteEndian(buffer);
|
||||
}
|
||||
|
||||
public void WriteUInt(uint i)
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(uint)];
|
||||
BitConverter.TryWriteBytes(buffer, i);
|
||||
WriteEndian(buffer);
|
||||
}
|
||||
|
||||
public void WriteInt(int i)
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(int)];
|
||||
BitConverter.TryWriteBytes(buffer, i);
|
||||
WriteEndian(buffer);
|
||||
}
|
||||
|
||||
public void WriteULong(ulong l)
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(ulong)];
|
||||
BitConverter.TryWriteBytes(buffer, l);
|
||||
WriteEndian(buffer);
|
||||
}
|
||||
|
||||
public void WriteLong(long l)
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(long)];
|
||||
BitConverter.TryWriteBytes(buffer, l);
|
||||
WriteEndian(buffer);
|
||||
}
|
||||
|
||||
public void WriteFloat(float f)
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(float)];
|
||||
BitConverter.TryWriteBytes(buffer, f);
|
||||
WriteEndian(buffer);
|
||||
}
|
||||
|
||||
public void WriteDouble(double d)
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[sizeof(double)];
|
||||
BitConverter.TryWriteBytes(buffer, d);
|
||||
WriteEndian(buffer);
|
||||
}
|
||||
|
||||
public void WriteString(string s)
|
||||
{
|
||||
WriteUShort((ushort)s.Length);
|
||||
|
||||
var buffer = Encoding.UTF8.GetBytes(s);
|
||||
Write(buffer);
|
||||
}
|
||||
|
||||
public void WriteNamedTag(NamedTag namedTag) => WriteNamedTag(namedTag.Name, namedTag.Tag);
|
||||
|
||||
public void WriteNamedTag(string tagName, INbtTag tag)
|
||||
{
|
||||
var tagType = NbtUtils.GetTagType(tag.Type);
|
||||
WriteTagType(tag.Type);
|
||||
WriteString(tagName);
|
||||
tagType.Write(this, tag);
|
||||
}
|
||||
|
||||
public void WriteTag(INbtTag tag)
|
||||
{
|
||||
var tagType = NbtUtils.GetTagType(tag.Type);
|
||||
WriteTagType(tag.Type);
|
||||
tagType.Write(this, tag);
|
||||
}
|
||||
|
||||
public void WriteTagType(NbtTagType tagType) => WriteByte((byte)tagType);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Async
|
||||
|
||||
private ValueTask FlushAsync(CancellationToken ct) => new(stream.FlushAsync(ct));
|
||||
|
||||
private ValueTask WriteAsync(byte[] buffer, int offset, int count, CancellationToken ct) => new(stream.WriteAsync(buffer, offset, count, ct));
|
||||
|
||||
private ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken ct) => stream.WriteAsync(buffer, ct);
|
||||
|
||||
private ValueTask WriteByteAsync(byte b, CancellationToken ct) => new(stream.WriteAsync([b], 0, 1, ct));
|
||||
|
||||
private async ValueTask WriteEndianAsync(Memory<byte> buffer, CancellationToken ct)
|
||||
{
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
for (var i = buffer.Length - 1; i >= 0; i--)
|
||||
{
|
||||
await WriteAsync(buffer.Slice(i, 1), ct);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await WriteAsync(buffer, ct);
|
||||
}
|
||||
}
|
||||
|
||||
public ValueTask WriteSByteAsync(sbyte b, CancellationToken ct = default) => WriteByteAsync((byte)b, ct);
|
||||
|
||||
public async ValueTask WriteUShortAsync(ushort s, CancellationToken ct = default)
|
||||
{
|
||||
var buffer = new byte[sizeof(ushort)];
|
||||
BitConverter.TryWriteBytes(buffer, s);
|
||||
await WriteEndianAsync(buffer, ct);
|
||||
}
|
||||
|
||||
public async ValueTask WriteShortAsync(short s, CancellationToken ct = default)
|
||||
{
|
||||
var buffer = new byte[sizeof(short)];
|
||||
BitConverter.TryWriteBytes(buffer, s);
|
||||
await WriteEndianAsync(buffer, ct);
|
||||
}
|
||||
|
||||
public async ValueTask WriteUIntAsync(uint i, CancellationToken ct = default)
|
||||
{
|
||||
var buffer = new byte[sizeof(uint)];
|
||||
BitConverter.TryWriteBytes(buffer, i);
|
||||
await WriteEndianAsync(buffer, ct);
|
||||
}
|
||||
|
||||
public async ValueTask WriteIntAsync(int i, CancellationToken ct = default)
|
||||
{
|
||||
var buffer = new byte[sizeof(int)];
|
||||
BitConverter.TryWriteBytes(buffer, i);
|
||||
await WriteEndianAsync(buffer, ct);
|
||||
}
|
||||
|
||||
public async ValueTask WriteULongAsync(ulong l, CancellationToken ct = default)
|
||||
{
|
||||
var buffer = new byte[sizeof(ulong)];
|
||||
BitConverter.TryWriteBytes(buffer, l);
|
||||
await WriteEndianAsync(buffer, ct);
|
||||
}
|
||||
|
||||
public async ValueTask WriteLongAsync(long l, CancellationToken ct = default)
|
||||
{
|
||||
var buffer = new byte[sizeof(long)];
|
||||
BitConverter.TryWriteBytes(buffer, l);
|
||||
await WriteEndianAsync(buffer, ct);
|
||||
}
|
||||
|
||||
public async ValueTask WriteFloatAsync(float f, CancellationToken ct = default)
|
||||
{
|
||||
var buffer = new byte[sizeof(float)];
|
||||
BitConverter.TryWriteBytes(buffer, f);
|
||||
await WriteEndianAsync(buffer, ct);
|
||||
}
|
||||
|
||||
public async ValueTask WriteDoubleAsync(double d, CancellationToken ct = default)
|
||||
{
|
||||
var buffer = new byte[sizeof(double)];
|
||||
BitConverter.TryWriteBytes(buffer, d);
|
||||
await WriteEndianAsync(buffer, ct);
|
||||
}
|
||||
|
||||
public async ValueTask WriteStringAsync(string s, CancellationToken ct = default)
|
||||
{
|
||||
await WriteUShortAsync((ushort)s.Length, ct);
|
||||
|
||||
var buffer = Encoding.UTF8.GetBytes(s);
|
||||
await WriteAsync(buffer, ct);
|
||||
}
|
||||
|
||||
public ValueTask WriteNamedTagAsync(NamedTag namedTag, CancellationToken ct = default) => WriteNamedTagAsync(namedTag.Name, namedTag.Tag, ct);
|
||||
|
||||
public async ValueTask WriteNamedTagAsync(string tagName, INbtTag tag, CancellationToken ct = default)
|
||||
{
|
||||
var tagType = NbtUtils.GetTagType(tag.Type);
|
||||
await WriteTagTypeAsync(tag.Type, ct);
|
||||
await WriteStringAsync(tagName, ct);
|
||||
await tagType.WriteAsync(this, tag, ct);
|
||||
}
|
||||
|
||||
public async ValueTask WriteTagAsync(INbtTag tag, CancellationToken ct = default)
|
||||
{
|
||||
var tagType = NbtUtils.GetTagType(tag.Type);
|
||||
await WriteTagTypeAsync(tag.Type, ct);
|
||||
await tagType.WriteAsync(this, tag, ct);
|
||||
}
|
||||
|
||||
public ValueTask WriteTagTypeAsync(NbtTagType tagType, CancellationToken ct = default) => WriteByteAsync((byte)tagType, ct);
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
|
||||
private bool _disposedValue;
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (!_disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (!leaveOpen)
|
||||
{
|
||||
stream.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
_disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private async ValueTask DisposeAsync(bool disposing)
|
||||
{
|
||||
if (!_disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (!leaveOpen)
|
||||
{
|
||||
await stream.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
_disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
await DisposeAsync(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
1155
Nbt/Serialization/SNbt.cs
Executable file → Normal file
1155
Nbt/Serialization/SNbt.cs
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
119
Nbt/Type/NbtArrayType.cs
Executable file → Normal file
119
Nbt/Type/NbtArrayType.cs
Executable file → Normal file
@@ -1,43 +1,76 @@
|
||||
using Nbt.Serialization;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Type;
|
||||
|
||||
internal abstract class NbtArrayType<T>(NbtValueType<T> elementType) : NbtType<INbtArray<T>> where T : notnull
|
||||
{
|
||||
private readonly NbtValueType<T> elementType = elementType;
|
||||
|
||||
protected virtual T ReadValue(INbtReader reader) => elementType.ReadValue(reader);
|
||||
public abstract INbtArray<T> CreateTag(T[] values);
|
||||
public virtual INbtArray<T> CreateEmptyTag() => CreateTag([]);
|
||||
protected virtual void WriteValue(INbtWriter writer, T value) => elementType.WriteValue(writer, value);
|
||||
|
||||
public override INbtArray<T> Read(INbtReader reader)
|
||||
{
|
||||
var length = reader.ReadInt();
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
return CreateEmptyTag();
|
||||
}
|
||||
|
||||
var arr = new T[length];
|
||||
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
arr[i] = ReadValue(reader);
|
||||
}
|
||||
|
||||
return CreateTag(arr);
|
||||
}
|
||||
|
||||
public override void Write(INbtWriter writer, INbtArray<T> tag)
|
||||
{
|
||||
writer.WriteInt(tag.Value.Length);
|
||||
|
||||
foreach (var e in tag)
|
||||
{
|
||||
WriteValue(writer, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
using Nbt.Serialization;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Type;
|
||||
|
||||
internal abstract class NbtArrayType<T>(NbtValueType<T> elementType) : NbtType<INbtArray<T>> where T : notnull
|
||||
{
|
||||
private readonly NbtValueType<T> elementType = elementType;
|
||||
|
||||
public abstract INbtArray<T> CreateTag(T[] values);
|
||||
public virtual INbtArray<T> CreateEmptyTag() => CreateTag([]);
|
||||
|
||||
protected virtual T ReadValue(INbtReader reader) => elementType.ReadValue(reader);
|
||||
protected virtual ValueTask<T> ReadValueAsync(INbtAsyncReader reader, CancellationToken ct = default) => elementType.ReadValueAsync(reader, ct);
|
||||
|
||||
protected virtual void WriteValue(INbtWriter writer, T value) => elementType.WriteValue(writer, value);
|
||||
protected virtual ValueTask WriteValueAsync(INbtAsyncWriter writer, T value, CancellationToken ct) => elementType.WriteValueAsync(writer, value, ct);
|
||||
|
||||
public override INbtArray<T> Read(INbtReader reader)
|
||||
{
|
||||
var length = reader.ReadInt();
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
return CreateEmptyTag();
|
||||
}
|
||||
|
||||
var arr = new T[length];
|
||||
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
arr[i] = ReadValue(reader);
|
||||
}
|
||||
|
||||
return CreateTag(arr);
|
||||
}
|
||||
|
||||
public override async ValueTask<INbtArray<T>> ReadAsync(INbtAsyncReader reader, CancellationToken ct = default)
|
||||
{
|
||||
var length = await reader.ReadIntAsync(ct);
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
return CreateEmptyTag();
|
||||
}
|
||||
|
||||
var arr = new T[length];
|
||||
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
arr[i] = await ReadValueAsync(reader, ct);
|
||||
}
|
||||
|
||||
return CreateTag(arr);
|
||||
}
|
||||
|
||||
public override void Write(INbtWriter writer, INbtArray<T> tag)
|
||||
{
|
||||
writer.WriteInt(tag.Value.Length);
|
||||
|
||||
foreach (var e in tag)
|
||||
{
|
||||
WriteValue(writer, e);
|
||||
}
|
||||
}
|
||||
|
||||
public override async ValueTask WriteAsync(INbtAsyncWriter writer, INbtArray<T> tag, CancellationToken ct = default)
|
||||
{
|
||||
await writer.WriteIntAsync(tag.Value.Length, ct);
|
||||
|
||||
foreach (var e in tag)
|
||||
{
|
||||
await WriteValueAsync(writer, e, ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
123
Nbt/Type/NbtCompoundType.cs
Executable file → Normal file
123
Nbt/Type/NbtCompoundType.cs
Executable file → Normal file
@@ -1,45 +1,78 @@
|
||||
using Nbt.Serialization;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Type;
|
||||
|
||||
internal class NbtCompoundType : NbtType<INbtCompound>
|
||||
{
|
||||
public static readonly NbtCompoundType Value = new();
|
||||
|
||||
private NbtCompoundType() { }
|
||||
|
||||
public override NbtTagType Type => NbtTagType.Compound;
|
||||
|
||||
public override INbtCompound Read(INbtReader reader)
|
||||
{
|
||||
var compound = new NbtCompound();
|
||||
|
||||
while (true)
|
||||
{
|
||||
var tagType = NbtUtils.GetTagType(reader.ReadTagType());
|
||||
|
||||
if (tagType == NbtEndType.Value)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var tagName = reader.ReadString();
|
||||
var tag = tagType.Read(reader);
|
||||
|
||||
compound.Add(tagName, tag);
|
||||
}
|
||||
|
||||
return compound;
|
||||
}
|
||||
|
||||
public override void Write(INbtWriter writer, INbtCompound tag)
|
||||
{
|
||||
foreach (var entry in (IEnumerable<NamedTag>)tag)
|
||||
{
|
||||
writer.WriteNamedTag(entry);
|
||||
}
|
||||
|
||||
writer.WriteTag(NbtEnd.Value);
|
||||
}
|
||||
}
|
||||
using Nbt.Serialization;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Type;
|
||||
|
||||
internal class NbtCompoundType : NbtType<INbtCompound>
|
||||
{
|
||||
public static readonly NbtCompoundType Value = new();
|
||||
|
||||
private NbtCompoundType() { }
|
||||
|
||||
public override NbtTagType Type => NbtTagType.Compound;
|
||||
|
||||
public override INbtCompound Read(INbtReader reader)
|
||||
{
|
||||
var compound = new NbtCompound();
|
||||
|
||||
while (true)
|
||||
{
|
||||
var tagType = NbtUtils.GetTagType(reader.ReadTagType());
|
||||
|
||||
if (tagType == NbtEndType.Value)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var tagName = reader.ReadString();
|
||||
var tag = tagType.Read(reader);
|
||||
|
||||
compound.Add(tagName, tag);
|
||||
}
|
||||
|
||||
return compound;
|
||||
}
|
||||
|
||||
public override async ValueTask<INbtCompound> ReadAsync(INbtAsyncReader reader, CancellationToken ct = default)
|
||||
{
|
||||
var compound = new NbtCompound();
|
||||
|
||||
while (true)
|
||||
{
|
||||
var tagType = await reader.ReadTagTypeAsync(ct);
|
||||
var type = NbtUtils.GetTagType(tagType);
|
||||
|
||||
if (type == NbtEndType.Value)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var tagName = await reader.ReadStringAsync(ct);
|
||||
var tag = await type.ReadAsync(reader, ct);
|
||||
|
||||
compound.Add(tagName, tag);
|
||||
}
|
||||
|
||||
return compound;
|
||||
}
|
||||
|
||||
public override void Write(INbtWriter writer, INbtCompound tag)
|
||||
{
|
||||
foreach (var entry in (IEnumerable<NamedTag>)tag)
|
||||
{
|
||||
writer.WriteNamedTag(entry);
|
||||
}
|
||||
|
||||
writer.WriteTag(NbtEnd.Value);
|
||||
}
|
||||
|
||||
public override async ValueTask WriteAsync(INbtAsyncWriter writer, INbtCompound tag, CancellationToken ct = default)
|
||||
{
|
||||
foreach (var entry in (IEnumerable<NamedTag>)tag)
|
||||
{
|
||||
await writer.WriteNamedTagAsync(entry, ct);
|
||||
}
|
||||
|
||||
await writer.WriteTagAsync(NbtEnd.Value, ct);
|
||||
}
|
||||
}
|
||||
|
||||
38
Nbt/Type/NbtEndType.cs
Executable file → Normal file
38
Nbt/Type/NbtEndType.cs
Executable file → Normal file
@@ -1,17 +1,21 @@
|
||||
using Nbt.Serialization;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Type;
|
||||
|
||||
internal class NbtEndType : NbtType<NbtEnd>
|
||||
{
|
||||
public static readonly NbtEndType Value = new();
|
||||
|
||||
private NbtEndType() { }
|
||||
|
||||
public override NbtTagType Type => NbtTagType.End;
|
||||
|
||||
public override NbtEnd Read(INbtReader reader) => NbtEnd.Value;
|
||||
|
||||
public override void Write(INbtWriter writer, NbtEnd tag) { }
|
||||
}
|
||||
using Nbt.Serialization;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Type;
|
||||
|
||||
internal class NbtEndType : NbtType<NbtEnd>
|
||||
{
|
||||
public static readonly NbtEndType Value = new();
|
||||
|
||||
private NbtEndType() { }
|
||||
|
||||
public override NbtTagType Type => NbtTagType.End;
|
||||
|
||||
public override NbtEnd Read(INbtReader reader) => NbtEnd.Value;
|
||||
|
||||
public override ValueTask<NbtEnd> ReadAsync(INbtAsyncReader reader, CancellationToken ct = default) => ValueTask.FromResult(NbtEnd.Value);
|
||||
|
||||
public override void Write(INbtWriter writer, NbtEnd tag) { }
|
||||
|
||||
public override ValueTask WriteAsync(INbtAsyncWriter writer, NbtEnd tag, CancellationToken ct = default) => ValueTask.CompletedTask;
|
||||
}
|
||||
|
||||
102
Nbt/Type/NbtListType.cs
Executable file → Normal file
102
Nbt/Type/NbtListType.cs
Executable file → Normal file
@@ -1,38 +1,64 @@
|
||||
using Nbt.Serialization;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Type;
|
||||
|
||||
internal class NbtListType : NbtType<INbtList>
|
||||
{
|
||||
public static readonly NbtListType Value = new();
|
||||
|
||||
private NbtListType() { }
|
||||
|
||||
public override NbtTagType Type => NbtTagType.List;
|
||||
|
||||
public override NbtList Read(INbtReader reader)
|
||||
{
|
||||
var tagType = NbtUtils.GetTagType(reader.ReadTagType());
|
||||
var length = reader.ReadInt();
|
||||
|
||||
var list = new NbtList(tagType.Type);
|
||||
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
var tag = tagType.Read(reader);
|
||||
|
||||
list.Add(tag);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public override void Write(INbtWriter writer, INbtList tag)
|
||||
{
|
||||
foreach (var entry in tag)
|
||||
{
|
||||
writer.WriteTag(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
using Nbt.Serialization;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Type;
|
||||
|
||||
internal class NbtListType : NbtType<INbtList>
|
||||
{
|
||||
public static readonly NbtListType Value = new();
|
||||
|
||||
private NbtListType() { }
|
||||
|
||||
public override NbtTagType Type => NbtTagType.List;
|
||||
|
||||
public override INbtList Read(INbtReader reader)
|
||||
{
|
||||
var tagType = NbtUtils.GetTagType(reader.ReadTagType());
|
||||
var length = reader.ReadInt();
|
||||
|
||||
var list = new NbtList(tagType.Type);
|
||||
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
var tag = tagType.Read(reader);
|
||||
|
||||
list.Add(tag);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public override async ValueTask<INbtList> ReadAsync(INbtAsyncReader reader, CancellationToken ct = default)
|
||||
{
|
||||
var tagType = await reader.ReadTagTypeAsync(ct);
|
||||
var type = NbtUtils.GetTagType(tagType);
|
||||
var length = await reader.ReadIntAsync(ct);
|
||||
|
||||
var list = new NbtList(type.Type);
|
||||
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
var tag = await type.ReadAsync(reader, ct);
|
||||
|
||||
list.Add(tag);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public override void Write(INbtWriter writer, INbtList tag)
|
||||
{
|
||||
foreach (var entry in tag)
|
||||
{
|
||||
writer.WriteTag(entry);
|
||||
}
|
||||
}
|
||||
|
||||
public override async ValueTask WriteAsync(INbtAsyncWriter writer, INbtList tag, CancellationToken ct = default)
|
||||
{
|
||||
foreach (var entry in tag)
|
||||
{
|
||||
await writer.WriteTagAsync(entry, ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
72
Nbt/Type/NbtType.cs
Executable file → Normal file
72
Nbt/Type/NbtType.cs
Executable file → Normal file
@@ -1,33 +1,41 @@
|
||||
using Nbt.Serialization;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Type;
|
||||
|
||||
internal interface INbtType
|
||||
{
|
||||
NbtTagType Type { get; }
|
||||
|
||||
INbtTag Read(INbtReader reader);
|
||||
|
||||
void Write(INbtWriter writer, INbtTag tag);
|
||||
}
|
||||
|
||||
internal interface INbtType<T> : INbtType where T : INbtTag
|
||||
{
|
||||
new T Read(INbtReader reader);
|
||||
|
||||
void Write(INbtWriter writer, T tag);
|
||||
}
|
||||
|
||||
internal abstract class NbtType<T> : INbtType<T> where T : INbtTag
|
||||
{
|
||||
public abstract NbtTagType Type { get; }
|
||||
|
||||
public abstract T Read(INbtReader reader);
|
||||
|
||||
public abstract void Write(INbtWriter writer, T tag);
|
||||
|
||||
INbtTag INbtType.Read(INbtReader reader) => Read(reader);
|
||||
|
||||
void INbtType.Write(INbtWriter writer, INbtTag tag) => Write(writer, (T)tag);
|
||||
using Nbt.Serialization;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Type;
|
||||
|
||||
internal interface INbtType
|
||||
{
|
||||
NbtTagType Type { get; }
|
||||
|
||||
INbtTag Read(INbtReader reader);
|
||||
ValueTask<INbtTag> ReadAsync(INbtAsyncReader reader, CancellationToken ct = default);
|
||||
|
||||
void Write(INbtWriter writer, INbtTag tag);
|
||||
ValueTask WriteAsync(INbtAsyncWriter writer, INbtTag tag, CancellationToken ct = default);
|
||||
}
|
||||
|
||||
internal interface INbtType<T> : INbtType where T : INbtTag
|
||||
{
|
||||
new T Read(INbtReader reader);
|
||||
new ValueTask<T> ReadAsync(INbtAsyncReader reader, CancellationToken ct = default);
|
||||
|
||||
void Write(INbtWriter writer, T tag);
|
||||
ValueTask WriteAsync(INbtAsyncWriter writer, T tag, CancellationToken ct = default);
|
||||
}
|
||||
|
||||
internal abstract class NbtType<T> : INbtType<T> where T : INbtTag
|
||||
{
|
||||
public abstract NbtTagType Type { get; }
|
||||
|
||||
public abstract T Read(INbtReader reader);
|
||||
public abstract ValueTask<T> ReadAsync(INbtAsyncReader reader, CancellationToken ct = default);
|
||||
|
||||
public abstract void Write(INbtWriter writer, T tag);
|
||||
public abstract ValueTask WriteAsync(INbtAsyncWriter writer, T tag, CancellationToken ct = default);
|
||||
|
||||
INbtTag INbtType.Read(INbtReader reader) => Read(reader);
|
||||
async ValueTask<INbtTag> INbtType.ReadAsync(INbtAsyncReader reader, CancellationToken ct) => await ReadAsync(reader, ct);
|
||||
|
||||
void INbtType.Write(INbtWriter writer, INbtTag tag) => Write(writer, (T)tag);
|
||||
ValueTask INbtType.WriteAsync(INbtAsyncWriter writer, INbtTag tag, CancellationToken ct) => WriteAsync(writer, (T)tag, ct);
|
||||
}
|
||||
36
Nbt/Type/NbtValueType.cs
Executable file → Normal file
36
Nbt/Type/NbtValueType.cs
Executable file → Normal file
@@ -1,15 +1,21 @@
|
||||
using Nbt.Serialization;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Type;
|
||||
|
||||
internal abstract class NbtValueType<T> : NbtType<INbtValue<T>> where T : notnull
|
||||
{
|
||||
protected internal abstract T ReadValue(INbtReader reader);
|
||||
public abstract INbtValue<T> CreateTag(T value);
|
||||
protected internal abstract void WriteValue(INbtWriter writer, T value);
|
||||
|
||||
public override INbtValue<T> Read(INbtReader reader) => CreateTag(ReadValue(reader));
|
||||
|
||||
public override void Write(INbtWriter writer, INbtValue<T> tag) => WriteValue(writer, tag.Value);
|
||||
}
|
||||
using Nbt.Serialization;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Type;
|
||||
|
||||
internal abstract class NbtValueType<T> : NbtType<INbtValue<T>> where T : notnull
|
||||
{
|
||||
public abstract INbtValue<T> CreateTag(T value);
|
||||
|
||||
protected internal abstract T ReadValue(INbtReader reader);
|
||||
protected internal abstract ValueTask<T> ReadValueAsync(INbtAsyncReader reader, CancellationToken ct);
|
||||
|
||||
protected internal abstract void WriteValue(INbtWriter writer, T value);
|
||||
protected internal abstract ValueTask WriteValueAsync(INbtAsyncWriter writer, T value, CancellationToken ct);
|
||||
|
||||
public override INbtValue<T> Read(INbtReader reader) => CreateTag(ReadValue(reader));
|
||||
public override async ValueTask<INbtValue<T>> ReadAsync(INbtAsyncReader reader, CancellationToken ct = default) => CreateTag(await ReadValueAsync(reader, ct));
|
||||
|
||||
public override void Write(INbtWriter writer, INbtValue<T> tag) => WriteValue(writer, tag.Value);
|
||||
public override ValueTask WriteAsync(INbtAsyncWriter writer, INbtValue<T> tag, CancellationToken ct = default) => WriteValueAsync(writer, tag.Value, ct);
|
||||
}
|
||||
|
||||
40
Nbt/Type/Value/NbtByteType.cs
Executable file → Normal file
40
Nbt/Type/Value/NbtByteType.cs
Executable file → Normal file
@@ -1,19 +1,21 @@
|
||||
using Nbt.Serialization;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Type;
|
||||
|
||||
internal class NbtByteType : NbtValueType<sbyte>
|
||||
{
|
||||
public static readonly NbtByteType Value = new();
|
||||
|
||||
private NbtByteType() { }
|
||||
|
||||
public override NbtTagType Type => NbtTagType.Byte;
|
||||
|
||||
protected internal override sbyte ReadValue(INbtReader reader) => reader.ReadSByte();
|
||||
|
||||
public override NbtByte CreateTag(sbyte value) => new(value);
|
||||
|
||||
protected internal override void WriteValue(INbtWriter writer, sbyte value) => writer.WriteSByte(value);
|
||||
}
|
||||
using Nbt.Serialization;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Type;
|
||||
|
||||
internal class NbtByteType : NbtValueType<sbyte>
|
||||
{
|
||||
public static readonly NbtByteType Value = new();
|
||||
|
||||
private NbtByteType() { }
|
||||
|
||||
public override NbtTagType Type => NbtTagType.Byte;
|
||||
|
||||
public override NbtByte CreateTag(sbyte value) => new(value);
|
||||
|
||||
protected internal override sbyte ReadValue(INbtReader reader) => reader.ReadSByte();
|
||||
protected internal override ValueTask<sbyte> ReadValueAsync(INbtAsyncReader reader, CancellationToken ct = default) => reader.ReadSByteAsync(ct);
|
||||
|
||||
protected internal override void WriteValue(INbtWriter writer, sbyte value) => writer.WriteSByte(value);
|
||||
protected internal override ValueTask WriteValueAsync(INbtAsyncWriter writer, sbyte value, CancellationToken ct) => writer.WriteSByteAsync(value, ct);
|
||||
}
|
||||
|
||||
40
Nbt/Type/Value/NbtDoubleType.cs
Executable file → Normal file
40
Nbt/Type/Value/NbtDoubleType.cs
Executable file → Normal file
@@ -1,19 +1,21 @@
|
||||
using Nbt.Serialization;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Type;
|
||||
|
||||
internal class NbtDoubleType : NbtValueType<double>
|
||||
{
|
||||
public static readonly NbtDoubleType Value = new();
|
||||
|
||||
private NbtDoubleType() { }
|
||||
|
||||
public override NbtTagType Type => NbtTagType.Double;
|
||||
|
||||
protected internal override double ReadValue(INbtReader reader) => reader.ReadDouble();
|
||||
|
||||
public override NbtDouble CreateTag(double value) => new(value);
|
||||
|
||||
protected internal override void WriteValue(INbtWriter writer, double value) => writer.WriteDouble(value);
|
||||
}
|
||||
using Nbt.Serialization;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Type;
|
||||
|
||||
internal class NbtDoubleType : NbtValueType<double>
|
||||
{
|
||||
public static readonly NbtDoubleType Value = new();
|
||||
|
||||
private NbtDoubleType() { }
|
||||
|
||||
public override NbtTagType Type => NbtTagType.Double;
|
||||
|
||||
public override NbtDouble CreateTag(double value) => new(value);
|
||||
|
||||
protected internal override double ReadValue(INbtReader reader) => reader.ReadDouble();
|
||||
protected internal override ValueTask<double> ReadValueAsync(INbtAsyncReader reader, CancellationToken ct = default) => reader.ReadDoubleAsync(ct);
|
||||
|
||||
protected internal override void WriteValue(INbtWriter writer, double value) => writer.WriteDouble(value);
|
||||
protected internal override ValueTask WriteValueAsync(INbtAsyncWriter writer, double value, CancellationToken ct) => writer.WriteDoubleAsync(value, ct);
|
||||
}
|
||||
|
||||
40
Nbt/Type/Value/NbtFloatType.cs
Executable file → Normal file
40
Nbt/Type/Value/NbtFloatType.cs
Executable file → Normal file
@@ -1,19 +1,21 @@
|
||||
using Nbt.Serialization;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Type;
|
||||
|
||||
internal class NbtFloatType : NbtValueType<float>
|
||||
{
|
||||
public static readonly NbtFloatType Value = new();
|
||||
|
||||
private NbtFloatType() { }
|
||||
|
||||
public override NbtTagType Type => NbtTagType.Float;
|
||||
|
||||
protected internal override float ReadValue(INbtReader reader) => reader.ReadFloat();
|
||||
|
||||
public override NbtFloat CreateTag(float value) => new(value);
|
||||
|
||||
protected internal override void WriteValue(INbtWriter writer, float value) => writer.WriteFloat(value);
|
||||
}
|
||||
using Nbt.Serialization;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Type;
|
||||
|
||||
internal class NbtFloatType : NbtValueType<float>
|
||||
{
|
||||
public static readonly NbtFloatType Value = new();
|
||||
|
||||
private NbtFloatType() { }
|
||||
|
||||
public override NbtTagType Type => NbtTagType.Float;
|
||||
|
||||
public override NbtFloat CreateTag(float value) => new(value);
|
||||
|
||||
protected internal override float ReadValue(INbtReader reader) => reader.ReadFloat();
|
||||
protected internal override ValueTask<float> ReadValueAsync(INbtAsyncReader reader, CancellationToken ct = default) => reader.ReadFloatAsync(ct);
|
||||
|
||||
protected internal override void WriteValue(INbtWriter writer, float value) => writer.WriteFloat(value);
|
||||
protected internal override ValueTask WriteValueAsync(INbtAsyncWriter writer, float value, CancellationToken ct) => writer.WriteFloatAsync(value, ct);
|
||||
}
|
||||
|
||||
40
Nbt/Type/Value/NbtIntType.cs
Executable file → Normal file
40
Nbt/Type/Value/NbtIntType.cs
Executable file → Normal file
@@ -1,19 +1,21 @@
|
||||
using Nbt.Serialization;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Type;
|
||||
|
||||
internal class NbtIntType : NbtValueType<int>
|
||||
{
|
||||
public static readonly NbtIntType Value = new();
|
||||
|
||||
private NbtIntType() { }
|
||||
|
||||
public override NbtTagType Type => NbtTagType.Int;
|
||||
|
||||
protected internal override int ReadValue(INbtReader reader) => reader.ReadInt();
|
||||
|
||||
public override NbtInt CreateTag(int value) => new(value);
|
||||
|
||||
protected internal override void WriteValue(INbtWriter writer, int value) => writer.WriteInt(value);
|
||||
}
|
||||
using Nbt.Serialization;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Type;
|
||||
|
||||
internal class NbtIntType : NbtValueType<int>
|
||||
{
|
||||
public static readonly NbtIntType Value = new();
|
||||
|
||||
private NbtIntType() { }
|
||||
|
||||
public override NbtTagType Type => NbtTagType.Int;
|
||||
|
||||
public override NbtInt CreateTag(int value) => new(value);
|
||||
|
||||
protected internal override int ReadValue(INbtReader reader) => reader.ReadInt();
|
||||
protected internal override ValueTask<int> ReadValueAsync(INbtAsyncReader reader, CancellationToken ct = default) => reader.ReadIntAsync(ct);
|
||||
|
||||
protected internal override void WriteValue(INbtWriter writer, int value) => writer.WriteInt(value);
|
||||
protected internal override ValueTask WriteValueAsync(INbtAsyncWriter writer, int value, CancellationToken ct) => writer.WriteIntAsync(value, ct);
|
||||
}
|
||||
|
||||
40
Nbt/Type/Value/NbtLongType.cs
Executable file → Normal file
40
Nbt/Type/Value/NbtLongType.cs
Executable file → Normal file
@@ -1,19 +1,21 @@
|
||||
using Nbt.Serialization;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Type;
|
||||
|
||||
internal class NbtLongType : NbtValueType<long>
|
||||
{
|
||||
public static readonly NbtLongType Value = new();
|
||||
|
||||
private NbtLongType() { }
|
||||
|
||||
public override NbtTagType Type => NbtTagType.Long;
|
||||
|
||||
protected internal override long ReadValue(INbtReader reader) => reader.ReadLong();
|
||||
|
||||
public override NbtLong CreateTag(long value) => new(value);
|
||||
|
||||
protected internal override void WriteValue(INbtWriter writer, long value) => writer.WriteLong(value);
|
||||
}
|
||||
using Nbt.Serialization;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Type;
|
||||
|
||||
internal class NbtLongType : NbtValueType<long>
|
||||
{
|
||||
public static readonly NbtLongType Value = new();
|
||||
|
||||
private NbtLongType() { }
|
||||
|
||||
public override NbtTagType Type => NbtTagType.Long;
|
||||
|
||||
public override NbtLong CreateTag(long value) => new(value);
|
||||
|
||||
protected internal override long ReadValue(INbtReader reader) => reader.ReadLong();
|
||||
protected internal override ValueTask<long> ReadValueAsync(INbtAsyncReader reader, CancellationToken ct = default) => reader.ReadLongAsync(ct);
|
||||
|
||||
protected internal override void WriteValue(INbtWriter writer, long value) => writer.WriteLong(value);
|
||||
protected internal override ValueTask WriteValueAsync(INbtAsyncWriter writer, long value, CancellationToken ct) => writer.WriteLongAsync(value, ct);
|
||||
}
|
||||
|
||||
40
Nbt/Type/Value/NbtShortType.cs
Executable file → Normal file
40
Nbt/Type/Value/NbtShortType.cs
Executable file → Normal file
@@ -1,19 +1,21 @@
|
||||
using Nbt.Serialization;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Type;
|
||||
|
||||
internal class NbtShortType : NbtValueType<short>
|
||||
{
|
||||
public static readonly NbtShortType Value = new();
|
||||
|
||||
private NbtShortType() { }
|
||||
|
||||
public override NbtTagType Type => NbtTagType.Short;
|
||||
|
||||
protected internal override short ReadValue(INbtReader reader) => reader.ReadShort();
|
||||
|
||||
public override NbtShort CreateTag(short value) => new(value);
|
||||
|
||||
protected internal override void WriteValue(INbtWriter writer, short value) => writer.WriteShort(value);
|
||||
}
|
||||
using Nbt.Serialization;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Type;
|
||||
|
||||
internal class NbtShortType : NbtValueType<short>
|
||||
{
|
||||
public static readonly NbtShortType Value = new();
|
||||
|
||||
private NbtShortType() { }
|
||||
|
||||
public override NbtTagType Type => NbtTagType.Short;
|
||||
|
||||
public override NbtShort CreateTag(short value) => new(value);
|
||||
|
||||
protected internal override short ReadValue(INbtReader reader) => reader.ReadShort();
|
||||
protected internal override ValueTask<short> ReadValueAsync(INbtAsyncReader reader, CancellationToken ct = default) => reader.ReadShortAsync(ct);
|
||||
|
||||
protected internal override void WriteValue(INbtWriter writer, short value) => writer.WriteShort(value);
|
||||
protected internal override ValueTask WriteValueAsync(INbtAsyncWriter writer, short value, CancellationToken ct) => writer.WriteShortAsync(value, ct);
|
||||
}
|
||||
|
||||
40
Nbt/Type/Value/NbtStringType.cs
Executable file → Normal file
40
Nbt/Type/Value/NbtStringType.cs
Executable file → Normal file
@@ -1,19 +1,21 @@
|
||||
using Nbt.Serialization;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Type;
|
||||
|
||||
internal class NbtStringType : NbtValueType<string>
|
||||
{
|
||||
public static readonly NbtStringType Value = new();
|
||||
|
||||
private NbtStringType() { }
|
||||
|
||||
public override NbtTagType Type => NbtTagType.String;
|
||||
|
||||
protected internal override string ReadValue(INbtReader reader) => reader.ReadString();
|
||||
|
||||
public override NbtString CreateTag(string value) => new(value);
|
||||
|
||||
protected internal override void WriteValue(INbtWriter writer, string value) => writer.WriteString(value);
|
||||
}
|
||||
using Nbt.Serialization;
|
||||
using Nbt.Tag;
|
||||
|
||||
namespace Nbt.Type;
|
||||
|
||||
internal class NbtStringType : NbtValueType<string>
|
||||
{
|
||||
public static readonly NbtStringType Value = new();
|
||||
|
||||
private NbtStringType() { }
|
||||
|
||||
public override NbtTagType Type => NbtTagType.String;
|
||||
|
||||
public override NbtString CreateTag(string value) => new(value);
|
||||
|
||||
protected internal override string ReadValue(INbtReader reader) => reader.ReadString();
|
||||
protected internal override ValueTask<string> ReadValueAsync(INbtAsyncReader reader, CancellationToken ct = default) => reader.ReadStringAsync(ct);
|
||||
|
||||
protected internal override void WriteValue(INbtWriter writer, string value) => writer.WriteString(value);
|
||||
protected internal override ValueTask WriteValueAsync(INbtAsyncWriter writer, string value, CancellationToken ct) => writer.WriteStringAsync(value, ct);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user