1
0
Files

754 lines
39 KiB
C#

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<sbyte> tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag));
public static string Serialize(INbtArray<int> tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag));
public static string Serialize(INbtArray<long> tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag));
public static string Serialize(INbtValue<sbyte> tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag));
public static string Serialize(INbtValue<short> tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag));
public static string Serialize(INbtValue<int> tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag));
public static string Serialize(INbtValue<long> tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag));
public static string Serialize(INbtValue<float> tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag));
public static string Serialize(INbtValue<double> tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag));
public static string Serialize(INbtValue<string> 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<sbyte> tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag));
public static void Serialize(TextWriter writer, INbtArray<int> tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag));
public static void Serialize(TextWriter writer, INbtArray<long> tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag));
public static void Serialize(TextWriter writer, INbtValue<sbyte> tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag));
public static void Serialize(TextWriter writer, INbtValue<short> tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag));
public static void Serialize(TextWriter writer, INbtValue<int> tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag));
public static void Serialize(TextWriter writer, INbtValue<long> tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag));
public static void Serialize(TextWriter writer, INbtValue<float> tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag));
public static void Serialize(TextWriter writer, INbtValue<double> tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag));
public static void Serialize(TextWriter writer, INbtValue<string> 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<sbyte> tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag));
public static void Serialize(Stream stream, INbtArray<int> tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag));
public static void Serialize(Stream stream, INbtArray<long> tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag));
public static void Serialize(Stream stream, INbtValue<sbyte> tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag));
public static void Serialize(Stream stream, INbtValue<short> tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag));
public static void Serialize(Stream stream, INbtValue<int> tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag));
public static void Serialize(Stream stream, INbtValue<long> tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag));
public static void Serialize(Stream stream, INbtValue<float> tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag));
public static void Serialize(Stream stream, INbtValue<double> tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag));
public static void Serialize(Stream stream, INbtValue<string> tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag));
private static void Serialize(TextWriter writer, SerializerOptions? options, Action<Serializer> serialize)
{
var serializer = new Serializer(writer, options);
serialize(serializer);
}
private static void Serialize(Stream stream, SerializerOptions? options, Action<Serializer> serialize)
{
using var writer = new StreamWriter(stream, leaveOpen: true);
Serialize(writer, options, serialize);
}
private static string Serialize(SerializerOptions? options, Action<Serializer> serialize)
{
using var writer = new StringWriter();
Serialize(writer, options, serialize);
return writer.ToString();
}
#endregion
#region Async
public static async ValueTask<string> SerializeAsync(INbtTag tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
public static async ValueTask<string> SerializeAsync(NamedTag tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
public static async ValueTask<string> SerializeAsync(INbtList tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
public static async ValueTask<string> SerializeAsync(INbtCompound tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
public static async ValueTask<string> SerializeAsync(INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
public static async ValueTask<string> SerializeAsync(INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
public static async ValueTask<string> SerializeAsync(INbtArray<sbyte> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
public static async ValueTask<string> SerializeAsync(INbtArray<int> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
public static async ValueTask<string> SerializeAsync(INbtArray<long> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
public static async ValueTask<string> SerializeAsync(INbtValue<sbyte> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
public static async ValueTask<string> SerializeAsync(INbtValue<short> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
public static async ValueTask<string> SerializeAsync(INbtValue<int> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
public static async ValueTask<string> SerializeAsync(INbtValue<long> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
public static async ValueTask<string> SerializeAsync(INbtValue<float> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
public static async ValueTask<string> SerializeAsync(INbtValue<double> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
public static async ValueTask<string> SerializeAsync(INbtValue<string> 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<sbyte> 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<int> 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<long> 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<sbyte> 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<short> 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<int> 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<long> 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<float> 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<double> 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<string> 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<sbyte> 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<int> 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<long> 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<sbyte> 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<short> 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<int> 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<long> 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<float> 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<double> 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<string> 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<Serializer, CancellationToken, ValueTask> serialize)
{
var serializer = new Serializer(writer, options);
await serialize(serializer, ct);
}
private static async ValueTask SerializeAsync(Stream stream, SerializerOptions? options, CancellationToken ct, Func<Serializer, CancellationToken, ValueTask> serialize)
{
using var writer = new StreamWriter(stream, leaveOpen: true);
await SerializeAsync(writer, options, ct, serialize);
}
private static async ValueTask<string> SerializeAsync(SerializerOptions? options, CancellationToken ct, Func<Serializer, CancellationToken, ValueTask> 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<NamedTag>)
{
WriteSeparator();
Serialize(entry);
context!.Length++;
}
ExitContext();
writer.Write('}');
}
public void Serialize(INbtArray tag)
{
switch (tag)
{
case INbtArray<sbyte> byteArrayTag:
Serialize(byteArrayTag);
break;
case INbtArray<int> intArrayTag:
Serialize(intArrayTag);
break;
case INbtArray<long> longArrayTag:
Serialize(longArrayTag);
break;
}
}
public void Serialize(INbtValue valueTag)
{
switch (valueTag)
{
case INbtValue<sbyte> tag:
Serialize(tag);
break;
case INbtValue<short> tag:
Serialize(tag);
break;
case INbtValue<int> tag:
Serialize(tag);
break;
case INbtValue<long> tag:
Serialize(tag);
break;
case INbtValue<float> tag:
Serialize(tag);
break;
case INbtValue<double> tag:
Serialize(tag);
break;
case INbtValue<string> tag:
Serialize(tag);
break;
}
}
public void Serialize(INbtArray<sbyte> tag) => Serialize(tag, 'B', Serialize);
public void Serialize(INbtArray<int> tag) => Serialize(tag, 'I', Serialize);
public void Serialize(INbtArray<long> tag) => Serialize(tag, 'L', Serialize);
public void Serialize(INbtValue<sbyte> tag) => Serialize(tag.Value);
public void Serialize(INbtValue<short> tag) => Serialize(tag.Value);
public void Serialize(INbtValue<int> tag) => Serialize(tag.Value);
public void Serialize(INbtValue<long> tag) => Serialize(tag.Value);
public void Serialize(INbtValue<float> tag) => Serialize(tag.Value);
public void Serialize(INbtValue<double> tag) => Serialize(tag.Value);
public void Serialize(INbtValue<string> tag) => Serialize(tag.Value);
private void Serialize<T>(INbtArray<T> tag, char decorator, Action<T> 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<NamedTag>)
{
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<sbyte> byteArrayTag:
await SerializeAsync(byteArrayTag, ct);
break;
case INbtArray<int> intArrayTag:
await SerializeAsync(intArrayTag, ct);
break;
case INbtArray<long> longArrayTag:
await SerializeAsync(longArrayTag, ct);
break;
}
}
public async ValueTask SerializeAsync(INbtValue valueTag, CancellationToken ct)
{
switch (valueTag)
{
case INbtValue<sbyte> tag:
await SerializeAsync(tag, ct);
break;
case INbtValue<short> tag:
await SerializeAsync(tag, ct);
break;
case INbtValue<int> tag:
await SerializeAsync(tag, ct);
break;
case INbtValue<long> tag:
await SerializeAsync(tag, ct);
break;
case INbtValue<float> tag:
await SerializeAsync(tag, ct);
break;
case INbtValue<double> tag:
await SerializeAsync(tag, ct);
break;
case INbtValue<string> tag:
await SerializeAsync(tag, ct);
break;
}
}
public async ValueTask SerializeAsync(INbtArray<sbyte> tag, CancellationToken ct) => await SerializeAsync(tag, "B", ct, SerializeAsync);
public async ValueTask SerializeAsync(INbtArray<int> tag, CancellationToken ct) => await SerializeAsync(tag, "I", ct, SerializeAsync);
public async ValueTask SerializeAsync(INbtArray<long> tag, CancellationToken ct) => await SerializeAsync(tag, "L", ct, SerializeAsync);
public async ValueTask SerializeAsync(INbtValue<sbyte> tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct);
public async ValueTask SerializeAsync(INbtValue<short> tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct);
public async ValueTask SerializeAsync(INbtValue<int> tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct);
public async ValueTask SerializeAsync(INbtValue<long> tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct);
public async ValueTask SerializeAsync(INbtValue<float> tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct);
public async ValueTask SerializeAsync(INbtValue<double> tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct);
public async ValueTask SerializeAsync(INbtValue<string> tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct);
private async ValueTask SerializeAsync<T>(INbtArray<T> tag, string decorator, CancellationToken ct, Func<T, CancellationToken, ValueTask> 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
}