diff --git a/Nbt/Serialization/NbtReader.cs b/Nbt/Serialization/NbtReader.cs old mode 100755 new mode 100644 index fb215af..efe6417 --- a/Nbt/Serialization/NbtReader.cs +++ b/Nbt/Serialization/NbtReader.cs @@ -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 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 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 buffer) - { - ReadAllBytes(buffer); - - if (BitConverter.IsLittleEndian) - { - buffer.Reverse(); - } - } - - private byte ReadByte() => (byte)ReadAndThrowIfEndOfStream(); - - public sbyte ReadSByte() => (sbyte)ReadAndThrowIfEndOfStream(); - - private ushort ReadUShort() - { - Span buffer = stackalloc byte[sizeof(ushort)]; - ReadEndian(buffer); - return BitConverter.ToUInt16(buffer); - } - - public short ReadShort() - { - Span buffer = stackalloc byte[sizeof(short)]; - ReadEndian(buffer); - return BitConverter.ToInt16(buffer); - } - - public int ReadInt() - { - Span buffer = stackalloc byte[sizeof(int)]; - ReadEndian(buffer); - return BitConverter.ToInt32(buffer); - } - - public long ReadLong() - { - Span buffer = stackalloc byte[sizeof(long)]; - ReadEndian(buffer); - return BitConverter.ToInt64(buffer); - } - - public float ReadFloat() - { - Span buffer = stackalloc byte[sizeof(float)]; - ReadEndian(buffer); - return BitConverter.ToSingle(buffer); - } - - public double ReadDouble() - { - Span 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.Shared.Rent(len); - - try - { - ReadAllBytes(buffer, 0, len); - return Encoding.UTF8.GetString(buffer, 0, len); - } - finally - { - Array.Fill(buffer, (byte)0, 0, len); - ArrayPool.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 ReadTagAsync(CancellationToken ct = default); + + ValueTask ReadNamedTagAsync(CancellationToken ct = default); + + ValueTask ReadTagTypeAsync(CancellationToken ct = default); + + ValueTask ReadSByteAsync(CancellationToken ct = default); + + ValueTask ReadShortAsync(CancellationToken ct = default); + + ValueTask ReadIntAsync(CancellationToken ct = default); + + ValueTask ReadLongAsync(CancellationToken ct = default); + + ValueTask ReadFloatAsync(CancellationToken ct = default); + + ValueTask ReadDoubleAsync(CancellationToken ct = default); + + ValueTask 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 buffer) => stream.Read(buffer); + + private void ReadExactly(byte[] buffer, int offset, int count) => stream.ReadExactly(buffer, offset, count); + + private void ReadExactly(Span buffer) => stream.ReadExactly(buffer); + + private byte ReadByte() + { + var b = new byte[1]; + ReadExactly(b); + return b[0]; + } + + private void ReadEndian(Span buffer) + { + ReadExactly(buffer); + + if (BitConverter.IsLittleEndian) + { + buffer.Reverse(); + } + } + + public sbyte ReadSByte() => (sbyte)ReadByte(); + + private ushort ReadUShort() + { + Span buffer = stackalloc byte[sizeof(ushort)]; + ReadEndian(buffer); + return BitConverter.ToUInt16(buffer); + } + + public short ReadShort() + { + Span buffer = stackalloc byte[sizeof(short)]; + ReadEndian(buffer); + return BitConverter.ToInt16(buffer); + } + + public int ReadInt() + { + Span buffer = stackalloc byte[sizeof(int)]; + ReadEndian(buffer); + return BitConverter.ToInt32(buffer); + } + + public long ReadLong() + { + Span buffer = stackalloc byte[sizeof(long)]; + ReadEndian(buffer); + return BitConverter.ToInt64(buffer); + } + + public float ReadFloat() + { + Span buffer = stackalloc byte[sizeof(float)]; + ReadEndian(buffer); + return BitConverter.ToSingle(buffer); + } + + public double ReadDouble() + { + Span 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.Shared.Rent(len); + + try + { + ReadExactly(buffer, 0, len); + return Encoding.UTF8.GetString(buffer, 0, len); + } + finally + { + Array.Fill(buffer, (byte)0, 0, len); + ArrayPool.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 ReadAsync(byte[] buffer, int offset, int count, CancellationToken ct) => new(stream.ReadAsync(buffer, offset, count, ct)); + + private ValueTask ReadAsync(Memory 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 buffer, CancellationToken ct) => stream.ReadExactlyAsync(buffer, ct); + + private async ValueTask ReadByteAsync(CancellationToken ct) + { + var b = new byte[1]; + await ReadExactlyAsync(b, ct); + return b[0]; + } + + private async ValueTask ReadEndianAsync(Memory buffer, CancellationToken ct) + { + await ReadExactlyAsync(buffer, ct); + + if (BitConverter.IsLittleEndian) + { + buffer.Span.Reverse(); + } + } + + public async ValueTask ReadSByteAsync(CancellationToken ct = default) => (sbyte)await ReadByteAsync(ct); + + public async ValueTask ReadUShortAsync(CancellationToken ct) + { + var buffer = new byte[sizeof(ushort)]; + await ReadEndianAsync(buffer, ct); + return BitConverter.ToUInt16(buffer); + } + + public async ValueTask ReadShortAsync(CancellationToken ct = default) + { + var buffer = new byte[sizeof(short)]; + await ReadEndianAsync(buffer, ct); + return BitConverter.ToInt16(buffer); + } + + public async ValueTask ReadIntAsync(CancellationToken ct = default) + { + var buffer = new byte[sizeof(int)]; + await ReadEndianAsync(buffer, ct); + return BitConverter.ToInt32(buffer); + } + + public async ValueTask ReadLongAsync(CancellationToken ct = default) + { + var buffer = new byte[sizeof(long)]; + await ReadEndianAsync(buffer, ct); + return BitConverter.ToInt64(buffer); + } + + public async ValueTask ReadFloatAsync(CancellationToken ct = default) + { + var buffer = new byte[sizeof(float)]; + await ReadEndianAsync(buffer, ct); + return BitConverter.ToSingle(buffer); + } + + public async ValueTask ReadDoubleAsync(CancellationToken ct = default) + { + var buffer = new byte[sizeof(double)]; + await ReadEndianAsync(buffer, ct); + return BitConverter.ToDouble(buffer); + } + + public async ValueTask ReadStringAsync(CancellationToken ct = default) + { + var len = await ReadUShortAsync(ct); + + if (len == 0) + { + return string.Empty; + } + + var buffer = ArrayPool.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.Shared.Return(buffer); + } + } + + public async ValueTask ReadTagTypeAsync(CancellationToken ct = default) => (NbtTagType)await ReadByteAsync(ct); + + public async ValueTask ReadTagAsync(CancellationToken ct = default) + { + var tagType = await ReadTagTypeAsync(ct); + var type = NbtUtils.GetTagType(tagType); + return await type.ReadAsync(this, ct); + } + + public async ValueTask 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 +} diff --git a/Nbt/Serialization/NbtWriter.cs b/Nbt/Serialization/NbtWriter.cs old mode 100755 new mode 100644 index bda72e6..f728e00 --- a/Nbt/Serialization/NbtWriter.cs +++ b/Nbt/Serialization/NbtWriter.cs @@ -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 buffer) => stream.Write(buffer); - - public void WriteByte(byte b) => stream.WriteByte(b); - - private void WriteEndian(Span 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 buffer = stackalloc byte[sizeof(ushort)]; - BitConverter.TryWriteBytes(buffer, s); - WriteEndian(buffer); - } - - public void WriteShort(short s) - { - Span buffer = stackalloc byte[sizeof(short)]; - BitConverter.TryWriteBytes(buffer, s); - WriteEndian(buffer); - } - - public void WriteUInt(uint i) - { - Span buffer = stackalloc byte[sizeof(uint)]; - BitConverter.TryWriteBytes(buffer, i); - WriteEndian(buffer); - } - - public void WriteInt(int i) - { - Span buffer = stackalloc byte[sizeof(int)]; - BitConverter.TryWriteBytes(buffer, i); - WriteEndian(buffer); - } - - public void WriteULong(ulong l) - { - Span buffer = stackalloc byte[sizeof(ulong)]; - BitConverter.TryWriteBytes(buffer, l); - WriteEndian(buffer); - } - - public void WriteLong(long l) - { - Span buffer = stackalloc byte[sizeof(long)]; - BitConverter.TryWriteBytes(buffer, l); - WriteEndian(buffer); - } - - public void WriteFloat(float f) - { - Span buffer = stackalloc byte[sizeof(float)]; - BitConverter.TryWriteBytes(buffer, f); - WriteEndian(buffer); - } - - public void WriteDouble(double d) - { - Span 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 buffer) => stream.Write(buffer); + + private void WriteByte(byte b) => stream.WriteByte(b); + + private void WriteEndian(Span 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 buffer = stackalloc byte[sizeof(ushort)]; + BitConverter.TryWriteBytes(buffer, s); + WriteEndian(buffer); + } + + public void WriteShort(short s) + { + Span buffer = stackalloc byte[sizeof(short)]; + BitConverter.TryWriteBytes(buffer, s); + WriteEndian(buffer); + } + + public void WriteUInt(uint i) + { + Span buffer = stackalloc byte[sizeof(uint)]; + BitConverter.TryWriteBytes(buffer, i); + WriteEndian(buffer); + } + + public void WriteInt(int i) + { + Span buffer = stackalloc byte[sizeof(int)]; + BitConverter.TryWriteBytes(buffer, i); + WriteEndian(buffer); + } + + public void WriteULong(ulong l) + { + Span buffer = stackalloc byte[sizeof(ulong)]; + BitConverter.TryWriteBytes(buffer, l); + WriteEndian(buffer); + } + + public void WriteLong(long l) + { + Span buffer = stackalloc byte[sizeof(long)]; + BitConverter.TryWriteBytes(buffer, l); + WriteEndian(buffer); + } + + public void WriteFloat(float f) + { + Span buffer = stackalloc byte[sizeof(float)]; + BitConverter.TryWriteBytes(buffer, f); + WriteEndian(buffer); + } + + public void WriteDouble(double d) + { + Span 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 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 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 } \ No newline at end of file diff --git a/Nbt/Serialization/SNbt.cs b/Nbt/Serialization/SNbt.cs old mode 100755 new mode 100644 index 1514d9f..a408d6f --- a/Nbt/Serialization/SNbt.cs +++ b/Nbt/Serialization/SNbt.cs @@ -1,402 +1,753 @@ -namespace Nbt.Serialization; - -using System.Globalization; -using Nbt.Tag; - -public static class SNbt -{ - #region Serialize - - public enum SerializationStyle - { - Compact, Spaced, Indented - } - - public class SerializerOptions - { - public static readonly SerializerOptions Default = new(); - - public SerializationStyle Style { get; init; } = SerializationStyle.Compact; - public string Indent { get; init; } = " "; - public bool AlwaysQuoteTagNames { get; init; } = false; - // public bool AlwaysQuoteStringTags { get; init; } = false; - } - - public static string Serialize(INbtTag tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); - public static string Serialize(NamedTag tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); - public static string Serialize(INbtList tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); - public static string Serialize(INbtCompound tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); - public static string Serialize(INbtArray tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); - public static string Serialize(INbtValue tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); - public static string Serialize(INbtArray tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); - public static string Serialize(INbtArray tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); - public static string Serialize(INbtArray tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); - public static string Serialize(INbtValue tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); - public static string Serialize(INbtValue tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); - public static string Serialize(INbtValue tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); - public static string Serialize(INbtValue tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); - public static string Serialize(INbtValue tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); - public static string Serialize(INbtValue tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); - public static string Serialize(INbtValue tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); - - public static void Serialize(TextWriter writer, INbtTag tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); - public static void Serialize(TextWriter writer, NamedTag tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); - public static void Serialize(TextWriter writer, INbtList tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); - public static void Serialize(TextWriter writer, INbtCompound tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); - public static void Serialize(TextWriter writer, INbtArray tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); - public static void Serialize(TextWriter writer, INbtValue tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); - public static void Serialize(TextWriter writer, INbtArray tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); - public static void Serialize(TextWriter writer, INbtArray tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); - public static void Serialize(TextWriter writer, INbtArray tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); - public static void Serialize(TextWriter writer, INbtValue tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); - public static void Serialize(TextWriter writer, INbtValue tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); - public static void Serialize(TextWriter writer, INbtValue tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); - public static void Serialize(TextWriter writer, INbtValue tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); - public static void Serialize(TextWriter writer, INbtValue tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); - public static void Serialize(TextWriter writer, INbtValue tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); - public static void Serialize(TextWriter writer, INbtValue tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); - - public static void Serialize(Stream stream, INbtTag tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); - public static void Serialize(Stream stream, NamedTag tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); - public static void Serialize(Stream stream, INbtList tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); - public static void Serialize(Stream stream, INbtCompound tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); - public static void Serialize(Stream stream, INbtArray tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); - public static void Serialize(Stream stream, INbtValue tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); - public static void Serialize(Stream stream, INbtArray tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); - public static void Serialize(Stream stream, INbtArray tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); - public static void Serialize(Stream stream, INbtArray tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); - public static void Serialize(Stream stream, INbtValue tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); - public static void Serialize(Stream stream, INbtValue tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); - public static void Serialize(Stream stream, INbtValue tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); - public static void Serialize(Stream stream, INbtValue tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); - public static void Serialize(Stream stream, INbtValue tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); - public static void Serialize(Stream stream, INbtValue tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); - public static void Serialize(Stream stream, INbtValue tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); - - private static void Serialize(TextWriter writer, SerializerOptions? options, Action serialize) - { - var serializer = new Serializer(writer, options); - serialize(serializer); - } - - private static void Serialize(Stream stream, SerializerOptions? options, Action serialize) - { - using var writer = new StreamWriter(stream, leaveOpen: true); - Serialize(writer, options, serialize); - } - - private static string Serialize(SerializerOptions? options, Action serialize) - { - using var writer = new StringWriter(); - Serialize(writer, options, serialize); - return writer.ToString(); - } - - private sealed class Serializer(TextWriter writer, SerializerOptions? options) - { - private readonly TextWriter writer = writer; - private readonly SerializerOptions options = options ?? SerializerOptions.Default; - private uint depth = 0u; - - private void WriteIndent() - { - for (var i = 0u; i < depth; i++) - { - writer.Write(options.Indent); - } - } - - public void Serialize(INbtTag tag) - { - switch (tag) - { - case INbtArray arrayTag: - Serialize(arrayTag); - break; - - case INbtValue valueTag: - Serialize(valueTag); - break; - - case INbtList listTag: - Serialize(listTag); - break; - - case INbtCompound compoundTag: - Serialize(compoundTag); - break; - } - } - - public void Serialize(NamedTag namedTag) - { - if (!string.IsNullOrEmpty(namedTag.Name)) - { - writer.Write(NbtUtils.QuoteString(namedTag.Name, onlyIfNeeded: !options.AlwaysQuoteTagNames)); - writer.Write(':'); - if (options.Style is not SerializationStyle.Compact) - { - writer.Write(' '); - } - } - - Serialize(namedTag.Tag); - } - - public void Serialize(INbtList tag) - { - writer.Write('['); - - depth++; - - var style = options.Style; - var isSpaced = style is SerializationStyle.Spaced; - var isIndented = style is SerializationStyle.Indented; - - var b = false; - - foreach (var entry in tag) - { - if (b) - { - writer.Write(','); - if (isSpaced) - { - writer.Write(' '); - } - } - else - { - b = true; - } - - if (isIndented) - { - writer.WriteLine(); - WriteIndent(); - } - - Serialize(entry); - } - - depth--; - - if (b && isIndented) - { - writer.WriteLine(); - WriteIndent(); - } - - writer.Write(']'); - } - - public void Serialize(INbtCompound tag) - { - writer.Write('{'); - - depth++; - - var style = options.Style; - var isSpaced = style is SerializationStyle.Spaced; - var isIndented = style is SerializationStyle.Indented; - - var b = false; - - foreach (var entry in tag as IEnumerable) - { - if (b) - { - writer.Write(','); - if (isSpaced) - { - writer.Write(' '); - } - } - else - { - b = true; - } - - if (isIndented) - { - writer.WriteLine(); - WriteIndent(); - } - - Serialize(entry); - } - - depth--; - - if (b && isIndented) - { - writer.WriteLine(); - WriteIndent(); - } - - writer.Write('}'); - } - - public void Serialize(INbtArray tag) - { - switch (tag) - { - case INbtArray byteArrayTag: - Serialize(byteArrayTag); - break; - - case INbtArray intArrayTag: - Serialize(intArrayTag); - break; - - case INbtArray longArrayTag: - Serialize(longArrayTag); - break; - } - } - - public void Serialize(INbtValue valueTag) - { - switch (valueTag) - { - case INbtValue tag: - Serialize(tag); - break; - - case INbtValue tag: - Serialize(tag); - break; - - case INbtValue tag: - Serialize(tag); - break; - - case INbtValue tag: - Serialize(tag); - break; - - case INbtValue tag: - Serialize(tag); - break; - - case INbtValue tag: - Serialize(tag); - break; - - case INbtValue tag: - Serialize(tag); - break; - } - } - - public void Serialize(INbtArray tag) => Serialize(tag, 'B', Serialize); - - public void Serialize(INbtArray tag) => Serialize(tag, 'I', Serialize); - - public void Serialize(INbtArray tag) => Serialize(tag, 'L', Serialize); - - public void Serialize(INbtValue tag) => Serialize(tag.Value); - - public void Serialize(INbtValue tag) => Serialize(tag.Value); - - public void Serialize(INbtValue tag) => Serialize(tag.Value); - - public void Serialize(INbtValue tag) => Serialize(tag.Value); - - public void Serialize(INbtValue tag) => Serialize(tag.Value); - - public void Serialize(INbtValue tag) => Serialize(tag.Value); - - public void Serialize(INbtValue tag) => Serialize(tag.Value); - - private void Serialize(INbtArray tag, char decorator, Action writeValue) where T : notnull - { - writer.Write('['); - writer.Write(decorator); - writer.Write(';'); - - if (tag.Value.Length > 0) - { - var isNotCompact = options.Style is not SerializationStyle.Compact; - - if (isNotCompact) - { - writer.Write(' '); - } - - var b = false; - - foreach (var e in tag) - { - if (b) - { - writer.Write(','); - if (isNotCompact) - { - writer.Write(' '); - } - } - else - { - b = true; - } - - writeValue(e); - } - } - - writer.Write(']'); - } - - private void Serialize(sbyte value) - { - writer.Write(value.ToString(CultureInfo.InvariantCulture)); - writer.Write('b'); - } - - private void Serialize(short value) - { - writer.Write(value.ToString(CultureInfo.InvariantCulture)); - writer.Write('s'); - } - - private void Serialize(int value) - { - writer.Write(value.ToString(CultureInfo.InvariantCulture)); - } - - private void Serialize(long value) - { - writer.Write(value.ToString(CultureInfo.InvariantCulture)); - writer.Write('L'); - } - - private void Serialize(float value) - { - writer.Write(value.ToString(CultureInfo.InvariantCulture)); - - if (float.IsFinite(value)) - { - writer.Write('F'); - } - } - - private void Serialize(double value) - { - writer.Write(value.ToString(CultureInfo.InvariantCulture)); - - if (double.IsFinite(value)) - { - writer.Write('D'); - } - } - - private void Serialize(string value) - { - // Utils.Quote(writer, value, NbtUtils.DOUBLE_QUOTE_CHAR, NbtUtils.ESCAPE_CHAR); - writer.Write(NbtUtils.QuoteString(value, onlyIfNeeded: false)); - } - } - - #endregion -} +namespace Nbt.Serialization; + +using System.Globalization; +using Nbt.Tag; + +public static class SNbt +{ + #region Serialize + + public enum SerializationStyle + { + Compact, Spaced, Indented + } + + public class SerializerOptions + { + public static readonly SerializerOptions Default = new(); + + public SerializationStyle Style { get; init; } = SerializationStyle.Compact; + public string Indent { get; init; } = " "; + public bool AlwaysQuoteTagNames { get; init; } = false; + // public bool AlwaysQuoteStringTags { get; init; } = false; + } + + #region Sync + + public static string Serialize(INbtTag tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); + public static string Serialize(NamedTag tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); + public static string Serialize(INbtList tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); + public static string Serialize(INbtCompound tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); + public static string Serialize(INbtArray tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); + public static string Serialize(INbtValue tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); + public static string Serialize(INbtArray tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); + public static string Serialize(INbtArray tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); + public static string Serialize(INbtArray tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); + public static string Serialize(INbtValue tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); + public static string Serialize(INbtValue tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); + public static string Serialize(INbtValue tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); + public static string Serialize(INbtValue tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); + public static string Serialize(INbtValue tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); + public static string Serialize(INbtValue tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); + public static string Serialize(INbtValue tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag)); + + public static void Serialize(TextWriter writer, INbtTag tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); + public static void Serialize(TextWriter writer, NamedTag tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); + public static void Serialize(TextWriter writer, INbtList tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); + public static void Serialize(TextWriter writer, INbtCompound tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); + public static void Serialize(TextWriter writer, INbtArray tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); + public static void Serialize(TextWriter writer, INbtValue tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); + public static void Serialize(TextWriter writer, INbtArray tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); + public static void Serialize(TextWriter writer, INbtArray tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); + public static void Serialize(TextWriter writer, INbtArray tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); + public static void Serialize(TextWriter writer, INbtValue tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); + public static void Serialize(TextWriter writer, INbtValue tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); + public static void Serialize(TextWriter writer, INbtValue tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); + public static void Serialize(TextWriter writer, INbtValue tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); + public static void Serialize(TextWriter writer, INbtValue tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); + public static void Serialize(TextWriter writer, INbtValue tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); + public static void Serialize(TextWriter writer, INbtValue tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag)); + + public static void Serialize(Stream stream, INbtTag tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); + public static void Serialize(Stream stream, NamedTag tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); + public static void Serialize(Stream stream, INbtList tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); + public static void Serialize(Stream stream, INbtCompound tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); + public static void Serialize(Stream stream, INbtArray tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); + public static void Serialize(Stream stream, INbtValue tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); + public static void Serialize(Stream stream, INbtArray tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); + public static void Serialize(Stream stream, INbtArray tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); + public static void Serialize(Stream stream, INbtArray tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); + public static void Serialize(Stream stream, INbtValue tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); + public static void Serialize(Stream stream, INbtValue tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); + public static void Serialize(Stream stream, INbtValue tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); + public static void Serialize(Stream stream, INbtValue tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); + public static void Serialize(Stream stream, INbtValue tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); + public static void Serialize(Stream stream, INbtValue tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); + public static void Serialize(Stream stream, INbtValue tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag)); + + private static void Serialize(TextWriter writer, SerializerOptions? options, Action serialize) + { + var serializer = new Serializer(writer, options); + serialize(serializer); + } + + private static void Serialize(Stream stream, SerializerOptions? options, Action serialize) + { + using var writer = new StreamWriter(stream, leaveOpen: true); + Serialize(writer, options, serialize); + } + + private static string Serialize(SerializerOptions? options, Action serialize) + { + using var writer = new StringWriter(); + Serialize(writer, options, serialize); + return writer.ToString(); + } + + #endregion + + #region Async + + public static async ValueTask SerializeAsync(INbtTag tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(NamedTag tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(INbtList tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(INbtCompound tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + + public static async ValueTask SerializeAsync(TextWriter writer, INbtTag tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(TextWriter writer, NamedTag tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(TextWriter writer, INbtList tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(TextWriter writer, INbtCompound tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(TextWriter writer, INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(TextWriter writer, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(TextWriter writer, INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(TextWriter writer, INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(TextWriter writer, INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(TextWriter writer, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(TextWriter writer, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(TextWriter writer, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(TextWriter writer, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(TextWriter writer, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(TextWriter writer, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(TextWriter writer, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + + public static async ValueTask SerializeAsync(Stream stream, INbtTag tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(Stream stream, NamedTag tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(Stream stream, INbtList tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(Stream stream, INbtCompound tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(Stream stream, INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(Stream stream, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(Stream stream, INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(Stream stream, INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(Stream stream, INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(Stream stream, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(Stream stream, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(Stream stream, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(Stream stream, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(Stream stream, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(Stream stream, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + public static async ValueTask SerializeAsync(Stream stream, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct)); + + private static async ValueTask SerializeAsync(TextWriter writer, SerializerOptions? options, CancellationToken ct, Func serialize) + { + var serializer = new Serializer(writer, options); + await serialize(serializer, ct); + } + + private static async ValueTask SerializeAsync(Stream stream, SerializerOptions? options, CancellationToken ct, Func serialize) + { + using var writer = new StreamWriter(stream, leaveOpen: true); + await SerializeAsync(writer, options, ct, serialize); + } + + private static async ValueTask SerializeAsync(SerializerOptions? options, CancellationToken ct, Func serialize) + { + using var writer = new StringWriter(); + await SerializeAsync(writer, options, ct, serialize); + return writer.ToString(); + } + + #endregion + + private sealed class Serializer(TextWriter writer, SerializerOptions? options) + { + private readonly TextWriter writer = writer; + private readonly SerializerOptions options = options ?? SerializerOptions.Default; + private uint depth = 0u; + private Context? context = null; + + #region Sync + + public void Serialize(INbtTag tag) + { + switch (tag) + { + case INbtArray arrayTag: + Serialize(arrayTag); + break; + + case INbtValue valueTag: + Serialize(valueTag); + break; + + case INbtList listTag: + Serialize(listTag); + break; + + case INbtCompound compoundTag: + Serialize(compoundTag); + break; + } + } + + public void Serialize(NamedTag namedTag) + { + if (!string.IsNullOrEmpty(namedTag.Name)) + { + writer.Write(NbtUtils.QuoteString(namedTag.Name, onlyIfNeeded: !options.AlwaysQuoteTagNames)); + writer.Write(':'); + if (options.Style is not SerializationStyle.Compact) + { + writer.Write(' '); + } + } + + Serialize(namedTag.Tag); + } + + public void Serialize(INbtList tag) + { + writer.Write('['); + + EnterContext(true); + + foreach (var entry in tag) + { + WriteSeparator(); + + Serialize(entry); + + context!.Length++; + } + + ExitContext(); + + writer.Write(']'); + } + + public void Serialize(INbtCompound tag) + { + writer.Write('{'); + + EnterContext(true); + + foreach (var entry in tag as IEnumerable) + { + WriteSeparator(); + + Serialize(entry); + + context!.Length++; + } + + ExitContext(); + + writer.Write('}'); + } + + public void Serialize(INbtArray tag) + { + switch (tag) + { + case INbtArray byteArrayTag: + Serialize(byteArrayTag); + break; + + case INbtArray intArrayTag: + Serialize(intArrayTag); + break; + + case INbtArray longArrayTag: + Serialize(longArrayTag); + break; + } + } + + public void Serialize(INbtValue valueTag) + { + switch (valueTag) + { + case INbtValue tag: + Serialize(tag); + break; + + case INbtValue tag: + Serialize(tag); + break; + + case INbtValue tag: + Serialize(tag); + break; + + case INbtValue tag: + Serialize(tag); + break; + + case INbtValue tag: + Serialize(tag); + break; + + case INbtValue tag: + Serialize(tag); + break; + + case INbtValue tag: + Serialize(tag); + break; + } + } + + public void Serialize(INbtArray tag) => Serialize(tag, 'B', Serialize); + + public void Serialize(INbtArray tag) => Serialize(tag, 'I', Serialize); + + public void Serialize(INbtArray tag) => Serialize(tag, 'L', Serialize); + + public void Serialize(INbtValue tag) => Serialize(tag.Value); + + public void Serialize(INbtValue tag) => Serialize(tag.Value); + + public void Serialize(INbtValue tag) => Serialize(tag.Value); + + public void Serialize(INbtValue tag) => Serialize(tag.Value); + + public void Serialize(INbtValue tag) => Serialize(tag.Value); + + public void Serialize(INbtValue tag) => Serialize(tag.Value); + + public void Serialize(INbtValue tag) => Serialize(tag.Value); + + private void Serialize(INbtArray tag, char decorator, Action writeValue) where T : notnull + { + writer.Write('['); + writer.Write(decorator); + writer.Write(';'); + + EnterContext(false); + + if (tag.Value.Length > 0) + { + if (options.Style is not SerializationStyle.Compact) + { + writer.Write(' '); + } + + foreach (var e in tag) + { + WriteSeparator(); + + writeValue(e); + + context!.Length++; + } + } + + ExitContext(); + + writer.Write(']'); + } + + private void Serialize(sbyte value) + { + writer.Write(value.ToString(CultureInfo.InvariantCulture)); + writer.Write('b'); + } + + private void Serialize(short value) + { + writer.Write(value.ToString(CultureInfo.InvariantCulture)); + writer.Write('s'); + } + + private void Serialize(int value) + { + writer.Write(value.ToString(CultureInfo.InvariantCulture)); + } + + private void Serialize(long value) + { + writer.Write(value.ToString(CultureInfo.InvariantCulture)); + writer.Write('L'); + } + + private void Serialize(float value) + { + writer.Write(value.ToString(CultureInfo.InvariantCulture)); + + if (float.IsFinite(value)) + { + writer.Write('F'); + } + } + + private void Serialize(double value) + { + writer.Write(value.ToString(CultureInfo.InvariantCulture)); + + if (double.IsFinite(value)) + { + writer.Write('D'); + } + } + + private void Serialize(string value) + { + // Utils.Quote(writer, value, NbtUtils.DOUBLE_QUOTE_CHAR, NbtUtils.ESCAPE_CHAR); + writer.Write(NbtUtils.QuoteString(value, onlyIfNeeded: false)); + } + + private void EnterContext(bool newLine) + { + depth++; + context = new(context, newLine); + } + + private void ExitContext() + { + depth--; + + if (context!.NewLine && context!.Length > 0 && options.Style is SerializationStyle.Indented) + { + WriteNewLine(); + } + + context = context!.Parent; + } + + private void WriteSeparator() + { + if (context!.Length > 0) + { + writer.Write(','); + + if (options.Style is SerializationStyle.Spaced || !context.NewLine && options.Style is not SerializationStyle.Compact) + { + writer.Write(' '); + } + } + + if (context.NewLine && options.Style is SerializationStyle.Indented) + { + WriteNewLine(); + } + } + + private void WriteNewLine() + { + writer.WriteLine(); + + for (var i = 0; i < depth; i++) + { + writer.Write(options.Indent); + } + } + + #endregion + + #region Async + + public async ValueTask SerializeAsync(INbtTag tag, CancellationToken ct) + { + switch (tag) + { + case INbtArray arrayTag: + await SerializeAsync(arrayTag, ct); + break; + + case INbtValue valueTag: + await SerializeAsync(valueTag, ct); + break; + + case INbtList listTag: + await SerializeAsync(listTag, ct); + break; + + case INbtCompound compoundTag: + await SerializeAsync(compoundTag, ct); + break; + } + } + + public async ValueTask SerializeAsync(NamedTag namedTag, CancellationToken ct) + { + if (!string.IsNullOrEmpty(namedTag.Name)) + { + await WriteStringAsync(NbtUtils.QuoteString(namedTag.Name, onlyIfNeeded: !options.AlwaysQuoteTagNames), ct); + await WriteStringAsync(":", ct); + if (options.Style is not SerializationStyle.Compact) + { + await WriteStringAsync(" ", ct); + } + } + + await SerializeAsync(namedTag.Tag, ct); + } + + public async ValueTask SerializeAsync(INbtList tag, CancellationToken ct) + { + await WriteStringAsync("[", ct); + + await EnterContextAsync(true, ct); + + foreach (var entry in tag) + { + await WriteSeparatorAsync(ct); + + await SerializeAsync(entry, ct); + + context!.Length++; + } + + await ExitContextAsync(ct); + + await WriteStringAsync("]", ct); + } + + public async ValueTask SerializeAsync(INbtCompound tag, CancellationToken ct) + { + await WriteStringAsync("{", ct); + + await EnterContextAsync(true, ct); + + foreach (var entry in tag as IEnumerable) + { + await WriteSeparatorAsync(ct); + + await SerializeAsync(entry, ct); + + context!.Length++; + } + + await ExitContextAsync(ct); + + await WriteStringAsync("}", ct); + } + + public async ValueTask SerializeAsync(INbtArray tag, CancellationToken ct) + { + switch (tag) + { + case INbtArray byteArrayTag: + await SerializeAsync(byteArrayTag, ct); + break; + + case INbtArray intArrayTag: + await SerializeAsync(intArrayTag, ct); + break; + + case INbtArray longArrayTag: + await SerializeAsync(longArrayTag, ct); + break; + } + } + + public async ValueTask SerializeAsync(INbtValue valueTag, CancellationToken ct) + { + switch (valueTag) + { + case INbtValue tag: + await SerializeAsync(tag, ct); + break; + + case INbtValue tag: + await SerializeAsync(tag, ct); + break; + + case INbtValue tag: + await SerializeAsync(tag, ct); + break; + + case INbtValue tag: + await SerializeAsync(tag, ct); + break; + + case INbtValue tag: + await SerializeAsync(tag, ct); + break; + + case INbtValue tag: + await SerializeAsync(tag, ct); + break; + + case INbtValue tag: + await SerializeAsync(tag, ct); + break; + } + } + + public async ValueTask SerializeAsync(INbtArray tag, CancellationToken ct) => await SerializeAsync(tag, "B", ct, SerializeAsync); + + public async ValueTask SerializeAsync(INbtArray tag, CancellationToken ct) => await SerializeAsync(tag, "I", ct, SerializeAsync); + + public async ValueTask SerializeAsync(INbtArray tag, CancellationToken ct) => await SerializeAsync(tag, "L", ct, SerializeAsync); + + public async ValueTask SerializeAsync(INbtValue tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct); + + public async ValueTask SerializeAsync(INbtValue tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct); + + public async ValueTask SerializeAsync(INbtValue tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct); + + public async ValueTask SerializeAsync(INbtValue tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct); + + public async ValueTask SerializeAsync(INbtValue tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct); + + public async ValueTask SerializeAsync(INbtValue tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct); + + public async ValueTask SerializeAsync(INbtValue tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct); + + private async ValueTask SerializeAsync(INbtArray tag, string decorator, CancellationToken ct, Func writeValue) where T : notnull + { + await WriteStringAsync("[", ct); + await WriteStringAsync(decorator, ct); + await WriteStringAsync(";", ct); + + await EnterContextAsync(false, ct); + + if (tag.Value.Length > 0) + { + if (options.Style is not SerializationStyle.Compact) + { + await WriteStringAsync(" ", ct); + } + + foreach (var e in tag) + { + await WriteSeparatorAsync(ct); + + await writeValue(e, ct); + + context!.Length++; + } + } + + await ExitContextAsync(ct); + + await WriteStringAsync("]", ct); + } + + private async ValueTask SerializeAsync(sbyte value, CancellationToken ct) + { + await WriteStringAsync(value.ToString(CultureInfo.InvariantCulture), ct); + await WriteStringAsync("b", ct); + } + + private async ValueTask SerializeAsync(short value, CancellationToken ct) + { + await WriteStringAsync(value.ToString(CultureInfo.InvariantCulture), ct); + await WriteStringAsync("s", ct); + } + + private async ValueTask SerializeAsync(int value, CancellationToken ct) + { + await WriteStringAsync(value.ToString(CultureInfo.InvariantCulture), ct); + } + + private async ValueTask SerializeAsync(long value, CancellationToken ct) + { + await WriteStringAsync(value.ToString(CultureInfo.InvariantCulture), ct); + await WriteStringAsync("L", ct); + } + + private async ValueTask SerializeAsync(float value, CancellationToken ct) + { + await WriteStringAsync(value.ToString(CultureInfo.InvariantCulture), ct); + + if (float.IsFinite(value)) + { + await WriteStringAsync("F", ct); + } + } + + private async ValueTask SerializeAsync(double value, CancellationToken ct) + { + await WriteStringAsync(value.ToString(CultureInfo.InvariantCulture), ct); + + if (double.IsFinite(value)) + { + await WriteStringAsync("D", ct); + } + } + + private async ValueTask SerializeAsync(string value, CancellationToken ct) + { + // Utils.Quote(writer, value, NbtUtils.DOUBLE_QUOTE_CHAR, NbtUtils.ESCAPE_CHAR); + await WriteStringAsync(NbtUtils.QuoteString(value, onlyIfNeeded: false), ct); + } + + private async ValueTask WriteStringAsync(string s, CancellationToken ct) + { + await writer.WriteAsync(s.AsMemory(), ct); + } + + private ValueTask EnterContextAsync(bool newLine, CancellationToken ct) + { + depth++; + context = new(context, newLine); + + return ValueTask.CompletedTask; + } + + private async ValueTask ExitContextAsync(CancellationToken ct) + { + depth--; + + if (context!.NewLine && context!.Length > 0 && options.Style is SerializationStyle.Indented) + { + await WriteNewLineAsync(ct); + } + + context = context!.Parent; + } + + private async ValueTask WriteSeparatorAsync(CancellationToken ct) + { + if (context!.Length > 0) + { + await WriteStringAsync(",", ct); + + if (options.Style is SerializationStyle.Spaced || !context.NewLine && options.Style is not SerializationStyle.Compact) + { + await WriteStringAsync(" ", ct); + } + } + + if (context.NewLine && options.Style is SerializationStyle.Indented) + { + await WriteNewLineAsync(ct); + } + } + + private async ValueTask WriteNewLineAsync(CancellationToken ct) + { + await WriteStringAsync(writer.NewLine, ct); + + for (var i = 0; i < depth; i++) + { + await WriteStringAsync(options.Indent, ct); + } + } + + #endregion + + private class Context(Context? parent, bool newLine) + { + public Context? Parent => parent; + public bool NewLine => newLine; + + public int Length { get; set; } = 0; + } + } + + #endregion +} diff --git a/Nbt/Type/NbtArrayType.cs b/Nbt/Type/NbtArrayType.cs old mode 100755 new mode 100644 index a2cdb26..7dc73bf --- a/Nbt/Type/NbtArrayType.cs +++ b/Nbt/Type/NbtArrayType.cs @@ -1,43 +1,76 @@ -using Nbt.Serialization; -using Nbt.Tag; - -namespace Nbt.Type; - -internal abstract class NbtArrayType(NbtValueType elementType) : NbtType> where T : notnull -{ - private readonly NbtValueType elementType = elementType; - - protected virtual T ReadValue(INbtReader reader) => elementType.ReadValue(reader); - public abstract INbtArray CreateTag(T[] values); - public virtual INbtArray CreateEmptyTag() => CreateTag([]); - protected virtual void WriteValue(INbtWriter writer, T value) => elementType.WriteValue(writer, value); - - public override INbtArray 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 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(NbtValueType elementType) : NbtType> where T : notnull +{ + private readonly NbtValueType elementType = elementType; + + public abstract INbtArray CreateTag(T[] values); + public virtual INbtArray CreateEmptyTag() => CreateTag([]); + + protected virtual T ReadValue(INbtReader reader) => elementType.ReadValue(reader); + protected virtual ValueTask 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 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> 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 tag) + { + writer.WriteInt(tag.Value.Length); + + foreach (var e in tag) + { + WriteValue(writer, e); + } + } + + public override async ValueTask WriteAsync(INbtAsyncWriter writer, INbtArray tag, CancellationToken ct = default) + { + await writer.WriteIntAsync(tag.Value.Length, ct); + + foreach (var e in tag) + { + await WriteValueAsync(writer, e, ct); + } + } +} diff --git a/Nbt/Type/NbtCompoundType.cs b/Nbt/Type/NbtCompoundType.cs old mode 100755 new mode 100644 index 5ee6878..613b4f1 --- a/Nbt/Type/NbtCompoundType.cs +++ b/Nbt/Type/NbtCompoundType.cs @@ -1,45 +1,78 @@ -using Nbt.Serialization; -using Nbt.Tag; - -namespace Nbt.Type; - -internal class NbtCompoundType : NbtType -{ - 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)tag) - { - writer.WriteNamedTag(entry); - } - - writer.WriteTag(NbtEnd.Value); - } -} +using Nbt.Serialization; +using Nbt.Tag; + +namespace Nbt.Type; + +internal class NbtCompoundType : NbtType +{ + 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 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)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)tag) + { + await writer.WriteNamedTagAsync(entry, ct); + } + + await writer.WriteTagAsync(NbtEnd.Value, ct); + } +} diff --git a/Nbt/Type/NbtEndType.cs b/Nbt/Type/NbtEndType.cs old mode 100755 new mode 100644 index 5f638fa..9df778e --- a/Nbt/Type/NbtEndType.cs +++ b/Nbt/Type/NbtEndType.cs @@ -1,17 +1,21 @@ -using Nbt.Serialization; -using Nbt.Tag; - -namespace Nbt.Type; - -internal class NbtEndType : NbtType -{ - 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 +{ + 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 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; +} diff --git a/Nbt/Type/NbtListType.cs b/Nbt/Type/NbtListType.cs old mode 100755 new mode 100644 index 52b84aa..9306365 --- a/Nbt/Type/NbtListType.cs +++ b/Nbt/Type/NbtListType.cs @@ -1,38 +1,64 @@ -using Nbt.Serialization; -using Nbt.Tag; - -namespace Nbt.Type; - -internal class NbtListType : NbtType -{ - 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 +{ + 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 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); + } + } +} diff --git a/Nbt/Type/NbtType.cs b/Nbt/Type/NbtType.cs old mode 100755 new mode 100644 index d141425..352251c --- a/Nbt/Type/NbtType.cs +++ b/Nbt/Type/NbtType.cs @@ -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 : INbtType where T : INbtTag -{ - new T Read(INbtReader reader); - - void Write(INbtWriter writer, T tag); -} - -internal abstract class NbtType : INbtType 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 ReadAsync(INbtAsyncReader reader, CancellationToken ct = default); + + void Write(INbtWriter writer, INbtTag tag); + ValueTask WriteAsync(INbtAsyncWriter writer, INbtTag tag, CancellationToken ct = default); +} + +internal interface INbtType : INbtType where T : INbtTag +{ + new T Read(INbtReader reader); + new ValueTask 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 : INbtType where T : INbtTag +{ + public abstract NbtTagType Type { get; } + + public abstract T Read(INbtReader reader); + public abstract ValueTask 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 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); } \ No newline at end of file diff --git a/Nbt/Type/NbtValueType.cs b/Nbt/Type/NbtValueType.cs old mode 100755 new mode 100644 index 0d43bf9..b77fcf0 --- a/Nbt/Type/NbtValueType.cs +++ b/Nbt/Type/NbtValueType.cs @@ -1,15 +1,21 @@ -using Nbt.Serialization; -using Nbt.Tag; - -namespace Nbt.Type; - -internal abstract class NbtValueType : NbtType> where T : notnull -{ - protected internal abstract T ReadValue(INbtReader reader); - public abstract INbtValue CreateTag(T value); - protected internal abstract void WriteValue(INbtWriter writer, T value); - - public override INbtValue Read(INbtReader reader) => CreateTag(ReadValue(reader)); - - public override void Write(INbtWriter writer, INbtValue tag) => WriteValue(writer, tag.Value); -} +using Nbt.Serialization; +using Nbt.Tag; + +namespace Nbt.Type; + +internal abstract class NbtValueType : NbtType> where T : notnull +{ + public abstract INbtValue CreateTag(T value); + + protected internal abstract T ReadValue(INbtReader reader); + protected internal abstract ValueTask 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 Read(INbtReader reader) => CreateTag(ReadValue(reader)); + public override async ValueTask> ReadAsync(INbtAsyncReader reader, CancellationToken ct = default) => CreateTag(await ReadValueAsync(reader, ct)); + + public override void Write(INbtWriter writer, INbtValue tag) => WriteValue(writer, tag.Value); + public override ValueTask WriteAsync(INbtAsyncWriter writer, INbtValue tag, CancellationToken ct = default) => WriteValueAsync(writer, tag.Value, ct); +} diff --git a/Nbt/Type/Value/NbtByteType.cs b/Nbt/Type/Value/NbtByteType.cs old mode 100755 new mode 100644 index 6f530c5..f828172 --- a/Nbt/Type/Value/NbtByteType.cs +++ b/Nbt/Type/Value/NbtByteType.cs @@ -1,19 +1,21 @@ -using Nbt.Serialization; -using Nbt.Tag; - -namespace Nbt.Type; - -internal class NbtByteType : NbtValueType -{ - 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 +{ + 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 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); +} diff --git a/Nbt/Type/Value/NbtDoubleType.cs b/Nbt/Type/Value/NbtDoubleType.cs old mode 100755 new mode 100644 index b58cbfc..dbbbefa --- a/Nbt/Type/Value/NbtDoubleType.cs +++ b/Nbt/Type/Value/NbtDoubleType.cs @@ -1,19 +1,21 @@ -using Nbt.Serialization; -using Nbt.Tag; - -namespace Nbt.Type; - -internal class NbtDoubleType : NbtValueType -{ - 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 +{ + 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 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); +} diff --git a/Nbt/Type/Value/NbtFloatType.cs b/Nbt/Type/Value/NbtFloatType.cs old mode 100755 new mode 100644 index a90647d..da3e81e --- a/Nbt/Type/Value/NbtFloatType.cs +++ b/Nbt/Type/Value/NbtFloatType.cs @@ -1,19 +1,21 @@ -using Nbt.Serialization; -using Nbt.Tag; - -namespace Nbt.Type; - -internal class NbtFloatType : NbtValueType -{ - 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 +{ + 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 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); +} diff --git a/Nbt/Type/Value/NbtIntType.cs b/Nbt/Type/Value/NbtIntType.cs old mode 100755 new mode 100644 index 2f985c3..06da269 --- a/Nbt/Type/Value/NbtIntType.cs +++ b/Nbt/Type/Value/NbtIntType.cs @@ -1,19 +1,21 @@ -using Nbt.Serialization; -using Nbt.Tag; - -namespace Nbt.Type; - -internal class NbtIntType : NbtValueType -{ - 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 +{ + 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 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); +} diff --git a/Nbt/Type/Value/NbtLongType.cs b/Nbt/Type/Value/NbtLongType.cs old mode 100755 new mode 100644 index ea9515c..bda4df1 --- a/Nbt/Type/Value/NbtLongType.cs +++ b/Nbt/Type/Value/NbtLongType.cs @@ -1,19 +1,21 @@ -using Nbt.Serialization; -using Nbt.Tag; - -namespace Nbt.Type; - -internal class NbtLongType : NbtValueType -{ - 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 +{ + 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 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); +} diff --git a/Nbt/Type/Value/NbtShortType.cs b/Nbt/Type/Value/NbtShortType.cs old mode 100755 new mode 100644 index ebd5bb4..c017812 --- a/Nbt/Type/Value/NbtShortType.cs +++ b/Nbt/Type/Value/NbtShortType.cs @@ -1,19 +1,21 @@ -using Nbt.Serialization; -using Nbt.Tag; - -namespace Nbt.Type; - -internal class NbtShortType : NbtValueType -{ - 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 +{ + 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 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); +} diff --git a/Nbt/Type/Value/NbtStringType.cs b/Nbt/Type/Value/NbtStringType.cs old mode 100755 new mode 100644 index 18409cb..033c987 --- a/Nbt/Type/Value/NbtStringType.cs +++ b/Nbt/Type/Value/NbtStringType.cs @@ -1,19 +1,21 @@ -using Nbt.Serialization; -using Nbt.Tag; - -namespace Nbt.Type; - -internal class NbtStringType : NbtValueType -{ - 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 +{ + 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 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); +}