perf: keep parser state in bytes until materialization

This commit is contained in:
Joseph Doherty
2026-03-13 10:02:07 -04:00
parent ca7e12e753
commit 9fa2ba97b9

View File

@@ -37,7 +37,7 @@ public readonly struct ParsedCommand
public sealed class NatsParser
{
private static readonly byte[] CrLfBytes = "\r\n"u8.ToArray();
private static ReadOnlySpan<byte> CrLfBytes => "\r\n"u8;
private ILogger? _logger;
public ILogger? Logger { set => _logger = value; }
@@ -85,7 +85,7 @@ public sealed class NatsParser
// Look for \r\n to find control line
var reader = new SequenceReader<byte>(buffer);
if (!reader.TryReadTo(out ReadOnlySequence<byte> line, CrLfBytes.AsSpan()))
if (!reader.TryReadTo(out ReadOnlySequence<byte> line, CrLfBytes))
return false;
// Control line size check
@@ -177,7 +177,7 @@ public sealed class NatsParser
case (byte)'c':
if (b1 == (byte)'o') // CONNECT
{
command = ParseConnect(lineSpan);
command = ParseConnect(line);
buffer = buffer.Slice(reader.Position);
TraceInOp("CONNECT");
return true;
@@ -188,7 +188,7 @@ public sealed class NatsParser
case (byte)'i':
if (b1 == (byte)'n') // INFO
{
command = ParseInfo(lineSpan);
command = ParseInfo(line);
buffer = buffer.Slice(reader.Position);
TraceInOp("INFO");
return true;
@@ -430,36 +430,34 @@ public sealed class NatsParser
};
}
private static ParsedCommandView ParseConnect(Span<byte> line)
private static ParsedCommandView ParseConnect(ReadOnlySequence<byte> line)
{
// CONNECT {json} -- find first space after command
int spaceIdx = line.IndexOf((byte)' ');
if (spaceIdx < 0)
var reader = new SequenceReader<byte>(line);
if (!reader.TryAdvanceTo((byte)' ', advancePastDelimiter: true))
throw new ProtocolViolationException("Invalid CONNECT");
var json = line[(spaceIdx + 1)..];
var json = line.Slice(reader.Position);
return new ParsedCommandView
{
Type = CommandType.Connect,
Operation = "CONNECT",
Payload = new ReadOnlySequence<byte>(json.ToArray()),
Payload = json,
MaxMessages = -1,
};
}
private static ParsedCommandView ParseInfo(Span<byte> line)
private static ParsedCommandView ParseInfo(ReadOnlySequence<byte> line)
{
// INFO {json} -- find first space after command
int spaceIdx = line.IndexOf((byte)' ');
if (spaceIdx < 0)
var reader = new SequenceReader<byte>(line);
if (!reader.TryAdvanceTo((byte)' ', advancePastDelimiter: true))
throw new ProtocolViolationException("Invalid INFO");
var json = line[(spaceIdx + 1)..];
var json = line.Slice(reader.Position);
return new ParsedCommandView
{
Type = CommandType.Info,
Operation = "INFO",
Payload = new ReadOnlySequence<byte>(json.ToArray()),
Payload = json,
MaxMessages = -1,
};
}