span based reader

This commit is contained in:
JanEggers
2019-04-15 14:00:00 +02:00
committed by JanEggers
parent 732ea84caa
commit fbca8a6dc1
11 changed files with 194 additions and 48 deletions
@@ -7,6 +7,7 @@
<Authors />
<PackageId />
<LangVersion>7.2</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
@@ -54,6 +54,7 @@ namespace MQTTnet.AspNetCore
public async Task<MqttBasePacket> ReceivePacketAsync(TimeSpan timeout, CancellationToken cancellationToken)
{
var input = Connection.Transport.Input;
var reader = new SpanBasedMqttPacketBodyReader();
try
{
+11 -7
View File
@@ -35,18 +35,22 @@ namespace MQTTnet.AspNetCore
}
var bodySlice = copy.Slice(0, bodyLength);
var buffer = bodySlice.GetArray();
packet = formatter.Decode(new ReceivedMqttPacket(fixedheader, new MqttPacketBodyReader(buffer, 0, buffer.Length), buffer.Length + 2));
var buffer = bodySlice.GetMemory();
var reader = new SpanBasedMqttPacketBodyReader();
reader.SetBuffer(buffer);
packet = formatter.Decode(new ReceivedMqttPacket(fixedheader, reader, buffer.Length + 2));
consumed = bodySlice.End;
observed = bodySlice.End;
return true;
}
private static byte[] GetArray(this in ReadOnlySequence<byte> input)
private static ReadOnlyMemory<byte> GetMemory(this in ReadOnlySequence<byte> input)
{
if (input.IsSingleSegment)
{
return input.First.Span.ToArray();
return input.First;
}
// Should be rare
@@ -62,7 +66,7 @@ namespace MQTTnet.AspNetCore
var index = 1;
result = 0;
var temp = input.Slice(0, Math.Min(5, input.Length)).GetArray();
var temp = input.Slice(0, Math.Min(5, input.Length)).GetMemory();
do
{
@@ -70,13 +74,13 @@ namespace MQTTnet.AspNetCore
{
return false;
}
encodedByte = temp[index];
encodedByte = temp.Span[index];
index++;
value += (byte)(encodedByte & 127) * multiplier;
if (multiplier > 128 * 128 * 128)
{
throw new MqttProtocolViolationException($"Remaining length is invalid (Data={string.Join(",", temp.AsSpan(1, index).ToArray())}).");
throw new MqttProtocolViolationException($"Remaining length is invalid (Data={string.Join(",", temp.Slice(1, index).ToArray())}).");
}
multiplier *= 128;
@@ -0,0 +1,104 @@
using MQTTnet.Formatter;
using System;
using System.Buffers.Binary;
using System.Text;
namespace MQTTnet.AspNetCore
{
public class SpanBasedMqttPacketBodyReader : IMqttPacketBodyReader
{
private ReadOnlyMemory<byte> _buffer;
private int _offset;
public void SetBuffer(ReadOnlyMemory<byte> buffer)
{
_buffer = buffer;
_offset = 0;
}
public ulong Length => (ulong)_buffer.Length;
public bool EndOfStream => _buffer.Length.Equals(_offset);
public ulong Offset => (ulong)_offset;
public byte ReadByte()
{
ValidateReceiveBuffer(1);
return _buffer.Span[_offset++];
}
public byte[] ReadRemainingData()
{
return _buffer.ToArray();
}
public ushort ReadUInt16()
{
ValidateReceiveBuffer(2);
var result = BinaryPrimitives.ReadUInt16BigEndian(_buffer.Span);
_offset += 2;
return result;
}
public byte[] ReadWithLengthPrefix()
{
return ReadSegmentWithLengthPrefix().ToArray();
}
private ReadOnlyMemory<byte> ReadSegmentWithLengthPrefix()
{
var length = ReadUInt16();
ValidateReceiveBuffer(length);
var result = _buffer.Slice(_offset, length);
_offset += length;
return result;
}
private void ValidateReceiveBuffer(ushort length)
{
if (_buffer.Length < _offset + length)
{
throw new ArgumentOutOfRangeException(nameof(_buffer), $"expected at least {_offset + length} bytes but there are only {_buffer.Length} bytes");
}
}
public unsafe string ReadStringWithLengthPrefix()
{
var buffer = ReadSegmentWithLengthPrefix();
fixed (byte* bytes = &buffer.Span.GetPinnableReference())
{
var result = Encoding.UTF8.GetString(bytes, buffer.Length);
return result;
}
}
public ushort ReadTwoByteInteger()
{
throw new NotImplementedException();
}
public uint ReadFourByteInteger()
{
throw new NotImplementedException();
}
public uint ReadVariableLengthInteger()
{
throw new NotImplementedException();
}
public bool ReadBoolean()
{
throw new NotImplementedException();
}
public void Seek(ulong position)
{
throw new NotImplementedException();
}
}
}