From c3d5b45b65d58084e5511b1089ce9a2d9557ccab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Boh=C3=A1=C4=8Dek?= Date: Sat, 1 Jan 2022 22:59:52 +0100 Subject: [PATCH] feat: use ReadOnlySpan for deserialization instead of strings --- .../ConverterDeserializationGenerator.cs | 2 +- .../Extensions/ParameterInfoExtensions.cs | 10 ++ .../BasicInlineConverterGenerator.cs | 2 +- .../BoolInlineConverterGenerator.cs | 2 +- .../EnumInlineConverterGenerator.cs | 2 +- .../FallbackInlineConverterGenerator.cs | 2 +- .../StringInlineConverterGenerator.cs | 2 +- .../PacketConverterGenerator.cs | 6 +- .../SourceGenerator.cs | 5 + .../Converters/BaseStringConverter.cs | 8 +- .../Converters/Basic/BasicTypeConverter.cs | 10 +- .../Converters/Basic/BoolStringConverter.cs | 11 +- .../Converters/Basic/ByteStringConverter.cs | 5 +- .../Converters/Basic/CharStringConverter.cs | 5 +- .../Converters/Basic/IntStringConverter.cs | 5 +- .../Converters/Basic/LongStringConverter.cs | 5 +- .../Converters/Basic/ShortStringConverter.cs | 5 +- .../Converters/Basic/StringTypeConverter.cs | 5 +- .../Converters/Basic/UIntStringConverter.cs | 5 +- .../Converters/Basic/ULongStringConverter.cs | 5 +- .../Converters/Basic/UShortStringConverter.cs | 5 +- .../Converters/Common/NameStringConverter.cs | 8 +- .../Converters/IStringConverter.cs | 4 +- .../Converters/IStringSerializer.cs | 4 +- .../Packets/UpgradeRareSubPacketConverter.cs | 16 +- .../Converters/Special/EnumTypeConverter.cs | 0 .../Special/ISpecialTypeConverter.cs | 0 .../Converters/Special/ListTypeConverter.cs | 0 .../Special/NullableTypeConverter.cs | 0 .../Converters/TypeConverterRepository.cs | 0 .../Errors/CouldNotConvertError.cs | 1 + .../NosSmooth.Packets.csproj | 2 +- Core/NosSmooth.Packets/PacketSerializer.cs | 6 +- .../PacketStringEnumerator.cs | 138 ++++++------------ Core/NosSmooth.Packets/PacketToken.cs | 56 ++++++- .../PacketStringBuilderTests.cs | 1 - .../PacketStringEnumeratorTests.cs | 129 ++++++++-------- 37 files changed, 248 insertions(+), 224 deletions(-) create mode 100644 Core/NosSmooth.Packets/Converters/Special/EnumTypeConverter.cs create mode 100644 Core/NosSmooth.Packets/Converters/Special/ISpecialTypeConverter.cs create mode 100644 Core/NosSmooth.Packets/Converters/Special/ListTypeConverter.cs create mode 100644 Core/NosSmooth.Packets/Converters/Special/NullableTypeConverter.cs create mode 100644 Core/NosSmooth.Packets/Converters/TypeConverterRepository.cs diff --git a/Core/NosSmooth.PacketSerializersGenerator/ConverterDeserializationGenerator.cs b/Core/NosSmooth.PacketSerializersGenerator/ConverterDeserializationGenerator.cs index 67baa90..0d158a8 100644 --- a/Core/NosSmooth.PacketSerializersGenerator/ConverterDeserializationGenerator.cs +++ b/Core/NosSmooth.PacketSerializersGenerator/ConverterDeserializationGenerator.cs @@ -94,7 +94,7 @@ public class ConverterDeserializationGenerator _textWriter.WriteLine($@"while ({_stringEnumeratorVariable}.IsOnLastToken() == false)"); _textWriter.WriteLine("{"); _textWriter.Indent++; - _textWriter.WriteLine($"{_stringEnumeratorVariable}.GetNextToken();"); + _textWriter.WriteLine($"{_stringEnumeratorVariable}.GetNextToken(out _);"); _textWriter.Indent--; _textWriter.WriteLine("}"); } diff --git a/Core/NosSmooth.PacketSerializersGenerator/Extensions/ParameterInfoExtensions.cs b/Core/NosSmooth.PacketSerializersGenerator/Extensions/ParameterInfoExtensions.cs index 43e04a9..9b887e6 100644 --- a/Core/NosSmooth.PacketSerializersGenerator/Extensions/ParameterInfoExtensions.cs +++ b/Core/NosSmooth.PacketSerializersGenerator/Extensions/ParameterInfoExtensions.cs @@ -37,6 +37,16 @@ public static class ParameterInfoExtensions return $"{parameterInfo.Name}Result"; } + /// + /// Gets the name of the token variable. + /// + /// The parameter. + /// The name of the token variable. + public static string GetTokenVariableName(this ParameterInfo parameterInfo) + { + return $"{parameterInfo.Name}Token"; + } + /// /// Gets the name of the error variable. /// diff --git a/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/BasicInlineConverterGenerator.cs b/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/BasicInlineConverterGenerator.cs index 2ad5e7c..232c90b 100644 --- a/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/BasicInlineConverterGenerator.cs +++ b/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/BasicInlineConverterGenerator.cs @@ -91,4 +91,4 @@ public static Result<{type}?> ParseBasic{type}(IStringConverter typeConverter, P "); } } -} \ No newline at end of file +} diff --git a/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/BoolInlineConverterGenerator.cs b/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/BoolInlineConverterGenerator.cs index e73f654..07ad39a 100644 --- a/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/BoolInlineConverterGenerator.cs +++ b/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/BoolInlineConverterGenerator.cs @@ -70,4 +70,4 @@ public static Result ParseBool(PacketStringEnumerator stringEnumerator) }} "); } -} \ No newline at end of file +} diff --git a/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/EnumInlineConverterGenerator.cs b/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/EnumInlineConverterGenerator.cs index f8e9930..0e15f3d 100644 --- a/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/EnumInlineConverterGenerator.cs +++ b/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/EnumInlineConverterGenerator.cs @@ -105,4 +105,4 @@ public static Result<{type}?> ParseEnum{type.ToString().Replace('.', '_')}(IStri ); } } -} \ No newline at end of file +} diff --git a/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/FallbackInlineConverterGenerator.cs b/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/FallbackInlineConverterGenerator.cs index 69fd6cd..9825c3e 100644 --- a/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/FallbackInlineConverterGenerator.cs +++ b/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/FallbackInlineConverterGenerator.cs @@ -58,4 +58,4 @@ public class FallbackInlineConverterGenerator : IInlineConverterGenerator { // ignore } -} \ No newline at end of file +} diff --git a/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/StringInlineConverterGenerator.cs b/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/StringInlineConverterGenerator.cs index 546c96d..a71a93b 100644 --- a/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/StringInlineConverterGenerator.cs +++ b/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/StringInlineConverterGenerator.cs @@ -53,4 +53,4 @@ public static Result ParseString(PacketStringEnumerator stringEnumerato " ); } -} \ No newline at end of file +} diff --git a/Core/NosSmooth.PacketSerializersGenerator/PacketConverterGenerator.cs b/Core/NosSmooth.PacketSerializersGenerator/PacketConverterGenerator.cs index c40c270..028a9c3 100644 --- a/Core/NosSmooth.PacketSerializersGenerator/PacketConverterGenerator.cs +++ b/Core/NosSmooth.PacketSerializersGenerator/PacketConverterGenerator.cs @@ -95,7 +95,7 @@ public override Result Serialize({_packetInfo.Name}? obj, PacketStringBuilder bu }} /// -public override Result<{_packetInfo.Name}?> Deserialize(PacketStringEnumerator stringEnumerator) +public override Result<{_packetInfo.Name}?> Deserialize(ref PacketStringEnumerator stringEnumerator) {{ var typeConverter = this; " @@ -176,7 +176,7 @@ public override Result<{_packetInfo.Name}?> Deserialize(PacketStringEnumerator s textWriter.WriteLine("IResultError? skipError;"); skipped = true; } - textWriter.WriteLine($@"skipResult = stringEnumerator.GetNextToken();"); + textWriter.WriteLine($@"skipResult = stringEnumerator.GetNextToken(out _);"); textWriter.WriteLine ("skipError = CheckDeserializationResult(result, \"None\", stringEnumerator, false);"); textWriter.WriteMultiline @@ -246,4 +246,4 @@ public override Result<{_packetInfo.Name}?> Deserialize(PacketStringEnumerator s return null; } -} \ No newline at end of file +} diff --git a/Core/NosSmooth.PacketSerializersGenerator/SourceGenerator.cs b/Core/NosSmooth.PacketSerializersGenerator/SourceGenerator.cs index b48933f..b220eff 100644 --- a/Core/NosSmooth.PacketSerializersGenerator/SourceGenerator.cs +++ b/Core/NosSmooth.PacketSerializersGenerator/SourceGenerator.cs @@ -130,6 +130,11 @@ public class SourceGenerator : ISourceGenerator $"{packetRecord.GetPrefix()}.{packetRecord.Identifier.NormalizeWhitespace().ToFullString()}Converter.g.cs", stringWriter.GetStringBuilder().ToString() ); + File.WriteAllText + ( + $"/tmp/{packetRecord.GetPrefix()}.{packetRecord.Identifier.NormalizeWhitespace().ToFullString()}Converter.g.cs", + stringWriter.GetStringBuilder().ToString() + ); } } diff --git a/Core/NosSmooth.Packets/Converters/BaseStringConverter.cs b/Core/NosSmooth.Packets/Converters/BaseStringConverter.cs index e020e74..3d31147 100644 --- a/Core/NosSmooth.Packets/Converters/BaseStringConverter.cs +++ b/Core/NosSmooth.Packets/Converters/BaseStringConverter.cs @@ -19,12 +19,12 @@ public abstract class BaseStringConverter : IStringConverter - public abstract Result Deserialize(PacketStringEnumerator stringEnumerator); + public abstract Result Deserialize(ref PacketStringEnumerator stringEnumerator); /// - Result IStringConverter.Deserialize(PacketStringEnumerator stringEnumerator) + Result IStringConverter.Deserialize(ref PacketStringEnumerator stringEnumerator) { - var result = Deserialize(stringEnumerator); + var result = Deserialize(ref stringEnumerator); if (!result.IsSuccess) { return Result.FromError(result); @@ -43,4 +43,4 @@ public abstract class BaseStringConverter : IStringConverter : BaseStringConverter - public override Result Deserialize(PacketStringEnumerator stringEnumerator) + public override Result Deserialize(ref PacketStringEnumerator stringEnumerator) { - var nextTokenResult = stringEnumerator.GetNextToken(); + var nextTokenResult = stringEnumerator.GetNextToken(out var packetToken); if (!nextTokenResult.IsSuccess) { return Result.FromError(nextTokenResult); } - if (nextTokenResult.Entity.Token == "-") + if (packetToken.Token[0] == '-' && packetToken.Token.Length == 1) { return Result.FromSuccess(default); } - return Deserialize(nextTokenResult.Entity.Token); + return Deserialize(packetToken.Token); } /// @@ -44,5 +44,5 @@ public abstract class BasicTypeConverter : BaseStringConverter /// The value to deserialize. /// The deserialized value or an error. - protected abstract Result Deserialize(string value); + protected abstract Result Deserialize(ReadOnlySpan value); } \ No newline at end of file diff --git a/Core/NosSmooth.Packets/Converters/Basic/BoolStringConverter.cs b/Core/NosSmooth.Packets/Converters/Basic/BoolStringConverter.cs index a1ad76a..777a3e0 100644 --- a/Core/NosSmooth.Packets/Converters/Basic/BoolStringConverter.cs +++ b/Core/NosSmooth.Packets/Converters/Basic/BoolStringConverter.cs @@ -22,19 +22,14 @@ public class BoolStringConverter : BaseStringConverter } /// - public override Result Deserialize(PacketStringEnumerator stringEnumerator) + public override Result Deserialize(ref PacketStringEnumerator stringEnumerator) { - var nextTokenResult = stringEnumerator.GetNextToken(); + var nextTokenResult = stringEnumerator.GetNextToken(out var packetToken); if (!nextTokenResult.IsSuccess) { return Result.FromError(nextTokenResult); } - if (nextTokenResult.Entity.Token == "-") - { - return Result.FromSuccess(default); - } - - return nextTokenResult.Entity.Token == "1" ? true : false; + return packetToken.Token[0] == '1' ? true : false; } } \ No newline at end of file diff --git a/Core/NosSmooth.Packets/Converters/Basic/ByteStringConverter.cs b/Core/NosSmooth.Packets/Converters/Basic/ByteStringConverter.cs index 2a9cab5..206d5ae 100644 --- a/Core/NosSmooth.Packets/Converters/Basic/ByteStringConverter.cs +++ b/Core/NosSmooth.Packets/Converters/Basic/ByteStringConverter.cs @@ -4,6 +4,7 @@ // Copyright (c) František Boháček. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System; using NosSmooth.Packets.Errors; using Remora.Results; @@ -15,11 +16,11 @@ namespace NosSmooth.Packets.Converters.Basic; public class ByteStringConverter : BasicTypeConverter { /// - protected override Result Deserialize(string value) + protected override Result Deserialize(ReadOnlySpan value) { if (!byte.TryParse(value, out var parsed)) { - return new CouldNotConvertError(this, value, "Could not parse as an byte."); + return new CouldNotConvertError(this, value.ToString(), "Could not parse as an byte."); } return parsed; diff --git a/Core/NosSmooth.Packets/Converters/Basic/CharStringConverter.cs b/Core/NosSmooth.Packets/Converters/Basic/CharStringConverter.cs index f0dd83f..b711f0e 100644 --- a/Core/NosSmooth.Packets/Converters/Basic/CharStringConverter.cs +++ b/Core/NosSmooth.Packets/Converters/Basic/CharStringConverter.cs @@ -4,6 +4,7 @@ // Copyright (c) František Boháček. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System; using NosSmooth.Packets.Errors; using Remora.Results; @@ -15,11 +16,11 @@ namespace NosSmooth.Packets.Converters.Basic; public class CharStringConverter : BasicTypeConverter { /// - protected override Result Deserialize(string value) + protected override Result Deserialize(ReadOnlySpan value) { if (value.Length != 1) { - return new CouldNotConvertError(this, value, "The token is not one character long."); + return new CouldNotConvertError(this, value.ToString(), "The token is not one character long."); } return value[0]; diff --git a/Core/NosSmooth.Packets/Converters/Basic/IntStringConverter.cs b/Core/NosSmooth.Packets/Converters/Basic/IntStringConverter.cs index 4ced867..2882b5e 100644 --- a/Core/NosSmooth.Packets/Converters/Basic/IntStringConverter.cs +++ b/Core/NosSmooth.Packets/Converters/Basic/IntStringConverter.cs @@ -4,6 +4,7 @@ // Copyright (c) František Boháček. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System; using NosSmooth.Packets.Errors; using Remora.Results; @@ -15,11 +16,11 @@ namespace NosSmooth.Packets.Converters.Basic; public class IntStringConverter : BasicTypeConverter { /// - protected override Result Deserialize(string value) + protected override Result Deserialize(ReadOnlySpan value) { if (!int.TryParse(value, out var parsed)) { - return new CouldNotConvertError(this, value, "Could not parse as int."); + return new CouldNotConvertError(this, value.ToString(), "Could not parse as int."); } return parsed; diff --git a/Core/NosSmooth.Packets/Converters/Basic/LongStringConverter.cs b/Core/NosSmooth.Packets/Converters/Basic/LongStringConverter.cs index 521d613..dec4c35 100644 --- a/Core/NosSmooth.Packets/Converters/Basic/LongStringConverter.cs +++ b/Core/NosSmooth.Packets/Converters/Basic/LongStringConverter.cs @@ -4,6 +4,7 @@ // Copyright (c) František Boháček. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System; using NosSmooth.Packets.Errors; using Remora.Results; @@ -15,11 +16,11 @@ namespace NosSmooth.Packets.Converters.Basic; public class LongStringConverter : BasicTypeConverter { /// - protected override Result Deserialize(string value) + protected override Result Deserialize(ReadOnlySpan value) { if (!long.TryParse(value, out var parsed)) { - return new CouldNotConvertError(this, value, "Could not parse as a long."); + return new CouldNotConvertError(this, value.ToString(), "Could not parse as a long."); } return parsed; diff --git a/Core/NosSmooth.Packets/Converters/Basic/ShortStringConverter.cs b/Core/NosSmooth.Packets/Converters/Basic/ShortStringConverter.cs index aa9568c..9061d03 100644 --- a/Core/NosSmooth.Packets/Converters/Basic/ShortStringConverter.cs +++ b/Core/NosSmooth.Packets/Converters/Basic/ShortStringConverter.cs @@ -4,6 +4,7 @@ // Copyright (c) František Boháček. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System; using NosSmooth.Packets.Errors; using Remora.Results; @@ -15,11 +16,11 @@ namespace NosSmooth.Packets.Converters.Basic; public class ShortStringConverter : BasicTypeConverter { /// - protected override Result Deserialize(string value) + protected override Result Deserialize(ReadOnlySpan value) { if (!short.TryParse(value, out var parsed)) { - return new CouldNotConvertError(this, value, "Could not parse as short."); + return new CouldNotConvertError(this, value.ToString(), "Could not parse as short."); } return parsed; diff --git a/Core/NosSmooth.Packets/Converters/Basic/StringTypeConverter.cs b/Core/NosSmooth.Packets/Converters/Basic/StringTypeConverter.cs index 6852c14..a0a0a9f 100644 --- a/Core/NosSmooth.Packets/Converters/Basic/StringTypeConverter.cs +++ b/Core/NosSmooth.Packets/Converters/Basic/StringTypeConverter.cs @@ -4,6 +4,7 @@ // Copyright (c) František Boháček. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System; using Remora.Results; namespace NosSmooth.Packets.Converters.Basic; @@ -14,8 +15,8 @@ namespace NosSmooth.Packets.Converters.Basic; public class StringTypeConverter : BasicTypeConverter { /// - protected override Result Deserialize(string value) + protected override Result Deserialize(ReadOnlySpan value) { - return value; + return value.ToString(); } } \ No newline at end of file diff --git a/Core/NosSmooth.Packets/Converters/Basic/UIntStringConverter.cs b/Core/NosSmooth.Packets/Converters/Basic/UIntStringConverter.cs index 2344e15..bca2e3e 100644 --- a/Core/NosSmooth.Packets/Converters/Basic/UIntStringConverter.cs +++ b/Core/NosSmooth.Packets/Converters/Basic/UIntStringConverter.cs @@ -4,6 +4,7 @@ // Copyright (c) František Boháček. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System; using NosSmooth.Packets.Errors; using Remora.Results; @@ -15,11 +16,11 @@ namespace NosSmooth.Packets.Converters.Basic; public class UIntStringConverter : BasicTypeConverter { /// - protected override Result Deserialize(string value) + protected override Result Deserialize(ReadOnlySpan value) { if (!uint.TryParse(value, out var parsed)) { - return new CouldNotConvertError(this, value, "Could not parse as uint"); + return new CouldNotConvertError(this, value.ToString(), "Could not parse as uint"); } return parsed; diff --git a/Core/NosSmooth.Packets/Converters/Basic/ULongStringConverter.cs b/Core/NosSmooth.Packets/Converters/Basic/ULongStringConverter.cs index 5b9c378..461db64 100644 --- a/Core/NosSmooth.Packets/Converters/Basic/ULongStringConverter.cs +++ b/Core/NosSmooth.Packets/Converters/Basic/ULongStringConverter.cs @@ -4,6 +4,7 @@ // Copyright (c) František Boháček. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System; using NosSmooth.Packets.Errors; using Remora.Results; @@ -15,11 +16,11 @@ namespace NosSmooth.Packets.Converters.Basic; public class ULongStringConverter : BasicTypeConverter { /// - protected override Result Deserialize(string value) + protected override Result Deserialize(ReadOnlySpan value) { if (!ulong.TryParse(value, out var parsed)) { - return new CouldNotConvertError(this, value, "Could not parse as an ulong."); + return new CouldNotConvertError(this, value.ToString(), "Could not parse as an ulong."); } return parsed; diff --git a/Core/NosSmooth.Packets/Converters/Basic/UShortStringConverter.cs b/Core/NosSmooth.Packets/Converters/Basic/UShortStringConverter.cs index 4d1c7d9..57e696b 100644 --- a/Core/NosSmooth.Packets/Converters/Basic/UShortStringConverter.cs +++ b/Core/NosSmooth.Packets/Converters/Basic/UShortStringConverter.cs @@ -4,6 +4,7 @@ // Copyright (c) František Boháček. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System; using NosSmooth.Packets.Errors; using Remora.Results; @@ -15,11 +16,11 @@ namespace NosSmooth.Packets.Converters.Basic; public class UShortStringConverter : BasicTypeConverter { /// - protected override Result Deserialize(string value) + protected override Result Deserialize(ReadOnlySpan value) { if (!ushort.TryParse(value, out var parsed)) { - return new CouldNotConvertError(this, value, "Could not parse as an ushort."); + return new CouldNotConvertError(this, value.ToString(), "Could not parse as an ushort."); } return parsed; diff --git a/Core/NosSmooth.Packets/Converters/Common/NameStringConverter.cs b/Core/NosSmooth.Packets/Converters/Common/NameStringConverter.cs index 0e63ea5..b167240 100644 --- a/Core/NosSmooth.Packets/Converters/Common/NameStringConverter.cs +++ b/Core/NosSmooth.Packets/Converters/Common/NameStringConverter.cs @@ -29,19 +29,19 @@ public class NameStringConverter : BaseStringConverter } /// - public override Result Deserialize(PacketStringEnumerator stringEnumerator) + public override Result Deserialize(ref PacketStringEnumerator stringEnumerator) { - var tokenResult = stringEnumerator.GetNextToken(); + var tokenResult = stringEnumerator.GetNextToken(out var packetToken); if (!tokenResult.IsSuccess) { return Result.FromError(tokenResult); } - if (tokenResult.Entity.Token == "-") + if (packetToken.Token[0] == '-' && packetToken.Token.Length == 1) { return Result.FromSuccess(null); } - return NameString.FromPacket(tokenResult.Entity.Token); + return NameString.FromPacket(packetToken.Token.ToString()); } } \ No newline at end of file diff --git a/Core/NosSmooth.Packets/Converters/IStringConverter.cs b/Core/NosSmooth.Packets/Converters/IStringConverter.cs index ba4f3f4..b04a617 100644 --- a/Core/NosSmooth.Packets/Converters/IStringConverter.cs +++ b/Core/NosSmooth.Packets/Converters/IStringConverter.cs @@ -18,7 +18,7 @@ public interface IStringConverter /// /// The packet string enumerator with the current position. /// The parsed object or an error. - public Result Deserialize(PacketStringEnumerator stringEnumerator); + public Result Deserialize(ref PacketStringEnumerator stringEnumerator); /// /// Serializes the given object to string by appending to the packet string builder. @@ -43,7 +43,7 @@ public interface IStringConverter : IStringConverter /// /// The packet string enumerator with the current position. /// The parsed object or an error. - public new Result Deserialize(PacketStringEnumerator stringEnumerator); + public new Result Deserialize(ref PacketStringEnumerator stringEnumerator); /// /// Serializes the given object to string by appending to the packet string builder. diff --git a/Core/NosSmooth.Packets/Converters/IStringSerializer.cs b/Core/NosSmooth.Packets/Converters/IStringSerializer.cs index 67786ff..a9e3ef5 100644 --- a/Core/NosSmooth.Packets/Converters/IStringSerializer.cs +++ b/Core/NosSmooth.Packets/Converters/IStringSerializer.cs @@ -20,7 +20,7 @@ public interface IStringSerializer /// The type of the object to serialize. /// The packet string enumerator with the current position. /// The parsed object or an error. - public Result Deserialize(Type parseType, PacketStringEnumerator stringEnumerator); + public Result Deserialize(Type parseType, ref PacketStringEnumerator stringEnumerator); /// /// Serializes the given object to string by appending to the packet string builder. @@ -37,7 +37,7 @@ public interface IStringSerializer /// The packet string enumerator with the current position. /// The type of the object to serialize. /// The parsed object or an error. - public Result Deserialize(PacketStringEnumerator stringEnumerator); + public Result Deserialize(ref PacketStringEnumerator stringEnumerator); /// /// Serializes the given object to string by appending to the packet string builder. diff --git a/Core/NosSmooth.Packets/Converters/Packets/UpgradeRareSubPacketConverter.cs b/Core/NosSmooth.Packets/Converters/Packets/UpgradeRareSubPacketConverter.cs index 5e7d13e..dac0cbb 100644 --- a/Core/NosSmooth.Packets/Converters/Packets/UpgradeRareSubPacketConverter.cs +++ b/Core/NosSmooth.Packets/Converters/Packets/UpgradeRareSubPacketConverter.cs @@ -28,31 +28,31 @@ public class UpgradeRareSubPacketConverter : BaseStringConverter - public override Result Deserialize(PacketStringEnumerator stringEnumerator) + public override Result Deserialize(ref PacketStringEnumerator stringEnumerator) { - var tokenResult = stringEnumerator.GetNextToken(); + var tokenResult = stringEnumerator.GetNextToken(out var packetToken); if (!tokenResult.IsSuccess) { return Result.FromError(tokenResult); } + var token = packetToken.Token; - var token = tokenResult.Entity.Token; if (token.Length > 3) { - return new CouldNotConvertError(this, token, "The string is not two/three characters long."); + return new CouldNotConvertError(this, token.ToString(), "The string is not two/three characters long."); } - var upgradeString = token.Substring(0, token.Length - 1); - var rareString = token[token.Length - 1].ToString(); + var upgradeString = token.Slice(0, token.Length - 1); + var rareString = token.Slice(token.Length - 1); if (!byte.TryParse(upgradeString, out var upgrade)) { - return new CouldNotConvertError(this, upgradeString, "Could not parse as byte"); + return new CouldNotConvertError(this, upgradeString.ToString(), "Could not parse as byte"); } if (!sbyte.TryParse(rareString, out var rare)) { - return new CouldNotConvertError(this, rareString, "Could not parse as byte"); + return new CouldNotConvertError(this, rareString.ToString(), "Could not parse as byte"); } return new UpgradeRareSubPacket(upgrade, rare); diff --git a/Core/NosSmooth.Packets/Converters/Special/EnumTypeConverter.cs b/Core/NosSmooth.Packets/Converters/Special/EnumTypeConverter.cs new file mode 100644 index 0000000..e69de29 diff --git a/Core/NosSmooth.Packets/Converters/Special/ISpecialTypeConverter.cs b/Core/NosSmooth.Packets/Converters/Special/ISpecialTypeConverter.cs new file mode 100644 index 0000000..e69de29 diff --git a/Core/NosSmooth.Packets/Converters/Special/ListTypeConverter.cs b/Core/NosSmooth.Packets/Converters/Special/ListTypeConverter.cs new file mode 100644 index 0000000..e69de29 diff --git a/Core/NosSmooth.Packets/Converters/Special/NullableTypeConverter.cs b/Core/NosSmooth.Packets/Converters/Special/NullableTypeConverter.cs new file mode 100644 index 0000000..e69de29 diff --git a/Core/NosSmooth.Packets/Converters/TypeConverterRepository.cs b/Core/NosSmooth.Packets/Converters/TypeConverterRepository.cs new file mode 100644 index 0000000..e69de29 diff --git a/Core/NosSmooth.Packets/Errors/CouldNotConvertError.cs b/Core/NosSmooth.Packets/Errors/CouldNotConvertError.cs index 64f23de..7b78040 100644 --- a/Core/NosSmooth.Packets/Errors/CouldNotConvertError.cs +++ b/Core/NosSmooth.Packets/Errors/CouldNotConvertError.cs @@ -5,6 +5,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Buffers; using NosSmooth.Packets.Converters; using Remora.Results; diff --git a/Core/NosSmooth.Packets/NosSmooth.Packets.csproj b/Core/NosSmooth.Packets/NosSmooth.Packets.csproj index a2d3199..c0e591c 100644 --- a/Core/NosSmooth.Packets/NosSmooth.Packets.csproj +++ b/Core/NosSmooth.Packets/NosSmooth.Packets.csproj @@ -2,9 +2,9 @@ 10 - net6.0;netstandard2.0 NosSmooth.Packets NosSmooth.Packets + net6.0;netstandard2.1 diff --git a/Core/NosSmooth.Packets/PacketSerializer.cs b/Core/NosSmooth.Packets/PacketSerializer.cs index 0d7048a..57d8ebe 100644 --- a/Core/NosSmooth.Packets/PacketSerializer.cs +++ b/Core/NosSmooth.Packets/PacketSerializer.cs @@ -59,20 +59,20 @@ public class PacketSerializer : IPacketSerializer public Result Deserialize(string packetString, PacketSource preferredSource) { var packetStringEnumerator = new PacketStringEnumerator(packetString); - var headerTokenResult = packetStringEnumerator.GetNextToken(); + var headerTokenResult = packetStringEnumerator.GetNextToken(out var packetToken); if (!headerTokenResult.IsSuccess) { return Result.FromError(headerTokenResult); } - var packetInfoResult = _packetTypesRepository.FindPacketInfo(headerTokenResult.Entity.Token, preferredSource); + var packetInfoResult = _packetTypesRepository.FindPacketInfo(packetToken.Token.ToString(), preferredSource); if (!packetInfoResult.IsSuccess) { return Result.FromError(packetInfoResult); } var packetInfo = packetInfoResult.Entity; - var deserializedResult = packetInfo.PacketConverter.Deserialize(packetStringEnumerator); + var deserializedResult = packetInfo.PacketConverter.Deserialize(ref packetStringEnumerator); if (!deserializedResult.IsSuccess) { return Result.FromError(deserializedResult); diff --git a/Core/NosSmooth.Packets/PacketStringEnumerator.cs b/Core/NosSmooth.Packets/PacketStringEnumerator.cs index 1b8fee3..96c27e2 100644 --- a/Core/NosSmooth.Packets/PacketStringEnumerator.cs +++ b/Core/NosSmooth.Packets/PacketStringEnumerator.cs @@ -4,6 +4,7 @@ // Copyright (c) František Boháček. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System; using System.Collections.Generic; using System.Text; using NosSmooth.Packets.Errors; @@ -14,15 +15,18 @@ namespace NosSmooth.Packets; /// /// Enumerator for packet strings. /// -public struct PacketStringEnumerator +public ref struct PacketStringEnumerator { - private readonly EnumeratorData _data; + private readonly ReadOnlySpan _data; private readonly Dictionary _numberOfSeparators; private EnumeratorLevel _currentLevel; private (char Separator, uint? MaxTokens)? _preparedLevel; - private PacketToken? _currentToken; + private bool _currentTokenRead; + private PacketToken _currentToken; private bool _readToLast; + private int _cursor; + /// /// Initializes a new instance of the struct. /// @@ -31,30 +35,14 @@ public struct PacketStringEnumerator public PacketStringEnumerator(string data, char separator = ' ') { _currentLevel = new EnumeratorLevel(null, separator); - _data = new EnumeratorData(data); + _data = new ReadOnlySpan(data.ToCharArray()); + _cursor = 0; _numberOfSeparators = new Dictionary(); _numberOfSeparators.Add(separator, 1); - _currentToken = null; - _preparedLevel = null; - _readToLast = false; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The data of the enumerator. - /// The current enumerator level. - /// The number of separators. - private PacketStringEnumerator(EnumeratorData data, EnumeratorLevel level, Dictionary numberOfSeparators) - { - _currentLevel = level; - _data = data; - - // TODO: use something less heavy than copying everything from the dictionary. - _numberOfSeparators = new Dictionary(numberOfSeparators); - _currentToken = null; + _currentToken = new PacketToken(default, default, default, default); _preparedLevel = null; _readToLast = false; + _currentTokenRead = false; } /// @@ -66,7 +54,7 @@ public struct PacketStringEnumerator /// The separator to look for. public void SetAfterSeparatorOnce(char separator) { - _currentToken = null; + _currentTokenRead = false; _currentLevel.SeparatorOnce = separator; } @@ -96,19 +84,6 @@ public struct PacketStringEnumerator _preparedLevel = null; } - /// - /// Create next level with the separator given in the prepared level. - /// - /// - /// Level of the current enumerator will stay the same. - /// Will return null, if there is not a level prepared. - /// - /// An enumerator with the new level pushed. - public PacketStringEnumerator? CreatePreparedLevel() - { - return _preparedLevel is not null ? CreateLevel(_preparedLevel.Value.Separator, _preparedLevel.Value.MaxTokens) : null; - } - /// /// Push next level with the separator given in the prepared level. /// @@ -120,7 +95,7 @@ public struct PacketStringEnumerator return false; } - _currentToken = null; + _currentTokenRead = false; _currentLevel = new EnumeratorLevel(_currentLevel, _preparedLevel.Value.Separator, _preparedLevel.Value.MaxTokens) { ReachedEnd = _currentLevel.ReachedEnd @@ -135,25 +110,6 @@ public struct PacketStringEnumerator return true; } - /// - /// Create next level with the given separator and maximum number of tokens. - /// - /// - /// Level of the current enumerator will stay the same. - /// The maximum number of tokens indicates how many tokens can be read ie. in lists, - /// the enumerator won't allow reading more than that many tokens, error will be thrown if the user tries to read more. - /// - /// The separator of the new level. - /// The maximum number of tokens to read. - /// An enumerator with the new level pushed. - public PacketStringEnumerator CreateLevel(char separator, uint? maxTokens = default) - { - _currentToken = null; - var stringEnumerator = new PacketStringEnumerator(_data, _currentLevel, _numberOfSeparators); - stringEnumerator.PushLevel(separator, maxTokens); - return stringEnumerator; - } - /// /// Push new separator level to the stack. /// @@ -166,7 +122,7 @@ public struct PacketStringEnumerator public void PushLevel(char separator, uint? maxTokens = default) { _preparedLevel = null; - _currentToken = null; + _currentTokenRead = false; _currentLevel = new EnumeratorLevel(_currentLevel, separator, maxTokens) { ReachedEnd = _currentLevel.ReachedEnd @@ -196,37 +152,51 @@ public struct PacketStringEnumerator return Result.FromSuccess(); } + /// + /// Skip the given amount of characters. + /// + /// The count of characters to skip. + public void Skip(int count) + { + _cursor += count; + } + /// /// Get the next token. /// + /// The resulting token. /// Whether to seek the cursor to the end of the token. /// The found token. - public Result GetNextToken(bool seek = true) + public Result GetNextToken(out PacketToken packetToken, bool seek = true) { // The token is cached if seek was false to speed things up. - if (_currentToken != null) + if (_currentTokenRead) { - var cachedToken = _currentToken.Value; + var cachedToken = _currentToken; if (seek) { UpdateCurrentAndParentLevels(cachedToken); _currentLevel.TokensRead++; - _currentToken = null; - _data.Cursor += cachedToken.Token.Length + 1; + _currentTokenRead = false; + _cursor += cachedToken.Token.Length + 1; _currentLevel.SeparatorOnce = null; } - return cachedToken; + packetToken = new PacketToken(default, default, default, default); + packetToken = cachedToken; + return Result.FromSuccess(); } - if (_data.ReachedEnd || (_currentLevel.ReachedEnd ?? false)) + if ((_cursor >= _data.Length) || (_currentLevel.ReachedEnd ?? false)) { - return new PacketEndReachedError(_data.Data, _currentLevel.ReachedEnd ?? false); + packetToken = new PacketToken(default, default, default, default); + return new PacketEndReachedError(_data.ToString(), _currentLevel.ReachedEnd ?? false); } - var currentIndex = _data.Cursor; - char currentCharacter = _data.Data[currentIndex]; - StringBuilder tokenString = new StringBuilder(); + var currentIndex = _cursor; + var length = 0; + var startIndex = currentIndex; + char currentCharacter = _data[currentIndex]; bool? isLast, encounteredUpperLevel; @@ -234,27 +204,27 @@ public struct PacketStringEnumerator // If should read to last, then read until isLast is null or true. while (!IsSeparator(currentCharacter, out isLast, out encounteredUpperLevel) || (_readToLast && !(isLast ?? true))) { - tokenString.Append(currentCharacter); + length++; currentIndex++; - if (currentIndex == _data.Data.Length) + if (currentIndex >= _data.Length) { isLast = true; encounteredUpperLevel = true; break; } - currentCharacter = _data.Data[currentIndex]; + currentCharacter = _data[currentIndex]; } _readToLast = false; currentIndex++; - var token = new PacketToken(tokenString.ToString(), isLast, encounteredUpperLevel, _data.ReachedEnd); + var token = new PacketToken(_data.Slice(startIndex, length), isLast, encounteredUpperLevel, _cursor >= _data.Length); if (seek) { UpdateCurrentAndParentLevels(token); - _data.Cursor = currentIndex; + _cursor = currentIndex; _currentLevel.TokensRead++; } else @@ -262,7 +232,8 @@ public struct PacketStringEnumerator _currentToken = token; } - return token; + packetToken = token; + return Result.FromSuccess(); } /// @@ -312,7 +283,7 @@ public struct PacketStringEnumerator /// Whether the last token was read. Null if cannot determine (ie. there are multiple levels with the same separator.) public bool? IsOnLastToken() { - if (_data.ReachedEnd) + if (_cursor >= _data.Length) { return true; } @@ -376,21 +347,6 @@ public struct PacketStringEnumerator return true; } - private class EnumeratorData - { - public EnumeratorData(string data) - { - Data = data; - Cursor = 0; - } - - public string Data { get; } - - public int Cursor { get; set; } - - public bool ReachedEnd => Cursor >= Data.Length; - } - private class EnumeratorLevel { public EnumeratorLevel(EnumeratorLevel? parent, char separator, uint? maxTokens = default) diff --git a/Core/NosSmooth.Packets/PacketToken.cs b/Core/NosSmooth.Packets/PacketToken.cs index 412c341..07cc31c 100644 --- a/Core/NosSmooth.Packets/PacketToken.cs +++ b/Core/NosSmooth.Packets/PacketToken.cs @@ -4,6 +4,7 @@ // Copyright (c) František Boháček. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System; using System.Diagnostics.CodeAnalysis; namespace NosSmooth.Packets; @@ -11,9 +12,52 @@ namespace NosSmooth.Packets; /// /// The single token from a packet. /// -/// The token. -/// Whether the token is last in the current level. Null if it cannot be determined. -/// Whether the current separator was from an upper stack level than the parent. That could mean some kind of an error if not etc. at the end of parsing a last entry of a list and last entry of a subpacket. -/// Whether the packet's end was reached. -[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1313:Parameter names should begin with lower-case letter", Justification = "Record struct creates the underlying properties.")] -public readonly record struct PacketToken(string Token, bool? IsLast, bool? EncounteredUpperLevel, bool PacketEndReached); \ No newline at end of file +[SuppressMessage +( + "StyleCop.CSharp.NamingRules", + "SA1313:Parameter names should begin with lower-case letter", + Justification = "Record struct creates the underlying properties." +)] +public readonly ref struct PacketToken +{ + /// + /// Initializes a new instance of the struct. + /// + /// The token. + /// Whether this is the last token in the current level. + /// Whether upper level separator was encountered. + /// Whether the packet end was reached. + public PacketToken + ( + ReadOnlySpan token, + bool? isLast, + bool? encounteredUpperLevel, + bool packetEndReached + ) + { + Token = token; + IsLast = isLast; + EncounteredUpperLevel = encounteredUpperLevel; + PacketEndReached = packetEndReached; + } + + /// + /// The token. + /// + public ReadOnlySpan Token { get; } + + /// + /// Whether the token is last in the current level. Null if it cannot be determined. + /// + public bool? IsLast { get; } + + /// + /// Whether the current separator was from an upper stack level than the parent. That could mean some kind of an error if not etc. at the end of parsing a last entry of a list and last entry of a subpacket. + /// + public bool? EncounteredUpperLevel { get; } + + /// + /// Whether the packet's end was reached. + /// + public bool PacketEndReached { get; } +} \ No newline at end of file diff --git a/Tests/NosSmooth.Packets.Tests/PacketStringBuilderTests.cs b/Tests/NosSmooth.Packets.Tests/PacketStringBuilderTests.cs index bb30058..848978a 100644 --- a/Tests/NosSmooth.Packets.Tests/PacketStringBuilderTests.cs +++ b/Tests/NosSmooth.Packets.Tests/PacketStringBuilderTests.cs @@ -55,7 +55,6 @@ public class PacketStringBuilderTests stringBuilder.Append("a"); stringBuilder.Append("b"); stringBuilder.Append("c"); - stringBuilder.ReplaceWithParentSeparator(); stringBuilder.PopLevel(); stringBuilder.Append("d"); diff --git a/Tests/NosSmooth.Packets.Tests/PacketStringEnumeratorTests.cs b/Tests/NosSmooth.Packets.Tests/PacketStringEnumeratorTests.cs index a196b27..7c8069a 100644 --- a/Tests/NosSmooth.Packets.Tests/PacketStringEnumeratorTests.cs +++ b/Tests/NosSmooth.Packets.Tests/PacketStringEnumeratorTests.cs @@ -23,64 +23,65 @@ public class PacketStringEnumeratorTests public void EnumeratorListComplexStringGivesCorrectResult() { var stringEnumerator = new PacketStringEnumerator("in 1 11.12.13|14.15.16|17.18.19"); - var headerTokenResult = stringEnumerator.GetNextToken(); + var headerTokenResult = stringEnumerator.GetNextToken(out var packetToken); Assert.True(headerTokenResult.IsSuccess); - Assert.False(headerTokenResult.Entity.PacketEndReached); - Assert.NotNull(headerTokenResult.Entity.IsLast); - Assert.NotNull(headerTokenResult.Entity.EncounteredUpperLevel); - Assert.False(headerTokenResult.Entity.IsLast); - Assert.False(headerTokenResult.Entity.EncounteredUpperLevel); - Assert.Matches("in", headerTokenResult.Entity.Token); - - var firstToken = stringEnumerator.GetNextToken(); + Assert.False(packetToken.PacketEndReached); + Assert.NotNull(packetToken.IsLast); + Assert.NotNull(packetToken.EncounteredUpperLevel); + Assert.False(packetToken.IsLast); + Assert.False(packetToken.EncounteredUpperLevel); + Assert.Matches("in", packetToken.Token.ToString()); + + var firstToken = stringEnumerator.GetNextToken(out packetToken); Assert.True(firstToken.IsSuccess); - Assert.False(firstToken.Entity.PacketEndReached); - Assert.NotNull(firstToken.Entity.IsLast); - Assert.NotNull(firstToken.Entity.EncounteredUpperLevel); - Assert.False(firstToken.Entity.IsLast); - Assert.False(firstToken.Entity.EncounteredUpperLevel); - Assert.Matches("1", firstToken.Entity.Token); + Assert.False(packetToken.PacketEndReached); + Assert.NotNull(packetToken.IsLast); + Assert.NotNull(packetToken.EncounteredUpperLevel); + Assert.False(packetToken.IsLast); + Assert.False(packetToken.EncounteredUpperLevel); + Assert.Matches("1", packetToken.Token.ToString()); - var listEnumerator = stringEnumerator.CreateLevel('|'); - listEnumerator.PrepareLevel('.'); + stringEnumerator.PushLevel('|'); + stringEnumerator.PrepareLevel('.'); for (int i = 0; i < 3; i++) { - var preparedLevel = listEnumerator.CreatePreparedLevel(); - Assert.NotNull(preparedLevel); + stringEnumerator.PushPreparedLevel(); for (int j = 0; j < 3; j++) { string currentNum = (j + (i * 3) + 1 + 10).ToString(); - var currentToken = preparedLevel!.Value.GetNextToken(); + var currentToken = stringEnumerator.GetNextToken(out packetToken); Assert.True(currentToken.IsSuccess); - Assert.False(currentToken.Entity.PacketEndReached); - Assert.NotNull(currentToken.Entity.IsLast); - Assert.NotNull(currentToken.Entity.EncounteredUpperLevel); + Assert.False(packetToken.PacketEndReached); + Assert.NotNull(packetToken.IsLast); + Assert.NotNull(packetToken.EncounteredUpperLevel); if (j == 2 && i == 2) { - Assert.True(currentToken.Entity.EncounteredUpperLevel); + Assert.True(packetToken.EncounteredUpperLevel); } else { - Assert.False(currentToken.Entity.EncounteredUpperLevel); + Assert.False(packetToken.EncounteredUpperLevel); } if (j != 2) { - Assert.False(currentToken.Entity.IsLast); + Assert.False(packetToken.IsLast); } else { - Assert.True(currentToken.Entity.IsLast); + Assert.True(packetToken.IsLast); } - Assert.Matches(currentNum, currentToken.Entity.Token); + Assert.Matches(currentNum, packetToken.Token.ToString()); } - Assert.True(preparedLevel!.Value.IsOnLastToken()); + Assert.True(stringEnumerator.IsOnLastToken()); + stringEnumerator.PopLevel(); } + stringEnumerator.PopLevel(); Assert.True(stringEnumerator.IsOnLastToken()); } @@ -91,18 +92,18 @@ public class PacketStringEnumeratorTests public void EnumeratorDoesNotAllowOvereachingPacketEnd() { var stringEnumerator = new PacketStringEnumerator("in 1 2 3 4"); - var tokenResult = stringEnumerator.GetNextToken(); + var tokenResult = stringEnumerator.GetNextToken(out _); Assert.True(tokenResult.IsSuccess); // in - tokenResult = stringEnumerator.GetNextToken(); + tokenResult = stringEnumerator.GetNextToken(out _); Assert.True(tokenResult.IsSuccess); // 1 - tokenResult = stringEnumerator.GetNextToken(); + tokenResult = stringEnumerator.GetNextToken(out _); Assert.True(tokenResult.IsSuccess); // 2 - tokenResult = stringEnumerator.GetNextToken(); + tokenResult = stringEnumerator.GetNextToken(out _); Assert.True(tokenResult.IsSuccess); // 3 - tokenResult = stringEnumerator.GetNextToken(); + tokenResult = stringEnumerator.GetNextToken(out _); Assert.True(tokenResult.IsSuccess); // 4 - tokenResult = stringEnumerator.GetNextToken(); + tokenResult = stringEnumerator.GetNextToken(out _); Assert.False(tokenResult.IsSuccess); Assert.IsType(tokenResult.Error); } @@ -114,20 +115,20 @@ public class PacketStringEnumeratorTests public void EnumeratorDoesNotAllowOvereachingListComplexTypeEnd() { var stringEnumerator = new PacketStringEnumerator("in 1|2.2|3.3|4.4|5"); - var tokenResult = stringEnumerator.GetNextToken(); + var tokenResult = stringEnumerator.GetNextToken(out _); Assert.True(tokenResult.IsSuccess); // in - var listEnumerator = stringEnumerator.CreateLevel('.'); - var itemEnumerator = listEnumerator.CreateLevel('|'); + stringEnumerator.PushLevel('.'); + stringEnumerator.PushLevel('|'); - tokenResult = itemEnumerator.GetNextToken(); + tokenResult = stringEnumerator.GetNextToken(out _); Assert.True(tokenResult.IsSuccess); // 1 - tokenResult = itemEnumerator.GetNextToken(); + tokenResult = stringEnumerator.GetNextToken(out var packetToken); Assert.True(tokenResult.IsSuccess); // 2 - Assert.True(tokenResult.Entity.IsLast); + Assert.True(packetToken.IsLast); - tokenResult = itemEnumerator.GetNextToken(); + tokenResult = stringEnumerator.GetNextToken(out _); Assert.False(tokenResult.IsSuccess); Assert.IsType(tokenResult.Error); Assert.True(((PacketEndReachedError)tokenResult.Error!).LevelEnd); @@ -140,33 +141,37 @@ public class PacketStringEnumeratorTests public void EnumeratorDoesNotAllowOvereachingListLength() { var stringEnumerator = new PacketStringEnumerator("in 1|2.2|3.3|4.4|5"); - var tokenResult = stringEnumerator.GetNextToken(); + var tokenResult = stringEnumerator.GetNextToken(out _); Assert.True(tokenResult.IsSuccess); // in - var listEnumerator = stringEnumerator.CreateLevel('.', 2); - var itemEnumerator = listEnumerator.CreateLevel('|'); + stringEnumerator.PushLevel('.', 2); + stringEnumerator.PushLevel('|'); // first item - tokenResult = itemEnumerator.GetNextToken(); + tokenResult = stringEnumerator.GetNextToken(out _); Assert.True(tokenResult.IsSuccess); - tokenResult = itemEnumerator.GetNextToken(); + tokenResult = stringEnumerator.GetNextToken(out var packetToken); Assert.True(tokenResult.IsSuccess); - Assert.True(tokenResult.Entity.IsLast); + Assert.True(packetToken.IsLast); + + stringEnumerator.PopLevel(); // second item - itemEnumerator = listEnumerator.CreateLevel('|'); - tokenResult = itemEnumerator.GetNextToken(); + stringEnumerator.PushLevel('|'); + tokenResult = stringEnumerator.GetNextToken(out _); Assert.True(tokenResult.IsSuccess); - tokenResult = itemEnumerator.GetNextToken(); + stringEnumerator.GetNextToken(out packetToken); Assert.True(tokenResult.IsSuccess); - Assert.True(tokenResult.Entity.IsLast); + Assert.True(packetToken.IsLast); + + stringEnumerator.PopLevel(); // cannot reach third item - Assert.True(listEnumerator.IsOnLastToken()); - itemEnumerator = listEnumerator.CreateLevel('|'); - tokenResult = itemEnumerator.GetNextToken(); + Assert.True(stringEnumerator.IsOnLastToken()); + stringEnumerator.PushLevel('|'); + tokenResult = stringEnumerator.GetNextToken(out _); Assert.False(tokenResult.IsSuccess); Assert.IsType(tokenResult.Error); Assert.True(((PacketEndReachedError)tokenResult.Error!).LevelEnd); @@ -179,18 +184,18 @@ public class PacketStringEnumeratorTests public void EnumeratorReturnsEncounteredUpperLevel() { var stringEnumerator = new PacketStringEnumerator("in 1|2 1"); - var tokenResult = stringEnumerator.GetNextToken(); + var tokenResult = stringEnumerator.GetNextToken(out _); Assert.True(tokenResult.IsSuccess); // in - var listEnumerator = stringEnumerator.CreateLevel('.'); - var itemEnumerator = listEnumerator.CreateLevel('|'); + stringEnumerator.PushLevel('.'); + stringEnumerator.PushLevel('|'); - tokenResult = itemEnumerator.GetNextToken(); + tokenResult = stringEnumerator.GetNextToken(out _); Assert.True(tokenResult.IsSuccess); - tokenResult = itemEnumerator.GetNextToken(); + tokenResult = stringEnumerator.GetNextToken(out var packetToken); Assert.True(tokenResult.IsSuccess); - Assert.True(tokenResult.Entity.IsLast); - Assert.True(tokenResult.Entity.EncounteredUpperLevel); + Assert.True(packetToken.IsLast); + Assert.True(packetToken.EncounteredUpperLevel); } } \ No newline at end of file -- 2.48.1