diff --git a/projects/Benchmarks/Program.cs b/projects/Benchmarks/Program.cs index bae73f01a5..71dea80bfc 100644 --- a/projects/Benchmarks/Program.cs +++ b/projects/Benchmarks/Program.cs @@ -21,7 +21,7 @@ public Config() { AddJob(Job.Default.WithRuntime(CoreRuntime.Core31)); AddJob(Job.Default.WithRuntime(ClrRuntime.Net48)); - AddExporter(DefaultExporters.Markdown, DefaultExporters.Csv); + AddExporter(DefaultExporters.Markdown, DefaultExporters.JsonFull).KeepBenchmarkFiles(true).DontOverwriteResults(true); AddDiagnoser(new DisassemblyDiagnoser(new DisassemblyDiagnoserConfig()), MemoryDiagnoser.Default); } } diff --git a/projects/Benchmarks/WireFormatting/DataTypeSerialization.cs b/projects/Benchmarks/WireFormatting/DataTypeSerialization.cs index 5755dcde1b..86ba8babf0 100644 --- a/projects/Benchmarks/WireFormatting/DataTypeSerialization.cs +++ b/projects/Benchmarks/WireFormatting/DataTypeSerialization.cs @@ -39,17 +39,17 @@ public class DataTypeFieldSerialization : DataTypeSerialization public override void SetUp() { _fieldNullBuffer = new byte[WireFormatting.GetFieldValueByteCount(null)]; - WireFormatting.WriteFieldValue(_fieldNullBuffer.Span, null); + WireFormatting.WriteFieldValue(ref _fieldNullBuffer.Span.GetStart(), null, _fieldNullBuffer.Length); _fieldIntBuffer = new byte[WireFormatting.GetFieldValueByteCount(_intObject)]; - WireFormatting.WriteFieldValue(_fieldIntBuffer.Span, _intObject); + WireFormatting.WriteFieldValue(ref _fieldIntBuffer.Span.GetStart(), _intObject, _fieldIntBuffer.Length); _fieldStringBuffer = new byte[WireFormatting.GetFieldValueByteCount(_shortString)]; - WireFormatting.WriteFieldValue(_fieldStringBuffer.Span, _shortString); + WireFormatting.WriteFieldValue(ref _fieldStringBuffer.Span.GetStart(), _shortString, _fieldStringBuffer.Length); _fieldArrayBuffer = new byte[WireFormatting.GetFieldValueByteCount(_byteArray)]; - WireFormatting.WriteFieldValue(_fieldArrayBuffer.Span, _byteArray); + WireFormatting.WriteFieldValue(ref _fieldArrayBuffer.Span.GetStart(), _byteArray, _fieldArrayBuffer.Length); _fieldDictBuffer = new byte[WireFormatting.GetFieldValueByteCount(_emptyDictionary)]; - WireFormatting.WriteFieldValue(_fieldDictBuffer.Span, _emptyDictionary); + WireFormatting.WriteFieldValue(ref _fieldDictBuffer.Span.GetStart(), _emptyDictionary, _fieldDictBuffer.Length); _fieldBinaryTableValueBuffer = new byte[WireFormatting.GetFieldValueByteCount(_binaryTableValue)]; - WireFormatting.WriteFieldValue(_fieldBinaryTableValueBuffer.Span, _binaryTableValue); + WireFormatting.WriteFieldValue(ref _fieldBinaryTableValueBuffer.Span.GetStart(), _binaryTableValue, _fieldBinaryTableValueBuffer.Length); } [Benchmark] @@ -64,20 +64,18 @@ public override void SetUp() public object DictRead() => WireFormatting.ReadFieldValue(_fieldDictBuffer.Span, out int _); [Benchmark] public object BinaryTableValueRead() => WireFormatting.ReadFieldValue(_fieldBinaryTableValueBuffer.Span, out int _); - [Benchmark] - public int NullWrite() => WireFormatting.WriteFieldValue(_buffer.Span,null); + public int NullWrite() => WireFormatting.WriteFieldValue(ref _buffer.Span.GetStart(), null, _buffer.Length); [Benchmark] - public int IntWrite() => WireFormatting.WriteFieldValue(_buffer.Span, _intObject); + public int IntWrite() => WireFormatting.WriteFieldValue(ref _buffer.Span.GetStart(), _intObject, _buffer.Length); [Benchmark] - public int StringWrite() => WireFormatting.WriteFieldValue(_buffer.Span, _shortString); + public int StringWrite() => WireFormatting.WriteFieldValue(ref _buffer.Span.GetStart(), _shortString, _buffer.Length); [Benchmark] - public int ArrayWrite() => WireFormatting.WriteFieldValue(_buffer.Span, _byteArray); + public int ArrayWrite() => WireFormatting.WriteFieldValue(ref _buffer.Span.GetStart(), _byteArray, _buffer.Length); [Benchmark] - public int DictWrite() => WireFormatting.WriteFieldValue(_buffer.Span, _emptyDictionary); + public int DictWrite() => WireFormatting.WriteFieldValue(ref _buffer.Span.GetStart(), _emptyDictionary, _buffer.Length); [Benchmark] - public int BinaryTableValueWrite() => WireFormatting.WriteFieldValue(_buffer.Span, _binaryTableValue); - + public int BinaryTableValueWrite() => WireFormatting.WriteFieldValue(ref _buffer.Span.GetStart(), _binaryTableValue, _buffer.Length); [Benchmark] public int NullGetSize() => WireFormatting.GetFieldValueByteCount(null); [Benchmark] @@ -103,10 +101,10 @@ public override void SetUp() { _array = new List { "longstring", 1234, 12.34m, _timestamp }; _emptyArrayBuffer = new byte[WireFormatting.GetArrayByteCount(_emptyArray)]; - WireFormatting.WriteArray(_emptyArrayBuffer.Span, _emptyArray); + WireFormatting.WriteArray(ref _emptyArrayBuffer.Span.GetStart(), _emptyArray, _emptyArrayBuffer.Length); _populatedArrayBuffer = new byte[WireFormatting.GetArrayByteCount(_array)]; - WireFormatting.WriteArray(_populatedArrayBuffer.Span, _array); + WireFormatting.WriteArray(ref _populatedArrayBuffer.Span.GetStart(), _array, _populatedArrayBuffer.Length); } [Benchmark] @@ -116,10 +114,10 @@ public override void SetUp() public IList ArrayReadPopulated() => WireFormatting.ReadArray(_populatedArrayBuffer.Span, out _); [Benchmark] - public int ArrayWriteEmpty() => WireFormatting.WriteArray(_buffer.Span, _emptyArray); + public int ArrayWriteEmpty() => WireFormatting.WriteArray(ref _buffer.Span.GetStart(), _emptyArray, _buffer.Length); [Benchmark] - public int ArrayWritePopulated() => WireFormatting.WriteArray(_buffer.Span, _array); + public int ArrayWritePopulated() => WireFormatting.WriteArray(ref _buffer.Span.GetStart(), _array, _buffer.Length); [Benchmark] public int ArrayGetSizeEmpty() => WireFormatting.GetArrayByteCount(_emptyArray); @@ -149,10 +147,10 @@ public override void SetUp() }; _emptyDictionaryBuffer = new byte[WireFormatting.GetTableByteCount(_emptyDict)]; - WireFormatting.WriteTable(_emptyDictionaryBuffer.Span, _emptyDict); + WireFormatting.WriteTable(ref _emptyDictionaryBuffer.Span.GetStart(), _emptyDict, _emptyDictionaryBuffer.Length); _populatedDictionaryBuffer = new byte[WireFormatting.GetTableByteCount(_populatedDict)]; - WireFormatting.WriteTable(_populatedDictionaryBuffer.Span, _populatedDict); + WireFormatting.WriteTable(ref _populatedDictionaryBuffer.Span.GetStart(), _populatedDict, _populatedDictionaryBuffer.Length); } [Benchmark] @@ -162,10 +160,10 @@ public override void SetUp() public int TableReadPopulated() => WireFormatting.ReadDictionary(_populatedDictionaryBuffer.Span, out _); [Benchmark] - public int TableWriteEmpty() => WireFormatting.WriteTable(_buffer.Span, _emptyDict); + public int TableWriteEmpty() => WireFormatting.WriteTable(ref _buffer.Span.GetStart(), _emptyDict, _buffer.Length); [Benchmark] - public int TableWritePopulated() => WireFormatting.WriteTable(_buffer.Span, _populatedDict); + public int TableWritePopulated() => WireFormatting.WriteTable(ref _buffer.Span.GetStart(), _populatedDict, _buffer.Length); [Benchmark] public int TableGetSizeEmpty() => WireFormatting.GetTableByteCount(_emptyDict); @@ -187,10 +185,10 @@ public class DataTypeLongStringSerialization : DataTypeSerialization public int LongstrReadPopulated() => WireFormatting.ReadLongstr(_populatedLongStringBuffer.Span, out _); [Benchmark] - public int LongstrWriteEmpty() => WireFormatting.WriteLongstr(_buffer.Span, string.Empty); + public int LongstrWriteEmpty() => WireFormatting.WriteLongstr(ref _buffer.Span.GetStart(), string.Empty, _buffer.Length); [Benchmark] - public int LongstrWritePopulated() => WireFormatting.WriteLongstr(_buffer.Span, _longString); + public int LongstrWritePopulated() => WireFormatting.WriteLongstr(ref _buffer.Span.GetStart(), _longString, _buffer.Length); [Benchmark] public int LongstrGetSizeEmpty() => WireFormatting.GetFieldValueByteCount(string.Empty); @@ -201,7 +199,7 @@ public class DataTypeLongStringSerialization : DataTypeSerialization private static byte[] GenerateLongStringBuffer(string val) { byte[] _buffer = new byte[5 + Encoding.UTF8.GetByteCount(val)]; - WireFormatting.WriteLongstr(_buffer, val); + WireFormatting.WriteLongstr(ref _buffer.GetStart(), val, _buffer.Length); return _buffer; } } @@ -219,10 +217,10 @@ public class DataTypeShortStringSerialization : DataTypeSerialization public int ShortstrReadPopulated() => WireFormatting.ReadShortstr(_populatedShortStringBuffer.Span, out _); [Benchmark] - public int ShortstrWriteEmpty() => WireFormatting.WriteShortstr(_buffer.Span, string.Empty); + public int ShortstrWriteEmpty() => WireFormatting.WriteShortstr(ref _buffer.Span.GetStart(), string.Empty, _buffer.Length); [Benchmark] - public int ShortstrWritePopulated() => WireFormatting.WriteShortstr(_buffer.Span, _shortString); + public int ShortstrWritePopulated() => WireFormatting.WriteShortstr(ref _buffer.Span.GetStart(), _shortString, _buffer.Length); [Benchmark] public int ShortstrGetSizeEmpty() => WireFormatting.GetByteCount(string.Empty); @@ -233,7 +231,7 @@ public class DataTypeShortStringSerialization : DataTypeSerialization private static byte[] GenerateStringBuffer(string val) { byte[] _buffer = new byte[2 + Encoding.UTF8.GetByteCount(val)]; - WireFormatting.WriteShortstr(_buffer, val); + WireFormatting.WriteShortstr(ref _buffer.GetStart(), val, _buffer.Length); return _buffer; } } diff --git a/projects/Benchmarks/WireFormatting/MethodSerialization.cs b/projects/Benchmarks/WireFormatting/MethodSerialization.cs index 0f3a4a6b8b..a0bdf830ad 100644 --- a/projects/Benchmarks/WireFormatting/MethodSerialization.cs +++ b/projects/Benchmarks/WireFormatting/MethodSerialization.cs @@ -1,5 +1,6 @@ using System; using System.Text; + using BenchmarkDotNet.Attributes; using RabbitMQ.Client.Framing; @@ -37,11 +38,12 @@ public class MethodBasicDeliver : MethodSerializationBase public override void SetUp() { - int offset = RabbitMQ.Client.Impl.WireFormatting.WriteShortstr(_buffer.Span, string.Empty); - offset += RabbitMQ.Client.Impl.WireFormatting.WriteLonglong(_buffer.Slice(offset).Span, 0); - offset += RabbitMQ.Client.Impl.WireFormatting.WriteBits(_buffer.Slice(offset).Span, false); - offset += RabbitMQ.Client.Impl.WireFormatting.WriteShortstr(_buffer.Slice(offset).Span, string.Empty); - RabbitMQ.Client.Impl.WireFormatting.WriteShortstr(_buffer.Slice(offset).Span, string.Empty); + int length = _buffer.Length; + int offset = Client.Impl.WireFormatting.WriteShortstr(ref _buffer.Span.GetStart(), string.Empty, length); + offset += Client.Impl.WireFormatting.WriteLonglong(ref _buffer.Span.GetOffset(offset), 0); + offset += Client.Impl.WireFormatting.WriteBits(ref _buffer.Span.GetOffset(offset), false); + offset += Client.Impl.WireFormatting.WriteShortstr(ref _buffer.Span.GetOffset(offset), string.Empty, length - offset); + Client.Impl.WireFormatting.WriteShortstr(ref _buffer.Span.GetOffset(offset), string.Empty, length - offset); } [Benchmark] diff --git a/projects/Benchmarks/WireFormatting/PrimitivesSerialization.cs b/projects/Benchmarks/WireFormatting/PrimitivesSerialization.cs index 00334e5350..ce6f264689 100644 --- a/projects/Benchmarks/WireFormatting/PrimitivesSerialization.cs +++ b/projects/Benchmarks/WireFormatting/PrimitivesSerialization.cs @@ -19,7 +19,7 @@ public virtual void Setup() { } public class PrimitivesBool : PrimitivesBase { - public override void Setup() => WireFormatting.WriteBits(_buffer.Span, true, false, true, false, true); + public override void Setup() => WireFormatting.WriteBits(ref _buffer.Span.GetStart(), true, false, true, false, true); [Benchmark] public int BoolRead2() => WireFormatting.ReadBits(_buffer.Span, out bool _, out bool _); @@ -29,70 +29,70 @@ public class PrimitivesBool : PrimitivesBase [Benchmark] [Arguments(true, false)] - public int BoolWrite2(bool param1, bool param2) => WireFormatting.WriteBits(_buffer.Span, param1, param2); + public int BoolWrite2(bool param1, bool param2) => WireFormatting.WriteBits(ref _buffer.Span.GetStart(), param1, param2); [Benchmark] [Arguments(true, false)] - public int BoolWrite5(bool param1, bool param2) => WireFormatting.WriteBits(_buffer.Span, param1, param2, param1, param2, param1); + public int BoolWrite5(bool param1, bool param2) => WireFormatting.WriteBits(ref _buffer.Span.GetStart(), param1, param2, param1, param2, param1); } public class PrimitivesDecimal : PrimitivesBase { - public override void Setup() => WireFormatting.WriteDecimal(_buffer.Span, 123.45m); + public override void Setup() => WireFormatting.WriteDecimal(ref _buffer.Span.GetStart(), 123.45m); [Benchmark] public decimal DecimalRead() => WireFormatting.ReadDecimal(_buffer.Span); [Benchmark] - public int DecimalWrite() => WireFormatting.WriteDecimal(_buffer.Span, 123.45m); + public int DecimalWrite() => WireFormatting.WriteDecimal(ref _buffer.Span.GetStart(), 123.45m); } public class PrimitivesLong : PrimitivesBase { - public override void Setup() => WireFormatting.WriteLong(_buffer.Span, 12345u); + public override void Setup() => WireFormatting.WriteLong(ref _buffer.Span.GetStart(), 12345u); [Benchmark] public int LongRead() => WireFormatting.ReadLong(_buffer.Span, out _); [Benchmark] [Arguments(12345u)] - public int LongWrite(uint value) => WireFormatting.WriteLong(_buffer.Span, value); + public int LongWrite(uint value) => WireFormatting.WriteLong(ref _buffer.Span.GetStart(), value); } public class PrimitivesLonglong : PrimitivesBase { - public override void Setup() => WireFormatting.WriteLonglong(_buffer.Span, 12345ul); + public override void Setup() => WireFormatting.WriteLonglong(ref _buffer.Span.GetStart(), 12345ul); [Benchmark] public int LonglongRead() => WireFormatting.ReadLonglong(_buffer.Span, out _); [Benchmark] [Arguments(12345ul)] - public int LonglongWrite(ulong value) => WireFormatting.WriteLonglong(_buffer.Span, value); + public int LonglongWrite(ulong value) => WireFormatting.WriteLonglong(ref _buffer.Span.GetStart(), value); } public class PrimitivesShort : PrimitivesBase { - public override void Setup() => WireFormatting.WriteShort(_buffer.Span, 12345); + public override void Setup() => WireFormatting.WriteShort(ref _buffer.Span.GetStart(), 12345); [Benchmark] public int ShortRead() => WireFormatting.ReadShort(_buffer.Span, out _); [Benchmark] [Arguments(12345)] - public int ShortWrite(ushort value) => WireFormatting.WriteShort(_buffer.Span, value); + public int ShortWrite(ushort value) => WireFormatting.WriteShort(ref _buffer.Span.GetStart(), value); } public class PrimitivesTimestamp : PrimitivesBase { AmqpTimestamp _timestamp = new AmqpTimestamp(DateTimeOffset.UtcNow.ToUnixTimeSeconds()); - public override void Setup() => WireFormatting.WriteTimestamp(_buffer.Span, _timestamp); + public override void Setup() => WireFormatting.WriteTimestamp(ref _buffer.Span.GetStart(), _timestamp); [Benchmark] public int TimestampRead() => WireFormatting.ReadTimestamp(_buffer.Span, out _); [Benchmark] - public int TimestampWrite() => WireFormatting.WriteTimestamp(_buffer.Span, _timestamp); + public int TimestampWrite() => WireFormatting.WriteTimestamp(ref _buffer.Span.GetStart(), _timestamp); } } diff --git a/projects/RabbitMQ.Client/client/framing/BasicAck.cs b/projects/RabbitMQ.Client/client/framing/BasicAck.cs index 30a921c5fa..e9db73000f 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicAck.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicAck.cs @@ -30,6 +30,8 @@ //--------------------------------------------------------------------------- using System; +using System.Runtime.CompilerServices; + using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; @@ -40,16 +42,13 @@ internal sealed class BasicAck : Client.Impl.MethodBase public ulong _deliveryTag; public bool _multiple; - public BasicAck() - { - } - public BasicAck(ulong DeliveryTag, bool Multiple) { _deliveryTag = DeliveryTag; _multiple = Multiple; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public BasicAck(ReadOnlySpan span) { int offset = WireFormatting.ReadLonglong(span, out _deliveryTag); @@ -58,17 +57,12 @@ public BasicAck(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicAck; public override string ProtocolMethodName => "basic.ack"; - public override bool HasContent => false; - public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteLonglong(span, _deliveryTag); - return offset + WireFormatting.WriteBits(span.Slice(offset), _multiple); - } - - public override int GetRequiredBufferSize() - { - return 8 + 1; + int offset = WireFormatting.WriteLonglong(ref span.GetStart(), _deliveryTag); + offset += WireFormatting.WriteBits(ref span.GetOffset(offset), _multiple); + return offset; } + public override int GetRequiredBufferSize() => 9; } } diff --git a/projects/RabbitMQ.Client/client/framing/BasicCancel.cs b/projects/RabbitMQ.Client/client/framing/BasicCancel.cs index 692617286c..086a3aa715 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicCancel.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicCancel.cs @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------- using System; -using System.Text; + using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; @@ -59,12 +59,11 @@ public BasicCancel(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicCancel; public override string ProtocolMethodName => "basic.cancel"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteShortstr(span, _consumerTag); - return offset + WireFormatting.WriteBits(span.Slice(offset), _nowait); + int offset = WireFormatting.WriteShortstr(ref span.GetStart(), _consumerTag, span.Length); + return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _nowait); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/BasicCancelOk.cs b/projects/RabbitMQ.Client/client/framing/BasicCancelOk.cs index d2304cc409..489790617c 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicCancelOk.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicCancelOk.cs @@ -56,11 +56,10 @@ public BasicCancelOk(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicCancelOk; public override string ProtocolMethodName => "basic.cancel-ok"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - return WireFormatting.WriteShortstr(span, _consumerTag); + return WireFormatting.WriteShortstr(ref span.GetStart(), _consumerTag, span.Length); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/BasicConsume.cs b/projects/RabbitMQ.Client/client/framing/BasicConsume.cs index 52ecb82c1c..8d6aab539c 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicConsume.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicConsume.cs @@ -31,6 +31,7 @@ using System; using System.Collections.Generic; + using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; @@ -75,15 +76,15 @@ public BasicConsume(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicConsume; public override string ProtocolMethodName => "basic.consume"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteShort(span, default); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _queue); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _consumerTag); - offset += WireFormatting.WriteBits(span.Slice(offset), _noLocal, _noAck, _exclusive, _nowait); - return offset + WireFormatting.WriteTable(span.Slice(offset), _arguments); + int length = span.Length; + int offset = WireFormatting.WriteShort(ref span.GetStart(), default); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _queue, length - offset); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _consumerTag, length - offset); + offset += WireFormatting.WriteBits(ref span.GetOffset(offset), _noLocal, _noAck, _exclusive, _nowait); + return offset + WireFormatting.WriteTable(ref span.GetOffset(offset), _arguments, length - offset); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/BasicConsumeOk.cs b/projects/RabbitMQ.Client/client/framing/BasicConsumeOk.cs index 0578852da2..a7d500f0d4 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicConsumeOk.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicConsumeOk.cs @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------- using System; -using System.Text; + using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; @@ -56,11 +56,10 @@ public BasicConsumeOk(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicConsumeOk; public override string ProtocolMethodName => "basic.consume-ok"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - return WireFormatting.WriteShortstr(span, _consumerTag); + return WireFormatting.WriteShortstr(ref span.GetStart(), _consumerTag, span.Length); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/BasicDeliver.cs b/projects/RabbitMQ.Client/client/framing/BasicDeliver.cs index f8a4e99ec7..e934984f9e 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicDeliver.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicDeliver.cs @@ -30,8 +30,7 @@ //--------------------------------------------------------------------------- using System; -using System.Buffers.Binary; -using System.Text; + using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; @@ -69,15 +68,15 @@ public BasicDeliver(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicDeliver; public override string ProtocolMethodName => "basic.deliver"; - public override bool HasContent => true; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteShortstr(span, _consumerTag); - offset += WireFormatting.WriteLonglong(span.Slice(offset), _deliveryTag); - offset += WireFormatting.WriteBits(span.Slice(offset), _redelivered); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _exchange); - return offset + WireFormatting.WriteShortstr(span.Slice(offset), _routingKey); + int length = span.Length; + int offset = WireFormatting.WriteShortstr(ref span.GetStart(), _consumerTag, length); + offset += WireFormatting.WriteLonglong(ref span.GetOffset(offset), _deliveryTag); + offset += WireFormatting.WriteBits(ref span.GetOffset(offset), _redelivered); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _exchange, length - offset); + return offset + WireFormatting.WriteShortstr(ref span.GetOffset(offset), _routingKey, length - offset); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/BasicGet.cs b/projects/RabbitMQ.Client/client/framing/BasicGet.cs index 4e8648c09e..65707297c9 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicGet.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicGet.cs @@ -30,6 +30,7 @@ //--------------------------------------------------------------------------- using System; + using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; @@ -61,13 +62,12 @@ public BasicGet(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicGet; public override string ProtocolMethodName => "basic.get"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteShort(span, default); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _queue); - return offset + WireFormatting.WriteBits(span.Slice(offset), _noAck); + int offset = WireFormatting.WriteShort(ref span.GetStart(), default); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _queue, span.Length - offset); + return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _noAck); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/BasicGetEmpty.cs b/projects/RabbitMQ.Client/client/framing/BasicGetEmpty.cs index 69b2a15204..33f97e45e3 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicGetEmpty.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicGetEmpty.cs @@ -41,7 +41,6 @@ internal sealed class BasicGetEmpty : Client.Impl.MethodBase public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicGetEmpty; public override string ProtocolMethodName => "basic.get-empty"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { diff --git a/projects/RabbitMQ.Client/client/framing/BasicGetOk.cs b/projects/RabbitMQ.Client/client/framing/BasicGetOk.cs index 00e4ac8973..7509d8ceea 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicGetOk.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicGetOk.cs @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------- using System; -using System.Text; + using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; @@ -68,15 +68,15 @@ public BasicGetOk(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicGetOk; public override string ProtocolMethodName => "basic.get-ok"; - public override bool HasContent => true; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteLonglong(span, _deliveryTag); - offset += WireFormatting.WriteBits(span.Slice(offset), _redelivered); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _exchange); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _routingKey); - return offset + WireFormatting.WriteLong(span.Slice(offset), _messageCount); + int length = span.Length; + int offset = WireFormatting.WriteLonglong(ref span.GetStart(), _deliveryTag); + offset += WireFormatting.WriteBits(ref span.GetOffset(offset), _redelivered); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _exchange, length - offset); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _routingKey, length - offset); + return offset + WireFormatting.WriteLong(ref span.GetOffset(offset), _messageCount); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/BasicNack.cs b/projects/RabbitMQ.Client/client/framing/BasicNack.cs index 1f2186647b..c1bddca520 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicNack.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicNack.cs @@ -60,12 +60,11 @@ public BasicNack(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicNack; public override string ProtocolMethodName => "basic.nack"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteLonglong(span, _deliveryTag); - return offset + WireFormatting.WriteBits(span.Slice(offset), _multiple, _requeue); + int offset = WireFormatting.WriteLonglong(ref span.GetStart(), _deliveryTag); + return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _multiple, _requeue); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/BasicProperties.cs b/projects/RabbitMQ.Client/client/framing/BasicProperties.cs index aabfd4f6b7..294048f69f 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicProperties.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicProperties.cs @@ -31,7 +31,7 @@ using System; using System.Collections.Generic; -using System.Text; + using RabbitMQ.Client.Impl; namespace RabbitMQ.Client.Framing @@ -236,24 +236,25 @@ public BasicProperties(ReadOnlySpan span) internal override int WritePropertiesTo(Span span) { - int offset = WireFormatting.WriteBits(span, + int length = span.Length; + int offset = WireFormatting.WriteBits(ref span.GetStart(), IsContentTypePresent(), IsContentEncodingPresent(), IsHeadersPresent(), IsDeliveryModePresent(), IsPriorityPresent(), IsCorrelationIdPresent(), IsReplyToPresent(), IsExpirationPresent(), IsMessageIdPresent(), IsTimestampPresent(), IsTypePresent(), IsUserIdPresent(), IsAppIdPresent(), IsClusterIdPresent()); - if (IsContentTypePresent()) { offset += WireFormatting.WriteShortstr(span.Slice(offset), _contentType); } - if (IsContentEncodingPresent()) { offset += WireFormatting.WriteShortstr(span.Slice(offset), _contentEncoding); } - if (IsHeadersPresent()) { offset += WireFormatting.WriteTable(span.Slice(offset), _headers); } + if (IsContentTypePresent()) { offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _contentType, length - offset); } + if (IsContentEncodingPresent()) { offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _contentEncoding, length - offset); } + if (IsHeadersPresent()) { offset += WireFormatting.WriteTable(ref span.GetOffset(offset), _headers, length - offset); } if (IsDeliveryModePresent()) { span[offset++] = _deliveryMode; } if (IsPriorityPresent()) { span[offset++] = _priority; } - if (IsCorrelationIdPresent()) { offset += WireFormatting.WriteShortstr(span.Slice(offset), _correlationId); } - if (IsReplyToPresent()) { offset += WireFormatting.WriteShortstr(span.Slice(offset), _replyTo); } - if (IsExpirationPresent()) { offset += WireFormatting.WriteShortstr(span.Slice(offset), _expiration); } - if (IsMessageIdPresent()) { offset += WireFormatting.WriteShortstr(span.Slice(offset), _messageId); } - if (IsTimestampPresent()) { offset += WireFormatting.WriteTimestamp(span.Slice(offset), _timestamp); } - if (IsTypePresent()) { offset += WireFormatting.WriteShortstr(span.Slice(offset), _type); } - if (IsUserIdPresent()) { offset += WireFormatting.WriteShortstr(span.Slice(offset), _userId); } - if (IsAppIdPresent()) { offset += WireFormatting.WriteShortstr(span.Slice(offset), _appId); } - if (IsClusterIdPresent()) { offset += WireFormatting.WriteShortstr(span.Slice(offset), _clusterId); } + if (IsCorrelationIdPresent()) { offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _correlationId, length - offset); } + if (IsReplyToPresent()) { offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _replyTo, length - offset); } + if (IsExpirationPresent()) { offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _expiration, length - offset); } + if (IsMessageIdPresent()) { offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _messageId, length - offset); } + if (IsTimestampPresent()) { offset += WireFormatting.WriteTimestamp(ref span.GetOffset(offset), _timestamp); } + if (IsTypePresent()) { offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _type, length - offset); } + if (IsUserIdPresent()) { offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _userId, length - offset); } + if (IsAppIdPresent()) { offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _appId, length - offset); } + if (IsClusterIdPresent()) { offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _clusterId, length - offset); } return offset; } diff --git a/projects/RabbitMQ.Client/client/framing/BasicPublish.cs b/projects/RabbitMQ.Client/client/framing/BasicPublish.cs index 4ec46776fc..986b740787 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicPublish.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicPublish.cs @@ -30,6 +30,7 @@ //--------------------------------------------------------------------------- using System; + using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; @@ -66,14 +67,14 @@ public BasicPublish(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicPublish; public override string ProtocolMethodName => "basic.publish"; - public override bool HasContent => true; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteShort(span, default); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _exchange); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _routingKey); - return offset + WireFormatting.WriteBits(span.Slice(offset), _mandatory, _immediate); + int length = span.Length; + int offset = WireFormatting.WriteShort(ref span.GetStart(), default); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _exchange, length - offset); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _routingKey, length - offset); + return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _mandatory, _immediate); } public override int GetRequiredBufferSize() @@ -104,14 +105,13 @@ public BasicPublishMemory(ReadOnlyMemory Exchange, ReadOnlyMemory Ro public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicPublish; public override string ProtocolMethodName => "basic.publish"; - public override bool HasContent => true; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteShort(span, default); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _exchange.Span); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _routingKey.Span); - return offset + WireFormatting.WriteBits(span.Slice(offset), _mandatory, _immediate); + int offset = WireFormatting.WriteShort(ref span.GetStart(), default); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _exchange.Span); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _routingKey.Span); + return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _mandatory, _immediate); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/BasicQos.cs b/projects/RabbitMQ.Client/client/framing/BasicQos.cs index 8827097bd2..55407afcac 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicQos.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicQos.cs @@ -61,13 +61,12 @@ public BasicQos(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicQos; public override string ProtocolMethodName => "basic.qos"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteLong(span, _prefetchSize); - offset += WireFormatting.WriteShort(span.Slice(offset), _prefetchCount); - return offset + WireFormatting.WriteBits(span.Slice(offset), _global); + int offset = WireFormatting.WriteLong(ref span.GetStart(), _prefetchSize); + offset += WireFormatting.WriteShort(ref span.GetOffset(offset), _prefetchCount); + return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _global); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/BasicQosOk.cs b/projects/RabbitMQ.Client/client/framing/BasicQosOk.cs index eec5245931..bd421a0fdf 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicQosOk.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicQosOk.cs @@ -42,7 +42,6 @@ public BasicQosOk() public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicQosOk; public override string ProtocolMethodName => "basic.qos-ok"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { diff --git a/projects/RabbitMQ.Client/client/framing/BasicRecover.cs b/projects/RabbitMQ.Client/client/framing/BasicRecover.cs index 8c3fd6571a..8944d4d244 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicRecover.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicRecover.cs @@ -55,11 +55,10 @@ public BasicRecover(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicRecover; public override string ProtocolMethodName => "basic.recover"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - return WireFormatting.WriteBits(span, _requeue); + return WireFormatting.WriteBits(ref span.GetStart(), _requeue); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/BasicRecoverAsync.cs b/projects/RabbitMQ.Client/client/framing/BasicRecoverAsync.cs index 0f46194a2a..1e40693be4 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicRecoverAsync.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicRecoverAsync.cs @@ -55,11 +55,10 @@ public BasicRecoverAsync(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicRecoverAsync; public override string ProtocolMethodName => "basic.recover-async"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - return WireFormatting.WriteBits(span, _requeue); + return WireFormatting.WriteBits(ref span.GetStart(), _requeue); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/BasicRecoverOk.cs b/projects/RabbitMQ.Client/client/framing/BasicRecoverOk.cs index 90fce6114c..b724288d64 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicRecoverOk.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicRecoverOk.cs @@ -42,7 +42,6 @@ public BasicRecoverOk() public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicRecoverOk; public override string ProtocolMethodName => "basic.recover-ok"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { diff --git a/projects/RabbitMQ.Client/client/framing/BasicReject.cs b/projects/RabbitMQ.Client/client/framing/BasicReject.cs index 392af4967a..c0fc53ee77 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicReject.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicReject.cs @@ -58,12 +58,11 @@ public BasicReject(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicReject; public override string ProtocolMethodName => "basic.reject"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteLonglong(span, _deliveryTag); - return offset + WireFormatting.WriteBits(span.Slice(offset), _requeue); + int offset = WireFormatting.WriteLonglong(ref span.GetStart(), _deliveryTag); + return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _requeue); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/BasicReturn.cs b/projects/RabbitMQ.Client/client/framing/BasicReturn.cs index de9cf132dd..4f1ab3afc8 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicReturn.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicReturn.cs @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------- using System; -using System.Text; + using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; @@ -65,14 +65,14 @@ public BasicReturn(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicReturn; public override string ProtocolMethodName => "basic.return"; - public override bool HasContent => true; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteShort(span, _replyCode); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _replyText); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _exchange); - return offset + WireFormatting.WriteShortstr(span.Slice(offset), _routingKey); + int length = span.Length; + int offset = WireFormatting.WriteShort(ref span.GetStart(), _replyCode); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _replyText, length - offset); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _exchange, length - offset); + return offset + WireFormatting.WriteShortstr(ref span.GetOffset(offset), _routingKey, length - offset); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/ChannelClose.cs b/projects/RabbitMQ.Client/client/framing/ChannelClose.cs index 4dc81ec65b..6fc2c31d54 100644 --- a/projects/RabbitMQ.Client/client/framing/ChannelClose.cs +++ b/projects/RabbitMQ.Client/client/framing/ChannelClose.cs @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------- using System; -using System.Text; + using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; @@ -65,14 +65,13 @@ public ChannelClose(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ChannelClose; public override string ProtocolMethodName => "channel.close"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteShort(span, _replyCode); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _replyText); - offset += WireFormatting.WriteShort(span.Slice(offset), _classId); - return offset + WireFormatting.WriteShort(span.Slice(offset), _methodId); + int offset = WireFormatting.WriteShort(ref span.GetStart(), _replyCode); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _replyText, span.Length - offset); + offset += WireFormatting.WriteShort(ref span.GetOffset(offset), _classId); + return offset + WireFormatting.WriteShort(ref span.GetOffset(offset), _methodId); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/ChannelCloseOk.cs b/projects/RabbitMQ.Client/client/framing/ChannelCloseOk.cs index 23a91391a0..c43974112f 100644 --- a/projects/RabbitMQ.Client/client/framing/ChannelCloseOk.cs +++ b/projects/RabbitMQ.Client/client/framing/ChannelCloseOk.cs @@ -42,7 +42,6 @@ public ChannelCloseOk() public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ChannelCloseOk; public override string ProtocolMethodName => "channel.close-ok"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { diff --git a/projects/RabbitMQ.Client/client/framing/ChannelFlow.cs b/projects/RabbitMQ.Client/client/framing/ChannelFlow.cs index 20ef906cac..22fc607962 100644 --- a/projects/RabbitMQ.Client/client/framing/ChannelFlow.cs +++ b/projects/RabbitMQ.Client/client/framing/ChannelFlow.cs @@ -55,11 +55,10 @@ public ChannelFlow(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ChannelFlow; public override string ProtocolMethodName => "channel.flow"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - return WireFormatting.WriteBits(span, _active); + return WireFormatting.WriteBits(ref span.GetStart(), _active); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/ChannelFlowOk.cs b/projects/RabbitMQ.Client/client/framing/ChannelFlowOk.cs index 6e06a26ca5..fc414f7869 100644 --- a/projects/RabbitMQ.Client/client/framing/ChannelFlowOk.cs +++ b/projects/RabbitMQ.Client/client/framing/ChannelFlowOk.cs @@ -55,11 +55,10 @@ public ChannelFlowOk(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ChannelFlowOk; public override string ProtocolMethodName => "channel.flow-ok"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - return WireFormatting.WriteBits(span, _active); + return WireFormatting.WriteBits(ref span.GetStart(), _active); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/ChannelOpen.cs b/projects/RabbitMQ.Client/client/framing/ChannelOpen.cs index 910911a846..cc33d1eb13 100644 --- a/projects/RabbitMQ.Client/client/framing/ChannelOpen.cs +++ b/projects/RabbitMQ.Client/client/framing/ChannelOpen.cs @@ -41,7 +41,6 @@ internal sealed class ChannelOpen : Client.Impl.MethodBase public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ChannelOpen; public override string ProtocolMethodName => "channel.open"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { diff --git a/projects/RabbitMQ.Client/client/framing/ChannelOpenOk.cs b/projects/RabbitMQ.Client/client/framing/ChannelOpenOk.cs index 0d94d7c7d2..c16ec0a52d 100644 --- a/projects/RabbitMQ.Client/client/framing/ChannelOpenOk.cs +++ b/projects/RabbitMQ.Client/client/framing/ChannelOpenOk.cs @@ -41,7 +41,6 @@ internal sealed class ChannelOpenOk : Client.Impl.MethodBase public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ChannelOpenOk; public override string ProtocolMethodName => "channel.open-ok"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { diff --git a/projects/RabbitMQ.Client/client/framing/ConfirmSelect.cs b/projects/RabbitMQ.Client/client/framing/ConfirmSelect.cs index 62d7d32c36..779bd9864a 100644 --- a/projects/RabbitMQ.Client/client/framing/ConfirmSelect.cs +++ b/projects/RabbitMQ.Client/client/framing/ConfirmSelect.cs @@ -55,11 +55,10 @@ public ConfirmSelect(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConfirmSelect; public override string ProtocolMethodName => "confirm.select"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - return WireFormatting.WriteBits(span, _nowait); + return WireFormatting.WriteBits(ref span.GetStart(), _nowait); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/ConfirmSelectOk.cs b/projects/RabbitMQ.Client/client/framing/ConfirmSelectOk.cs index 78f68e6012..eb691ea6d1 100644 --- a/projects/RabbitMQ.Client/client/framing/ConfirmSelectOk.cs +++ b/projects/RabbitMQ.Client/client/framing/ConfirmSelectOk.cs @@ -42,7 +42,6 @@ public ConfirmSelectOk() public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConfirmSelectOk; public override string ProtocolMethodName => "confirm.select-ok"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { diff --git a/projects/RabbitMQ.Client/client/framing/ConnectionBlocked.cs b/projects/RabbitMQ.Client/client/framing/ConnectionBlocked.cs index 2e89e4bb5b..32984ab67b 100644 --- a/projects/RabbitMQ.Client/client/framing/ConnectionBlocked.cs +++ b/projects/RabbitMQ.Client/client/framing/ConnectionBlocked.cs @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------- using System; -using System.Text; + using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; @@ -56,11 +56,10 @@ public ConnectionBlocked(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionBlocked; public override string ProtocolMethodName => "connection.blocked"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - return WireFormatting.WriteShortstr(span, _reason); + return WireFormatting.WriteShortstr(ref span.GetStart(), _reason, span.Length); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/ConnectionClose.cs b/projects/RabbitMQ.Client/client/framing/ConnectionClose.cs index fffdb5eeb4..44e83d79d8 100644 --- a/projects/RabbitMQ.Client/client/framing/ConnectionClose.cs +++ b/projects/RabbitMQ.Client/client/framing/ConnectionClose.cs @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------- using System; -using System.Text; + using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; @@ -65,14 +65,13 @@ public ConnectionClose(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionClose; public override string ProtocolMethodName => "connection.close"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteShort(span, _replyCode); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _replyText); - offset += WireFormatting.WriteShort(span.Slice(offset), _classId); - return offset + WireFormatting.WriteShort(span.Slice(offset), _methodId); + int offset = WireFormatting.WriteShort(ref span.GetStart(), _replyCode); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _replyText, span.Length - offset); + offset += WireFormatting.WriteShort(ref span.GetOffset(offset), _classId); + return offset + WireFormatting.WriteShort(ref span.GetOffset(offset), _methodId); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/ConnectionCloseOk.cs b/projects/RabbitMQ.Client/client/framing/ConnectionCloseOk.cs index 333edc325c..ee274c907f 100644 --- a/projects/RabbitMQ.Client/client/framing/ConnectionCloseOk.cs +++ b/projects/RabbitMQ.Client/client/framing/ConnectionCloseOk.cs @@ -42,7 +42,6 @@ public ConnectionCloseOk() public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionCloseOk; public override string ProtocolMethodName => "connection.close-ok"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { diff --git a/projects/RabbitMQ.Client/client/framing/ConnectionOpen.cs b/projects/RabbitMQ.Client/client/framing/ConnectionOpen.cs index 069a5b5567..6a67822bae 100644 --- a/projects/RabbitMQ.Client/client/framing/ConnectionOpen.cs +++ b/projects/RabbitMQ.Client/client/framing/ConnectionOpen.cs @@ -30,6 +30,7 @@ //--------------------------------------------------------------------------- using System; + using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; @@ -58,11 +59,10 @@ public ConnectionOpen(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionOpen; public override string ProtocolMethodName => "connection.open"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteShortstr(span, _virtualHost); + int offset = WireFormatting.WriteShortstr(ref span.GetStart(), _virtualHost, span.Length); span[offset++] = 0; // _reserved1 span[offset++] = 0; // _reserved2 return offset; diff --git a/projects/RabbitMQ.Client/client/framing/ConnectionOpenOk.cs b/projects/RabbitMQ.Client/client/framing/ConnectionOpenOk.cs index 36b8a10af1..09c77b2913 100644 --- a/projects/RabbitMQ.Client/client/framing/ConnectionOpenOk.cs +++ b/projects/RabbitMQ.Client/client/framing/ConnectionOpenOk.cs @@ -41,7 +41,6 @@ internal sealed class ConnectionOpenOk : Client.Impl.MethodBase public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionOpenOk; public override string ProtocolMethodName => "connection.open-ok"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { diff --git a/projects/RabbitMQ.Client/client/framing/ConnectionSecure.cs b/projects/RabbitMQ.Client/client/framing/ConnectionSecure.cs index 8c20f4be27..54eef04eec 100644 --- a/projects/RabbitMQ.Client/client/framing/ConnectionSecure.cs +++ b/projects/RabbitMQ.Client/client/framing/ConnectionSecure.cs @@ -55,11 +55,10 @@ public ConnectionSecure(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionSecure; public override string ProtocolMethodName => "connection.secure"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - return WireFormatting.WriteLongstr(span, _challenge); + return WireFormatting.WriteLongstr(ref span.GetStart(), _challenge); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/ConnectionSecureOk.cs b/projects/RabbitMQ.Client/client/framing/ConnectionSecureOk.cs index 79cacd4eb9..727063f2e1 100644 --- a/projects/RabbitMQ.Client/client/framing/ConnectionSecureOk.cs +++ b/projects/RabbitMQ.Client/client/framing/ConnectionSecureOk.cs @@ -55,11 +55,10 @@ public ConnectionSecureOk(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionSecureOk; public override string ProtocolMethodName => "connection.secure-ok"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - return WireFormatting.WriteLongstr(span, _response); + return WireFormatting.WriteLongstr(ref span.GetStart(), _response); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/ConnectionStart.cs b/projects/RabbitMQ.Client/client/framing/ConnectionStart.cs index cae6323b00..ce8a46c748 100644 --- a/projects/RabbitMQ.Client/client/framing/ConnectionStart.cs +++ b/projects/RabbitMQ.Client/client/framing/ConnectionStart.cs @@ -31,6 +31,7 @@ using System; using System.Collections.Generic; + using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; @@ -68,15 +69,14 @@ public ConnectionStart(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionStart; public override string ProtocolMethodName => "connection.start"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { span[0] = _versionMajor; span[1] = _versionMinor; - int offset = 2 + WireFormatting.WriteTable(span.Slice(2), (IDictionary)_serverProperties); - offset += WireFormatting.WriteLongstr(span.Slice(offset), _mechanisms); - return offset + WireFormatting.WriteLongstr(span.Slice(offset), _locales); + int offset = 2 + WireFormatting.WriteTable(ref span.GetOffset(2), (IDictionary)_serverProperties, span.Length - 2); + offset += WireFormatting.WriteLongstr(ref span.GetOffset(offset), _mechanisms); + return offset + WireFormatting.WriteLongstr(ref span.GetOffset(offset), _locales); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/ConnectionStartOk.cs b/projects/RabbitMQ.Client/client/framing/ConnectionStartOk.cs index 5dd3648c7c..ec3a512aa6 100644 --- a/projects/RabbitMQ.Client/client/framing/ConnectionStartOk.cs +++ b/projects/RabbitMQ.Client/client/framing/ConnectionStartOk.cs @@ -31,7 +31,7 @@ using System; using System.Collections.Generic; -using System.Text; + using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; @@ -67,19 +67,19 @@ public ConnectionStartOk(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionStartOk; public override string ProtocolMethodName => "connection.start-ok"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteTable(span, _clientProperties); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _mechanism); - offset += WireFormatting.WriteLongstr(span.Slice(offset), _response); - return offset + WireFormatting.WriteShortstr(span.Slice(offset), _locale); + int length = span.Length; + int offset = WireFormatting.WriteTable(ref span.GetStart(), _clientProperties, length); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _mechanism, length - offset); + offset += WireFormatting.WriteLongstr(ref span.GetOffset(offset), _response); + return offset + WireFormatting.WriteShortstr(ref span.GetOffset(offset), _locale, length - offset); } public override int GetRequiredBufferSize() { - int bufferSize = 1 + 4 +1; // bytes for length of _mechanism, length of _response, length of _locale + int bufferSize = 1 + 4 + 1; // bytes for length of _mechanism, length of _response, length of _locale bufferSize += WireFormatting.GetTableByteCount(_clientProperties); // _clientProperties in bytes bufferSize += WireFormatting.GetByteCount(_mechanism); // _mechanism in bytes bufferSize += _response.Length; // _response in bytes diff --git a/projects/RabbitMQ.Client/client/framing/ConnectionTune.cs b/projects/RabbitMQ.Client/client/framing/ConnectionTune.cs index f0f840a01c..d967079381 100644 --- a/projects/RabbitMQ.Client/client/framing/ConnectionTune.cs +++ b/projects/RabbitMQ.Client/client/framing/ConnectionTune.cs @@ -61,13 +61,12 @@ public ConnectionTune(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionTune; public override string ProtocolMethodName => "connection.tune"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteShort(span, _channelMax); - offset += WireFormatting.WriteLong(span.Slice(offset), _frameMax); - return offset + WireFormatting.WriteShort(span.Slice(offset), _heartbeat); + int offset = WireFormatting.WriteShort(ref span.GetStart(), _channelMax); + offset += WireFormatting.WriteLong(ref span.GetOffset(offset), _frameMax); + return offset + WireFormatting.WriteShort(ref span.GetOffset(offset), _heartbeat); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/ConnectionTuneOk.cs b/projects/RabbitMQ.Client/client/framing/ConnectionTuneOk.cs index 42736b205d..f081d0c144 100644 --- a/projects/RabbitMQ.Client/client/framing/ConnectionTuneOk.cs +++ b/projects/RabbitMQ.Client/client/framing/ConnectionTuneOk.cs @@ -61,13 +61,12 @@ public ConnectionTuneOk(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionTuneOk; public override string ProtocolMethodName => "connection.tune-ok"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteShort(span, _channelMax); - offset += WireFormatting.WriteLong(span.Slice(offset), _frameMax); - return offset + WireFormatting.WriteShort(span.Slice(offset), _heartbeat); + int offset = WireFormatting.WriteShort(ref span.GetStart(), _channelMax); + offset += WireFormatting.WriteLong(ref span.GetOffset(offset), _frameMax); + return offset + WireFormatting.WriteShort(ref span.GetOffset(offset), _heartbeat); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/ConnectionUnblocked.cs b/projects/RabbitMQ.Client/client/framing/ConnectionUnblocked.cs index dde99fc9a5..a7fb1965f6 100644 --- a/projects/RabbitMQ.Client/client/framing/ConnectionUnblocked.cs +++ b/projects/RabbitMQ.Client/client/framing/ConnectionUnblocked.cs @@ -42,7 +42,6 @@ public ConnectionUnblocked() public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionUnblocked; public override string ProtocolMethodName => "connection.unblocked"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { diff --git a/projects/RabbitMQ.Client/client/framing/ConnectionUpdateSecret.cs b/projects/RabbitMQ.Client/client/framing/ConnectionUpdateSecret.cs index 8e9de0d221..e763a6bb70 100644 --- a/projects/RabbitMQ.Client/client/framing/ConnectionUpdateSecret.cs +++ b/projects/RabbitMQ.Client/client/framing/ConnectionUpdateSecret.cs @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------- using System; -using System.Text; + using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; @@ -59,12 +59,11 @@ public ConnectionUpdateSecret(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionUpdateSecret; public override string ProtocolMethodName => "connection.update-secret"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteLongstr(span, _newSecret); - return offset + WireFormatting.WriteShortstr(span.Slice(offset), _reason); + int offset = WireFormatting.WriteLongstr(ref span.GetStart(), _newSecret); + return offset + WireFormatting.WriteShortstr(ref span.GetOffset(offset), _reason, span.Length - offset); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/ConnectionUpdateSecretOk.cs b/projects/RabbitMQ.Client/client/framing/ConnectionUpdateSecretOk.cs index 3e377c206f..a3438cc6c1 100644 --- a/projects/RabbitMQ.Client/client/framing/ConnectionUpdateSecretOk.cs +++ b/projects/RabbitMQ.Client/client/framing/ConnectionUpdateSecretOk.cs @@ -42,7 +42,6 @@ public ConnectionUpdateSecretOk() public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionUpdateSecretOk; public override string ProtocolMethodName => "connection.update-secret-ok"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { diff --git a/projects/RabbitMQ.Client/client/framing/ExchangeBind.cs b/projects/RabbitMQ.Client/client/framing/ExchangeBind.cs index 6c3423adca..54041964b9 100644 --- a/projects/RabbitMQ.Client/client/framing/ExchangeBind.cs +++ b/projects/RabbitMQ.Client/client/framing/ExchangeBind.cs @@ -31,6 +31,7 @@ using System; using System.Collections.Generic; + using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; @@ -72,16 +73,16 @@ public ExchangeBind(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ExchangeBind; public override string ProtocolMethodName => "exchange.bind"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteShort(span, default); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _destination); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _source); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _routingKey); - offset += WireFormatting.WriteBits(span.Slice(offset), _nowait); - return offset + WireFormatting.WriteTable(span.Slice(offset), _arguments); + int length = span.Length; + int offset = WireFormatting.WriteShort(ref span.GetStart(), default); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _destination, length - offset); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _source, length - offset); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _routingKey, length - offset); + offset += WireFormatting.WriteBits(ref span.GetOffset(offset), _nowait); + return offset + WireFormatting.WriteTable(ref span.GetOffset(offset), _arguments, length - offset); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/ExchangeBindOk.cs b/projects/RabbitMQ.Client/client/framing/ExchangeBindOk.cs index 04b7eacbc5..78ab2ad313 100644 --- a/projects/RabbitMQ.Client/client/framing/ExchangeBindOk.cs +++ b/projects/RabbitMQ.Client/client/framing/ExchangeBindOk.cs @@ -42,7 +42,6 @@ public ExchangeBindOk() public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ExchangeBindOk; public override string ProtocolMethodName => "exchange.bind-ok"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { diff --git a/projects/RabbitMQ.Client/client/framing/ExchangeDeclare.cs b/projects/RabbitMQ.Client/client/framing/ExchangeDeclare.cs index 2d7abc879f..4d044b7f9f 100644 --- a/projects/RabbitMQ.Client/client/framing/ExchangeDeclare.cs +++ b/projects/RabbitMQ.Client/client/framing/ExchangeDeclare.cs @@ -31,6 +31,7 @@ using System; using System.Collections.Generic; + using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; @@ -77,15 +78,15 @@ public ExchangeDeclare(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ExchangeDeclare; public override string ProtocolMethodName => "exchange.declare"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteShort(span, default); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _exchange); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _type); - offset += WireFormatting.WriteBits(span.Slice(offset), _passive, _durable, _autoDelete, _internal, _nowait); - return offset + WireFormatting.WriteTable(span.Slice(offset), _arguments); + int length = span.Length; + int offset = WireFormatting.WriteShort(ref span.GetStart(), default); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _exchange, length - offset); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _type, length - offset); + offset += WireFormatting.WriteBits(ref span.GetOffset(offset), _passive, _durable, _autoDelete, _internal, _nowait); + return offset + WireFormatting.WriteTable(ref span.GetOffset(offset), _arguments, length - offset); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/ExchangeDeclareOk.cs b/projects/RabbitMQ.Client/client/framing/ExchangeDeclareOk.cs index 03921f2220..b04a6848cd 100644 --- a/projects/RabbitMQ.Client/client/framing/ExchangeDeclareOk.cs +++ b/projects/RabbitMQ.Client/client/framing/ExchangeDeclareOk.cs @@ -42,7 +42,6 @@ public ExchangeDeclareOk() public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ExchangeDeclareOk; public override string ProtocolMethodName => "exchange.declare-ok"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { diff --git a/projects/RabbitMQ.Client/client/framing/ExchangeDelete.cs b/projects/RabbitMQ.Client/client/framing/ExchangeDelete.cs index 67110e2818..6ca89c7cc9 100644 --- a/projects/RabbitMQ.Client/client/framing/ExchangeDelete.cs +++ b/projects/RabbitMQ.Client/client/framing/ExchangeDelete.cs @@ -30,6 +30,7 @@ //--------------------------------------------------------------------------- using System; + using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; @@ -63,13 +64,12 @@ public ExchangeDelete(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ExchangeDelete; public override string ProtocolMethodName => "exchange.delete"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteShort(span, default); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _exchange); - return offset + WireFormatting.WriteBits(span.Slice(offset), _ifUnused, _nowait); + int offset = WireFormatting.WriteShort(ref span.GetStart(), default); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _exchange, span.Length - offset); + return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _ifUnused, _nowait); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/ExchangeDeleteOk.cs b/projects/RabbitMQ.Client/client/framing/ExchangeDeleteOk.cs index 106d4f2d82..316dfc19f7 100644 --- a/projects/RabbitMQ.Client/client/framing/ExchangeDeleteOk.cs +++ b/projects/RabbitMQ.Client/client/framing/ExchangeDeleteOk.cs @@ -42,7 +42,6 @@ public ExchangeDeleteOk() public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ExchangeDeleteOk; public override string ProtocolMethodName => "exchange.delete-ok"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { diff --git a/projects/RabbitMQ.Client/client/framing/ExchangeUnbind.cs b/projects/RabbitMQ.Client/client/framing/ExchangeUnbind.cs index b47c6a4e26..817448b957 100644 --- a/projects/RabbitMQ.Client/client/framing/ExchangeUnbind.cs +++ b/projects/RabbitMQ.Client/client/framing/ExchangeUnbind.cs @@ -31,6 +31,7 @@ using System; using System.Collections.Generic; + using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; @@ -72,16 +73,15 @@ public ExchangeUnbind(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ExchangeUnbind; public override string ProtocolMethodName => "exchange.unbind"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteShort(span, default); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _destination); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _source); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _routingKey); - offset += WireFormatting.WriteBits(span.Slice(offset), _nowait); - return offset + WireFormatting.WriteTable(span.Slice(offset), _arguments); + int offset = WireFormatting.WriteShort(ref span.GetStart(), default); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _destination, span.Length - offset); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _source, span.Length - offset); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _routingKey, span.Length - offset); + offset += WireFormatting.WriteBits(ref span.GetOffset(offset), _nowait); + return offset + WireFormatting.WriteTable(ref span.GetOffset(offset), _arguments, span.Length - offset); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/ExchangeUnbindOk.cs b/projects/RabbitMQ.Client/client/framing/ExchangeUnbindOk.cs index b195002955..51aaca007d 100644 --- a/projects/RabbitMQ.Client/client/framing/ExchangeUnbindOk.cs +++ b/projects/RabbitMQ.Client/client/framing/ExchangeUnbindOk.cs @@ -42,7 +42,6 @@ public ExchangeUnbindOk() public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ExchangeUnbindOk; public override string ProtocolMethodName => "exchange.unbind-ok"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { diff --git a/projects/RabbitMQ.Client/client/framing/QueueBind.cs b/projects/RabbitMQ.Client/client/framing/QueueBind.cs index 80c1614e08..0625ce7999 100644 --- a/projects/RabbitMQ.Client/client/framing/QueueBind.cs +++ b/projects/RabbitMQ.Client/client/framing/QueueBind.cs @@ -31,6 +31,7 @@ using System; using System.Collections.Generic; + using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; @@ -72,16 +73,15 @@ public QueueBind(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.QueueBind; public override string ProtocolMethodName => "queue.bind"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteShort(span, default); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _queue); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _exchange); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _routingKey); - offset += WireFormatting.WriteBits(span.Slice(offset), _nowait); - return offset + WireFormatting.WriteTable(span.Slice(offset), _arguments); + int offset = WireFormatting.WriteShort(ref span.GetStart(), default); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _queue, span.Length - offset); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _exchange, span.Length - offset); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _routingKey, span.Length - offset); + offset += WireFormatting.WriteBits(ref span.GetOffset(offset), _nowait); + return offset + WireFormatting.WriteTable(ref span.GetOffset(offset), _arguments, span.Length - offset); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/QueueBindOk.cs b/projects/RabbitMQ.Client/client/framing/QueueBindOk.cs index 660462c2b8..07e8c30a2d 100644 --- a/projects/RabbitMQ.Client/client/framing/QueueBindOk.cs +++ b/projects/RabbitMQ.Client/client/framing/QueueBindOk.cs @@ -42,7 +42,6 @@ public QueueBindOk() public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.QueueBindOk; public override string ProtocolMethodName => "queue.bind-ok"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { diff --git a/projects/RabbitMQ.Client/client/framing/QueueDeclare.cs b/projects/RabbitMQ.Client/client/framing/QueueDeclare.cs index e7c994b668..e2ed6b25d9 100644 --- a/projects/RabbitMQ.Client/client/framing/QueueDeclare.cs +++ b/projects/RabbitMQ.Client/client/framing/QueueDeclare.cs @@ -31,6 +31,7 @@ using System; using System.Collections.Generic; + using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; @@ -67,21 +68,20 @@ public QueueDeclare(ReadOnlySpan span) { int offset = 2; offset += WireFormatting.ReadShortstr(span.Slice(offset), out _queue); - offset += WireFormatting.ReadBits(span.Slice(offset), out _passive, out _durable, out _exclusive, out _autoDelete, out _nowait); + offset += WireFormatting.ReadBits(span.Slice(offset), out _passive, out _durable, out _exclusive, out _autoDelete, out _nowait); WireFormatting.ReadDictionary(span.Slice(offset), out var tmpDictionary); _arguments = tmpDictionary; } public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.QueueDeclare; public override string ProtocolMethodName => "queue.declare"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteShort(span, default); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _queue); - offset += WireFormatting.WriteBits(span.Slice(offset), _passive, _durable, _exclusive, _autoDelete, _nowait); - return offset + WireFormatting.WriteTable(span.Slice(offset), _arguments); + int offset = WireFormatting.WriteShort(ref span.GetStart(), default); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _queue, span.Length - offset); + offset += WireFormatting.WriteBits(ref span.GetOffset(offset), _passive, _durable, _exclusive, _autoDelete, _nowait); + return offset + WireFormatting.WriteTable(ref span.GetOffset(offset), _arguments, span.Length - offset); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/QueueDeclareOk.cs b/projects/RabbitMQ.Client/client/framing/QueueDeclareOk.cs index 41746a15a1..6bc70059d2 100644 --- a/projects/RabbitMQ.Client/client/framing/QueueDeclareOk.cs +++ b/projects/RabbitMQ.Client/client/framing/QueueDeclareOk.cs @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------- using System; -using System.Text; + using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; @@ -62,13 +62,12 @@ public QueueDeclareOk(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.QueueDeclareOk; public override string ProtocolMethodName => "queue.declare-ok"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteShortstr(span, _queue); - offset += WireFormatting.WriteLong(span.Slice(offset), _messageCount); - return offset + WireFormatting.WriteLong(span.Slice(offset), _consumerCount); + int offset = WireFormatting.WriteShortstr(ref span.GetStart(), _queue, span.Length); + offset += WireFormatting.WriteLong(ref span.GetOffset(offset), _messageCount); + return offset + WireFormatting.WriteLong(ref span.GetOffset(offset), _consumerCount); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/QueueDelete.cs b/projects/RabbitMQ.Client/client/framing/QueueDelete.cs index 31c6962fb8..1ac8641cf3 100644 --- a/projects/RabbitMQ.Client/client/framing/QueueDelete.cs +++ b/projects/RabbitMQ.Client/client/framing/QueueDelete.cs @@ -30,6 +30,7 @@ //--------------------------------------------------------------------------- using System; + using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; @@ -65,13 +66,12 @@ public QueueDelete(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.QueueDelete; public override string ProtocolMethodName => "queue.delete"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteShort(span, default); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _queue); - return offset + WireFormatting.WriteBits(span.Slice(offset), _ifUnused, _ifEmpty, _nowait); + int offset = WireFormatting.WriteShort(ref span.GetStart(), default); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _queue, span.Length - offset); + return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _ifUnused, _ifEmpty, _nowait); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/QueueDeleteOk.cs b/projects/RabbitMQ.Client/client/framing/QueueDeleteOk.cs index 00ee2d4b3f..c99d008a95 100644 --- a/projects/RabbitMQ.Client/client/framing/QueueDeleteOk.cs +++ b/projects/RabbitMQ.Client/client/framing/QueueDeleteOk.cs @@ -55,11 +55,10 @@ public QueueDeleteOk(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.QueueDeleteOk; public override string ProtocolMethodName => "queue.delete-ok"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - return WireFormatting.WriteLong(span, _messageCount); + return WireFormatting.WriteLong(ref span.GetStart(), _messageCount); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/QueuePurge.cs b/projects/RabbitMQ.Client/client/framing/QueuePurge.cs index 4cf7390732..ea53c50f1a 100644 --- a/projects/RabbitMQ.Client/client/framing/QueuePurge.cs +++ b/projects/RabbitMQ.Client/client/framing/QueuePurge.cs @@ -30,6 +30,7 @@ //--------------------------------------------------------------------------- using System; + using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; @@ -61,13 +62,12 @@ public QueuePurge(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.QueuePurge; public override string ProtocolMethodName => "queue.purge"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteShort(span, default); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _queue); - return offset + WireFormatting.WriteBits(span.Slice(offset), _nowait); + int offset = WireFormatting.WriteShort(ref span.GetStart(), default); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _queue, span.Length - offset); + return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _nowait); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/QueuePurgeOk.cs b/projects/RabbitMQ.Client/client/framing/QueuePurgeOk.cs index 3c7aeec20a..68f4d9764a 100644 --- a/projects/RabbitMQ.Client/client/framing/QueuePurgeOk.cs +++ b/projects/RabbitMQ.Client/client/framing/QueuePurgeOk.cs @@ -55,11 +55,10 @@ public QueuePurgeOk(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.QueuePurgeOk; public override string ProtocolMethodName => "queue.purge-ok"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - return WireFormatting.WriteLong(span, _messageCount); + return WireFormatting.WriteLong(ref span.GetStart(), _messageCount); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/QueueUnbind.cs b/projects/RabbitMQ.Client/client/framing/QueueUnbind.cs index 3e0a6bf7b2..1ed85037ed 100644 --- a/projects/RabbitMQ.Client/client/framing/QueueUnbind.cs +++ b/projects/RabbitMQ.Client/client/framing/QueueUnbind.cs @@ -31,6 +31,7 @@ using System; using System.Collections.Generic; + using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; @@ -69,15 +70,14 @@ public QueueUnbind(ReadOnlySpan span) public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.QueueUnbind; public override string ProtocolMethodName => "queue.unbind"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { - int offset = WireFormatting.WriteShort(span, default); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _queue); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _exchange); - offset += WireFormatting.WriteShortstr(span.Slice(offset), _routingKey); - return offset + WireFormatting.WriteTable(span.Slice(offset), _arguments); + int offset = WireFormatting.WriteShort(ref span.GetStart(), default); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _queue, span.Length - offset); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _exchange, span.Length - offset); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _routingKey, span.Length - offset); + return offset + WireFormatting.WriteTable(ref span.GetOffset(offset), _arguments, span.Length - offset); } public override int GetRequiredBufferSize() diff --git a/projects/RabbitMQ.Client/client/framing/QueueUnbindOk.cs b/projects/RabbitMQ.Client/client/framing/QueueUnbindOk.cs index 026a5b90ce..a755607167 100644 --- a/projects/RabbitMQ.Client/client/framing/QueueUnbindOk.cs +++ b/projects/RabbitMQ.Client/client/framing/QueueUnbindOk.cs @@ -42,7 +42,6 @@ public QueueUnbindOk() public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.QueueUnbindOk; public override string ProtocolMethodName => "queue.unbind-ok"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { diff --git a/projects/RabbitMQ.Client/client/framing/TxCommit.cs b/projects/RabbitMQ.Client/client/framing/TxCommit.cs index fdd8d67f4f..45763f32b3 100644 --- a/projects/RabbitMQ.Client/client/framing/TxCommit.cs +++ b/projects/RabbitMQ.Client/client/framing/TxCommit.cs @@ -42,7 +42,6 @@ public TxCommit() public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.TxCommit; public override string ProtocolMethodName => "tx.commit"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { diff --git a/projects/RabbitMQ.Client/client/framing/TxCommitOk.cs b/projects/RabbitMQ.Client/client/framing/TxCommitOk.cs index 68c548734c..0eb801aa14 100644 --- a/projects/RabbitMQ.Client/client/framing/TxCommitOk.cs +++ b/projects/RabbitMQ.Client/client/framing/TxCommitOk.cs @@ -42,7 +42,6 @@ public TxCommitOk() public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.TxCommitOk; public override string ProtocolMethodName => "tx.commit-ok"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { diff --git a/projects/RabbitMQ.Client/client/framing/TxRollback.cs b/projects/RabbitMQ.Client/client/framing/TxRollback.cs index a713c67dac..776c4abfa5 100644 --- a/projects/RabbitMQ.Client/client/framing/TxRollback.cs +++ b/projects/RabbitMQ.Client/client/framing/TxRollback.cs @@ -42,7 +42,6 @@ public TxRollback() public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.TxRollback; public override string ProtocolMethodName => "tx.rollback"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { diff --git a/projects/RabbitMQ.Client/client/framing/TxRollbackOk.cs b/projects/RabbitMQ.Client/client/framing/TxRollbackOk.cs index c447a6c0f2..eb613dc005 100644 --- a/projects/RabbitMQ.Client/client/framing/TxRollbackOk.cs +++ b/projects/RabbitMQ.Client/client/framing/TxRollbackOk.cs @@ -42,7 +42,6 @@ public TxRollbackOk() public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.TxRollbackOk; public override string ProtocolMethodName => "tx.rollback-ok"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { diff --git a/projects/RabbitMQ.Client/client/framing/TxSelect.cs b/projects/RabbitMQ.Client/client/framing/TxSelect.cs index 8d518d400a..4e15dc029f 100644 --- a/projects/RabbitMQ.Client/client/framing/TxSelect.cs +++ b/projects/RabbitMQ.Client/client/framing/TxSelect.cs @@ -42,7 +42,6 @@ public TxSelect() public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.TxSelect; public override string ProtocolMethodName => "tx.select"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { diff --git a/projects/RabbitMQ.Client/client/framing/TxSelectOk.cs b/projects/RabbitMQ.Client/client/framing/TxSelectOk.cs index 01fd55dc96..1f55a2a0e9 100644 --- a/projects/RabbitMQ.Client/client/framing/TxSelectOk.cs +++ b/projects/RabbitMQ.Client/client/framing/TxSelectOk.cs @@ -42,7 +42,6 @@ public TxSelectOk() public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.TxSelectOk; public override string ProtocolMethodName => "tx.select-ok"; - public override bool HasContent => false; public override int WriteArgumentsTo(Span span) { diff --git a/projects/RabbitMQ.Client/client/impl/CommandAssembler.cs b/projects/RabbitMQ.Client/client/impl/CommandAssembler.cs index 5ae65d8193..bf5fbc7373 100644 --- a/projects/RabbitMQ.Client/client/impl/CommandAssembler.cs +++ b/projects/RabbitMQ.Client/client/impl/CommandAssembler.cs @@ -104,7 +104,7 @@ private void ParseMethodFrame(in InboundFrame frame) } _method = _protocol.DecodeMethodFrom(frame.Payload.Span); - _state = _method.HasContent ? AssemblyState.ExpectingContentHeader : AssemblyState.Complete; + _state = _method.ProtocolCommandId.HasContent() ? AssemblyState.ExpectingContentHeader : AssemblyState.Complete; } private void ParseHeaderFrame(in InboundFrame frame) diff --git a/projects/RabbitMQ.Client/client/impl/Frame.cs b/projects/RabbitMQ.Client/client/impl/Frame.cs index a41a62f2ca..02a23d814f 100644 --- a/projects/RabbitMQ.Client/client/impl/Frame.cs +++ b/projects/RabbitMQ.Client/client/impl/Frame.cs @@ -72,8 +72,8 @@ public static int WriteTo(Span span, ushort channel, T method) where T const int StartMethodArguments = StartClassId + 4; int payloadLength = method.WriteArgumentsTo(span.Slice(StartMethodArguments)) + 4; - NetworkOrderSerializer.WriteUInt64(span, ((ulong)Constants.FrameMethod << 56) | ((ulong)channel << 40) | ((ulong)payloadLength << 8)); - NetworkOrderSerializer.WriteUInt32(span.Slice(StartClassId), (uint)method.ProtocolCommandId); + NetworkOrderSerializer.WriteUInt64(ref span.GetStart(), ((ulong)Constants.FrameMethod << 56) | ((ulong)channel << 40) | ((ulong)payloadLength << 8)); + NetworkOrderSerializer.WriteUInt32(ref span.GetOffset(StartClassId), (uint)method.ProtocolCommandId); span[payloadLength + StartPayload] = Constants.FrameEnd; return payloadLength + BaseFrameSize; } @@ -96,9 +96,9 @@ public static int WriteTo(Span span, ushort channel, T header, int body const int StartHeaderArguments = StartPayload + 12; int payloadLength = 12 + header.WritePropertiesTo(span.Slice(StartHeaderArguments)); - NetworkOrderSerializer.WriteUInt64(span, ((ulong)Constants.FrameHeader << 56) | ((ulong)channel << 40) | ((ulong)payloadLength << 8)); - NetworkOrderSerializer.WriteUInt32(span.Slice(StartClassId), (uint)header.ProtocolClassId << 16); // The last 16 bytes (Weight) aren't used - NetworkOrderSerializer.WriteUInt64(span.Slice(StartBodyLength), (ulong)bodyLength); + NetworkOrderSerializer.WriteUInt64(ref span.GetStart(), ((ulong)Constants.FrameHeader << 56) | ((ulong)channel << 40) | ((ulong)payloadLength << 8)); + NetworkOrderSerializer.WriteUInt32(ref span.GetOffset(StartClassId), (uint)header.ProtocolClassId << 16); // The last 16 bytes (Weight) aren't used + NetworkOrderSerializer.WriteUInt64(ref span.GetOffset(StartBodyLength), (ulong)bodyLength); span[payloadLength + StartPayload] = Constants.FrameEnd; return payloadLength + BaseFrameSize; } @@ -117,7 +117,7 @@ internal static class BodySegment public static int WriteTo(Span span, ushort channel, ReadOnlySpan body) { const int StartBodyArgument = StartPayload; - NetworkOrderSerializer.WriteUInt64(span, ((ulong)Constants.FrameBody << 56) | ((ulong)channel << 40) | ((ulong)body.Length << 8)); + NetworkOrderSerializer.WriteUInt64(ref span.GetStart(), ((ulong)Constants.FrameBody << 56) | ((ulong)channel << 40) | ((ulong)body.Length << 8)); body.CopyTo(span.Slice(StartBodyArgument)); span[StartPayload + body.Length] = Constants.FrameEnd; return body.Length + BaseFrameSize; @@ -227,8 +227,9 @@ internal static InboundFrame ReadFrom(Stream reader, byte[] frameHeaderBuffer) } FrameType type = (FrameType)firstByte; - int channel = NetworkOrderDeserializer.ReadUInt16(new ReadOnlySpan(frameHeaderBuffer, 1, 2)); - int payloadSize = NetworkOrderDeserializer.ReadInt32(new ReadOnlySpan(frameHeaderBuffer, 3, 4)); // FIXME - throw exn on unreasonable value + var frameHeaderSpan = new ReadOnlySpan(frameHeaderBuffer, 1, 6); + int channel = NetworkOrderDeserializer.ReadUInt16(frameHeaderSpan); + int payloadSize = NetworkOrderDeserializer.ReadInt32(frameHeaderSpan.Slice(2, 4)); // FIXME - throw exn on unreasonable value const int EndMarkerLength = 1; // Is returned by InboundFrame.ReturnPayload in Connection.MainLoopIteration diff --git a/projects/RabbitMQ.Client/client/impl/MethodBase.cs b/projects/RabbitMQ.Client/client/impl/MethodBase.cs index 7384df3963..903bbb5360 100644 --- a/projects/RabbitMQ.Client/client/impl/MethodBase.cs +++ b/projects/RabbitMQ.Client/client/impl/MethodBase.cs @@ -30,14 +30,13 @@ //--------------------------------------------------------------------------- using System; + using RabbitMQ.Client.client.framing; namespace RabbitMQ.Client.Impl { internal abstract class MethodBase { - public abstract bool HasContent { get; } - public abstract ProtocolCommandId ProtocolCommandId { get; } /// @@ -58,4 +57,20 @@ internal abstract class MethodBase public abstract int WriteArgumentsTo(Span span); public abstract int GetRequiredBufferSize(); } + + internal static class ProtocolCommandIdExtensions + { + public static bool HasContent(this ProtocolCommandId commandId) + { + switch (commandId) + { + case ProtocolCommandId.BasicDeliver: + case ProtocolCommandId.BasicGetOk: + case ProtocolCommandId.BasicReturn: + return true; + default: + return false; + } + } + } } diff --git a/projects/RabbitMQ.Client/client/impl/WireFormatting.Read.cs b/projects/RabbitMQ.Client/client/impl/WireFormatting.Read.cs new file mode 100644 index 0000000000..610459c866 --- /dev/null +++ b/projects/RabbitMQ.Client/client/impl/WireFormatting.Read.cs @@ -0,0 +1,334 @@ +// This source code is dual-licensed under the Apache License, version +// 2.0, and the Mozilla Public License, version 2.0. +// +// The APL v2.0: +// +//--------------------------------------------------------------------------- +// Copyright (c) 2007-2020 VMware, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//--------------------------------------------------------------------------- +// +// The MPL v2.0: +// +//--------------------------------------------------------------------------- +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. +// +// Copyright (c) 2007-2020 VMware, Inc. All rights reserved. +//--------------------------------------------------------------------------- + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +using RabbitMQ.Client.Exceptions; +using RabbitMQ.Util; + +namespace RabbitMQ.Client.Impl +{ + internal static partial class WireFormatting + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static decimal ReadDecimal(ReadOnlySpan span) + { + byte scale = span[0]; + if (scale > 28) + { + ThrowInvalidDecimalScale(scale); + } + + uint unsignedMantissa = NetworkOrderDeserializer.ReadUInt32(span.Slice(1)); + var data = new DecimalData(((uint)(scale << 16)) | unsignedMantissa & 0x80000000, 0, unsignedMantissa & 0x7FFFFFFF, 0); + return Unsafe.As(ref data); + } + + public static IList ReadArray(ReadOnlySpan span, out int bytesRead) + { + bytesRead = 4; + long arrayLength = NetworkOrderDeserializer.ReadUInt32(span); + if (arrayLength == 0) + { + return null; + } + List array = new List(); + while (bytesRead - 4 < arrayLength) + { + array.Add(ReadFieldValue(span.Slice(bytesRead), out int fieldValueBytesRead)); + bytesRead += fieldValueBytesRead; + } + + return array; + } + + public static object ReadFieldValue(ReadOnlySpan span, out int bytesRead) + { + switch ((char)span[0]) + { + case 'S': + bytesRead = 1 + ReadLongstr(span.Slice(1), out var bytes); + return bytes; + case 't': + bytesRead = 2; + return span[1] != 0 ? TrueBoolean : FalseBoolean; + case 'I': + bytesRead = 5; + return NetworkOrderDeserializer.ReadInt32(span.Slice(1)); + case 'V': + bytesRead = 1; + return null; + default: + return ReadFieldValueSlow(span, out bytesRead); + } + + // Moved out of outer switch to have a shorter main method (improves performance) + static object ReadFieldValueSlow(ReadOnlySpan span, out int bytesRead) + { + var slice = span.Slice(1); + switch ((char)span[0]) + { + case 'F': + bytesRead = 1 + ReadDictionary(slice, out var dictionary); + return dictionary; + case 'A': + IList arrayResult = ReadArray(slice, out int arrayBytesRead); + bytesRead = 1 + arrayBytesRead; + return arrayResult; + case 'l': + bytesRead = 9; + return NetworkOrderDeserializer.ReadInt64(slice); + case 'i': + bytesRead = 5; + return NetworkOrderDeserializer.ReadUInt32(slice); + case 'D': + bytesRead = 6; + return ReadDecimal(slice); + case 'B': + bytesRead = 2; + return span[1]; + case 'b': + bytesRead = 2; + return (sbyte)span[1]; + case 'd': + bytesRead = 9; + return NetworkOrderDeserializer.ReadDouble(slice); + case 'f': + bytesRead = 5; + return NetworkOrderDeserializer.ReadSingle(slice); + case 's': + bytesRead = 3; + return NetworkOrderDeserializer.ReadInt16(slice); + case 'T': + bytesRead = 1 + ReadTimestamp(slice, out var timestamp); + return timestamp; + case 'x': + bytesRead = 1 + ReadLongstr(slice, out var binaryTableResult); + return new BinaryTableValue(binaryTableResult); + default: + bytesRead = 0; + return ThrowInvalidTableValue((char)span[0]); + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReadLongstr(ReadOnlySpan span, out byte[] value) + { + uint byteCount = NetworkOrderDeserializer.ReadUInt32(span); + if (byteCount > int.MaxValue) + { + value = null; + return ThrowSyntaxErrorException(byteCount); + } + + value = span.Slice(4, (int)byteCount).ToArray(); + return 4 + value.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReadShortstr(ReadOnlySpan span, out string value) + { + int byteCount = span[0]; + if (byteCount == 0) + { + value = string.Empty; + return 1; + } + + // equals span.Length >= byteCount + 1 + if (span.Length > byteCount) + { +#if NETCOREAPP + value = UTF8.GetString(span.Slice(1, byteCount)); +#else + unsafe + { + fixed (byte* bytes = span.Slice(1)) + { + value = UTF8.GetString(bytes, byteCount); + } + } + +#endif + return 1 + byteCount; + } + + value = string.Empty; + return ThrowArgumentOutOfRangeException(span.Length, byteCount + 1); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReadBits(ReadOnlySpan span, out bool val) + { + val = (span[0] & 0b0000_0001) != 0; + return 1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReadBits(ReadOnlySpan span, out bool val1, out bool val2) + { + byte bits = span[0]; + val1 = (bits & 0b0000_0001) != 0; + val2 = (bits & 0b0000_0010) != 0; + return 1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReadBits(ReadOnlySpan span, out bool val1, out bool val2, out bool val3) + { + byte bits = span[0]; + val1 = (bits & 0b0000_0001) != 0; + val2 = (bits & 0b0000_0010) != 0; + val3 = (bits & 0b0000_0100) != 0; + return 1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReadBits(ReadOnlySpan span, out bool val1, out bool val2, out bool val3, out bool val4) + { + byte bits = span[0]; + val1 = (bits & 0b0000_0001) != 0; + val2 = (bits & 0b0000_0010) != 0; + val3 = (bits & 0b0000_0100) != 0; + val4 = (bits & 0b0000_1000) != 0; + return 1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReadBits(ReadOnlySpan span, out bool val1, out bool val2, out bool val3, out bool val4, out bool val5) + { + byte bits = span[0]; + val1 = (bits & 0b0000_0001) != 0; + val2 = (bits & 0b0000_0010) != 0; + val3 = (bits & 0b0000_0100) != 0; + val4 = (bits & 0b0000_1000) != 0; + val5 = (bits & 0b0001_0000) != 0; + return 1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReadBits(ReadOnlySpan span, + out bool val1, out bool val2, out bool val3, out bool val4, out bool val5, + out bool val6, out bool val7, out bool val8, out bool val9, out bool val10, + out bool val11, out bool val12, out bool val13, out bool val14) + { + byte bits = span[0]; + val1 = (bits & 0b1000_0000) != 0; + val2 = (bits & 0b0100_0000) != 0; + val3 = (bits & 0b0010_0000) != 0; + val4 = (bits & 0b0001_0000) != 0; + val5 = (bits & 0b0000_1000) != 0; + val6 = (bits & 0b0000_0100) != 0; + val7 = (bits & 0b0000_0010) != 0; + val8 = (bits & 0b0000_0001) != 0; + bits = span[1]; + val9 = (bits & 0b1000_0000) != 0; + val10 = (bits & 0b0100_0000) != 0; + val11 = (bits & 0b0010_0000) != 0; + val12 = (bits & 0b0001_0000) != 0; + val13 = (bits & 0b0000_1000) != 0; + val14 = (bits & 0b0000_0100) != 0; + return 2; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReadShort(ReadOnlySpan span, out ushort value) + { + value = NetworkOrderDeserializer.ReadUInt16(span); + return 2; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReadLong(ReadOnlySpan span, out uint value) + { + value = NetworkOrderDeserializer.ReadUInt32(span); + return 4; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReadLonglong(ReadOnlySpan span, out ulong value) + { + value = NetworkOrderDeserializer.ReadUInt64(span); + return 8; + } + + ///Reads an AMQP "table" definition from the reader. + /// + /// Supports the AMQP 0-8/0-9 standard entry types S, I, D, T + /// and F, as well as the QPid-0-8 specific b, d, f, l, s, t, + /// x and V types and the AMQP 0-9-1 A type. + /// + /// A . + public static int ReadDictionary(ReadOnlySpan span, out Dictionary valueDictionary) + { + long tableLength = NetworkOrderDeserializer.ReadUInt32(span); + if (tableLength == 0) + { + valueDictionary = null; + return 4; + } + + span = span.Slice(4); + valueDictionary = new Dictionary(); + int bytesRead = 0; + while (bytesRead < tableLength) + { + bytesRead += ReadShortstr(span.Slice(bytesRead), out string key); + valueDictionary[key] = ReadFieldValue(span.Slice(bytesRead), out int valueBytesRead); + bytesRead += valueBytesRead; + } + + return 4 + bytesRead; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReadTimestamp(ReadOnlySpan span, out AmqpTimestamp value) + { + // 0-9 is afaict silent on the signedness of the timestamp. + // See also MethodArgumentWriter.WriteTimestamp and AmqpTimestamp itself + value = new AmqpTimestamp((long)NetworkOrderDeserializer.ReadUInt64(span)); + return 8; + } + + public static int ThrowSyntaxErrorException(uint byteCount) + => throw new SyntaxErrorException($"Long string too long; byte length={byteCount}, max={int.MaxValue}"); + + private static int ThrowInvalidTableValue(char type) + => throw new SyntaxErrorException($"Unrecognised type in table: {type}"); + + private static decimal ThrowInvalidDecimalScale(int scale) + => throw new SyntaxErrorException($"Unrepresentable AMQP decimal table field: scale={scale}"); + } +} diff --git a/projects/RabbitMQ.Client/client/impl/WireFormatting.Write.cs b/projects/RabbitMQ.Client/client/impl/WireFormatting.Write.cs new file mode 100644 index 0000000000..00aa278da7 --- /dev/null +++ b/projects/RabbitMQ.Client/client/impl/WireFormatting.Write.cs @@ -0,0 +1,515 @@ +// This source code is dual-licensed under the Apache License, version +// 2.0, and the Mozilla Public License, version 2.0. +// +// The APL v2.0: +// +//--------------------------------------------------------------------------- +// Copyright (c) 2007-2020 VMware, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//--------------------------------------------------------------------------- +// +// The MPL v2.0: +// +//--------------------------------------------------------------------------- +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. +// +// Copyright (c) 2007-2020 VMware, Inc. All rights reserved. +//--------------------------------------------------------------------------- + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +using RabbitMQ.Client.Exceptions; +using RabbitMQ.Util; + +namespace RabbitMQ.Client.Impl +{ + internal static partial class WireFormatting + { + public static int WriteArray(ref byte destination, IList val, int bytesRemaining) + { + if (val is null || val.Count == 0) + { + NetworkOrderSerializer.WriteUInt32(ref destination, 0); + return 4; + } + + int bytesWritten = 4; + for (int index = 0; index < val.Count; index++) + { + bytesWritten += WriteFieldValue(ref destination.GetOffset(bytesWritten), val[index], bytesRemaining - bytesWritten); + } + + NetworkOrderSerializer.WriteUInt32(ref destination, (uint)bytesWritten - 4u); + return bytesWritten; + } + + public static int GetArrayByteCount(IList val) + { + if (val is null || val.Count == 0) + { + return 4; + } + + int byteCount = 4; + if (val is List valList) + { + for (int index = 0; index < valList.Count; index++) + { + byteCount += GetFieldValueByteCount(valList[index]); + } + } + else + { + for (int index = 0; index < val.Count; index++) + { + byteCount += GetFieldValueByteCount(val[index]); + } + } + + return byteCount; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#if NETCOREAPP + public static int GetByteCount(ReadOnlySpan val) => val.IsEmpty ? 0 : UTF8.GetByteCount(val); +#else + public static int GetByteCount(string val) => string.IsNullOrEmpty(val) ? 0 : UTF8.GetByteCount(val); +#endif + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteDecimal(ref byte destination, decimal value) + { + // Cast the decimal to our struct to avoid the decimal.GetBits allocations. + DecimalData data = Unsafe.As(ref value); + // According to the documentation :- + // - word 0: low-order "mantissa" + // - word 1, word 2: medium- and high-order "mantissa" + // - word 3: mostly reserved; "exponent" and sign bit + // In one way, this is broader than AMQP: the mantissa is larger. + // In another way, smaller: the exponent ranges 0-28 inclusive. + // We need to be careful about the range of word 0, too: we can + // only take 31 bits worth of it, since the sign bit needs to + // fit in there too. + if (data.Mid != 0 || // mantissa extends into middle word + data.Hi != 0 || // mantissa extends into top word + data.Lo < 0) // mantissa extends beyond 31 bits + { + return ThrowWireFormattingException(value); + } + + destination = (byte)((data.Flags >> 16) & 0xFF); + WriteLong(ref destination.GetOffset(1), (data.Flags & 0b1000_0000_0000_0000_0000_0000_0000_0000) | (data.Lo & 0b0111_1111_1111_1111_1111_1111_1111_1111)); + return 5; + } + + public static int WriteFieldValue(ref byte destination, object value, int bytesRemaining) + { + if (value == null) + { + destination = (byte)'V'; + return 1; + } + + // Order by likelihood of occurrence + ref byte fieldValue = ref destination.GetOffset(1); + switch (value) + { + case string val: + destination = (byte)'S'; + return 1 + WriteLongstr(ref fieldValue, val, bytesRemaining - 1); + case bool val: + destination = (byte)'t'; + fieldValue = val.ToByte(); + return 2; + case int val: + destination = (byte)'I'; + NetworkOrderSerializer.WriteInt32(ref fieldValue, val); + return 5; + case byte[] val: + destination = (byte)'S'; + return 1 + WriteLongstr(ref fieldValue, val); + default: + return WriteFieldValueSlow(ref destination, ref fieldValue, value, bytesRemaining); + } + + // Moved out of outer switch to have a shorter main method (improves performance) + static int WriteFieldValueSlow(ref byte destination, ref byte fieldValue, object value, int bytesRemaining) + { + // Order by likelihood of occurrence + switch (value) + { + case float val: + destination = (byte)'f'; + NetworkOrderSerializer.WriteSingle(ref fieldValue, val); + return 5; + case IDictionary val: + destination = (byte)'F'; + return 1 + WriteTable(ref fieldValue, val, bytesRemaining - 1); + case IList val: + destination = (byte)'A'; + return 1 + WriteArray(ref fieldValue, val, bytesRemaining - 1); + case AmqpTimestamp val: + destination = (byte)'T'; + return 1 + WriteTimestamp(ref fieldValue, val); + case double val: + destination = (byte)'d'; + NetworkOrderSerializer.WriteDouble(ref fieldValue, val); + return 9; + case long val: + destination = (byte)'l'; + NetworkOrderSerializer.WriteInt64(ref fieldValue, val); + return 9; + case byte val: + destination = (byte)'B'; + fieldValue = val; + return 2; + case sbyte val: + destination = (byte)'b'; + fieldValue = (byte)val; + return 2; + case short val: + destination = (byte)'s'; + NetworkOrderSerializer.WriteInt16(ref fieldValue, val); + return 3; + case uint val: + destination = (byte)'i'; + NetworkOrderSerializer.WriteUInt32(ref fieldValue, val); + return 5; + case decimal val: + destination = (byte)'D'; + return 1 + WriteDecimal(ref fieldValue, val); + case IDictionary val: + destination = (byte)'F'; + return 1 + WriteTable(ref fieldValue, val, bytesRemaining - 1); + case BinaryTableValue val: + destination = (byte)'x'; + return 1 + WriteLongstr(ref fieldValue, val.Bytes); + default: + return ThrowInvalidTableValue(value); + } + } + } + + public static int GetFieldValueByteCount(object value) + { + // Order by likelihood of occurrence + switch (value) + { + case null: + return 1; + case string val: + return 5 + GetByteCount(val); + case bool _: + return 2; + case int _: + case float _: + return 5; + case byte[] val: + return 5 + val.Length; + case IDictionary val: + return 1 + GetTableByteCount(val); + case IList val: + return 1 + GetArrayByteCount(val); + case AmqpTimestamp _: + case double _: + case long _: + return 9; + case byte _: + case sbyte _: + return 2; + case short _: + return 3; + case uint _: + return 5; + case decimal _: + return 6; + case IDictionary val: + return 1 + GetTableByteCount(val); + case BinaryTableValue val: + return 5 + val.Bytes.Length; + default: + return ThrowInvalidTableValue(value); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteLong(ref byte destination, uint val) + { + NetworkOrderSerializer.WriteUInt32(ref destination, val); + return 4; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteLonglong(ref byte destination, ulong val) + { + NetworkOrderSerializer.WriteUInt64(ref destination, val); + return 8; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteBits(ref byte destination, bool val) + { + destination = val.ToByte(); + return 1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteBits(ref byte destination, bool val1, bool val2) + { + destination = (byte)(val1.ToByte() + val2.ToByte() * 2); + return 1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteBits(ref byte destination, bool val1, bool val2, bool val3) + { + destination = (byte)(val1.ToByte() + val2.ToByte() * 2 + val3.ToByte() * 4); + return 1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteBits(ref byte destination, bool val1, bool val2, bool val3, bool val4) + { + destination = (byte)(val1.ToByte() + val2.ToByte() * 2 + val3.ToByte() * 4 + val4.ToByte() * 8); + return 1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteBits(ref byte destination, bool val1, bool val2, bool val3, bool val4, bool val5) + { + destination = (byte)(val1.ToByte() + val2.ToByte() * 2 + val3.ToByte() * 4 + val4.ToByte() * 8 + val5.ToByte() * 16); + return 1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteBits(ref byte destination, + bool val1, bool val2, bool val3, bool val4, bool val5, + bool val6, bool val7, bool val8, bool val9, bool val10, + bool val11, bool val12, bool val13, bool val14) + { + destination = (byte)(val8.ToByte() + val7.ToByte() * 2 + val6.ToByte() * 4 + val5.ToByte() * 8 + val4.ToByte() * 16 + val3.ToByte() * 32 + val2.ToByte() * 64 + val1.ToByte() * 128); + destination.GetOffset(1) = (byte)(val14.ToByte() * 4 + val13.ToByte() * 8 + val12.ToByte() * 16 + val11.ToByte() * 32 + val10.ToByte() * 64 + val9.ToByte() * 128); + return 2; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteLongstr(ref byte destination, ReadOnlySpan val) + { + WriteLong(ref destination, (uint)val.Length); + Unsafe.CopyBlockUnaligned(ref destination.GetOffset(4), ref val.GetStart(), (uint)val.Length); + return 4 + val.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteShort(ref byte destination, ushort val) + { + NetworkOrderSerializer.WriteUInt16(ref destination, val); + return 2; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteShortstr(ref byte destination, ReadOnlySpan value) + { + var length = value.Length; + if (length <= byte.MaxValue) + { + destination = (byte)length; + Unsafe.CopyBlockUnaligned(ref destination.GetOffset(1), ref value.GetStart(), (uint)value.Length); + return length + 1; + } + + return ThrowArgumentTooLong(length); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteShortstr(ref byte destination, string val, int remainingBytes) + { + int bytesWritten = 0; + if (!string.IsNullOrEmpty(val)) + { + int maxLength = remainingBytes - 1; + if (maxLength > byte.MaxValue) + { + maxLength = byte.MaxValue; + } + + unsafe + { + fixed (char* chars = val) + { + try + { + ref byte valDestination = ref destination.GetOffset(1); + fixed (byte* bytes = &valDestination) + { + bytesWritten = UTF8.GetBytes(chars, val.Length, bytes, maxLength); + } + } + catch (ArgumentException) + { + return ThrowArgumentOutOfRangeException(val, maxLength); + } + } + } + } + + destination = unchecked((byte)bytesWritten); + return bytesWritten + 1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteLongstr(ref byte destination, string val, int bytesRemaining) + { + static int GetBytes(ref byte destination, string val, int bytesRemaining) + { + unsafe + { + fixed (char* chars = val) + fixed (byte* bytes = &destination) + { + return UTF8.GetBytes(chars, val.Length, bytes, bytesRemaining); + } + } + } + + int bytesWritten = string.IsNullOrEmpty(val) ? 0 : GetBytes(ref destination.GetOffset(4), val, bytesRemaining - 4); + NetworkOrderSerializer.WriteUInt32(ref destination, (uint)bytesWritten); + return bytesWritten + 4; + } + + public static int WriteTable(ref byte destination, IDictionary val, int bytesRemaining) + { + if (val is null || val.Count == 0) + { + NetworkOrderSerializer.WriteUInt32(ref destination, 0u); + return 4; + } + + // Let's only write after the length header. + int bytesWritten = 4; + foreach (DictionaryEntry entry in val) + { + bytesWritten += WriteShortstr(ref destination.GetOffset(bytesWritten), entry.Key.ToString(), bytesRemaining - bytesWritten); + bytesWritten += WriteFieldValue(ref destination.GetOffset(bytesWritten), entry.Value, bytesRemaining - bytesWritten); + } + + NetworkOrderSerializer.WriteUInt32(ref destination, (uint)(bytesWritten - 4)); + return bytesWritten; + } + + public static int WriteTable(ref byte destination, IDictionary val, int bytesRemaining) + { + if (val is null || val.Count == 0) + { + NetworkOrderSerializer.WriteUInt32(ref destination, 0); + return 4; + } + + // Let's only write after the length header. + int bytesWritten = 4; + if (val is Dictionary dict) + { + foreach (KeyValuePair entry in dict) + { + bytesWritten += WriteShortstr(ref destination.GetOffset(bytesWritten), entry.Key, bytesRemaining - bytesWritten); + bytesWritten += WriteFieldValue(ref destination.GetOffset(bytesWritten), entry.Value, bytesRemaining - bytesWritten); + } + } + else + { + foreach (KeyValuePair entry in val) + { + bytesWritten += WriteShortstr(ref destination.GetOffset(bytesWritten), entry.Key, bytesRemaining - bytesWritten); + bytesWritten += WriteFieldValue(ref destination.GetOffset(bytesWritten), entry.Value, bytesRemaining - bytesWritten); + } + } + + NetworkOrderSerializer.WriteUInt32(ref destination, (uint)(bytesWritten - 4)); + return bytesWritten; + } + + public static int GetTableByteCount(IDictionary val) + { + if (val is null || val.Count == 0) + { + return 4; + } + + int byteCount = 4; + foreach (DictionaryEntry entry in val) + { + byteCount += GetByteCount(entry.Key.ToString()) + 1; + byteCount += GetFieldValueByteCount(entry.Value); + } + + return byteCount; + } + + public static int GetTableByteCount(IDictionary val) + { + if (val is null || val.Count == 0) + { + return 4; + } + + int byteCount = 4; + if (val is Dictionary dict) + { + foreach (KeyValuePair entry in dict) + { + byteCount += GetByteCount(entry.Key) + 1; + byteCount += GetFieldValueByteCount(entry.Value); + } + } + else + { + foreach (KeyValuePair entry in val) + { + byteCount += GetByteCount(entry.Key) + 1; + byteCount += GetFieldValueByteCount(entry.Value); + } + } + + return byteCount; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteTimestamp(ref byte destination, AmqpTimestamp val) + { + // 0-9 is afaict silent on the signedness of the timestamp. + // See also MethodArgumentReader.ReadTimestamp and AmqpTimestamp itself + return WriteLonglong(ref destination, (ulong)val.UnixTime); + } + + public static int ThrowArgumentTooLong(int length) + => throw new ArgumentOutOfRangeException("value", $"Value exceeds the maximum allowed length of 255 bytes, was {length} long."); + + public static int ThrowArgumentOutOfRangeException(int orig, int expected) + => throw new ArgumentOutOfRangeException("span", $"Span has not enough space ({orig} instead of {expected})"); + + public static int ThrowArgumentOutOfRangeException(string val, int maxLength) + => throw new ArgumentOutOfRangeException(nameof(val), val, $"Value exceeds the maximum allowed length of {maxLength} bytes."); + + private static int ThrowWireFormattingException(decimal value) + => throw new WireFormattingException("Decimal overflow in AMQP encoding", value); + + private static int ThrowInvalidTableValue(object value) + => throw new WireFormattingException($"Value of type '{value.GetType().Name}' cannot appear as table value", value); + } +} diff --git a/projects/RabbitMQ.Client/client/impl/WireFormatting.cs b/projects/RabbitMQ.Client/client/impl/WireFormatting.cs index 84cb123793..0d48a07791 100644 --- a/projects/RabbitMQ.Client/client/impl/WireFormatting.cs +++ b/projects/RabbitMQ.Client/client/impl/WireFormatting.cs @@ -29,18 +29,11 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -using System; -using System.Collections; -using System.Collections.Generic; -using System.Runtime.CompilerServices; using System.Text; -using RabbitMQ.Client.Exceptions; -using RabbitMQ.Util; - namespace RabbitMQ.Client.Impl { - internal static class WireFormatting + internal static partial class WireFormatting { public static readonly object TrueBoolean = true; public static readonly object FalseBoolean = false; @@ -72,926 +65,5 @@ internal DecimalData(uint flags, uint hi, uint lo, uint mid) } private static readonly UTF8Encoding UTF8 = new UTF8Encoding(); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static decimal ReadDecimal(ReadOnlySpan span) - { - byte scale = span[0]; - if (scale > 28) - { - ThrowInvalidDecimalScale(scale); - } - - uint unsignedMantissa = NetworkOrderDeserializer.ReadUInt32(span.Slice(1)); - var data = new DecimalData(((uint)(scale << 16)) | unsignedMantissa & 0x80000000, 0, unsignedMantissa & 0x7FFFFFFF, 0); - return Unsafe.As(ref data); - } - - public static IList ReadArray(ReadOnlySpan span, out int bytesRead) - { - bytesRead = 4; - long arrayLength = NetworkOrderDeserializer.ReadUInt32(span); - if (arrayLength == 0) - { - return null; - } - List array = new List(); - while (bytesRead - 4 < arrayLength) - { - array.Add(ReadFieldValue(span.Slice(bytesRead), out int fieldValueBytesRead)); - bytesRead += fieldValueBytesRead; - } - - return array; - } - - public static object ReadFieldValue(ReadOnlySpan span, out int bytesRead) - { - switch ((char)span[0]) - { - case 'S': - bytesRead = 1 + ReadLongstr(span.Slice(1), out var bytes); - return bytes; - case 't': - bytesRead = 2; - return span[1] != 0 ? TrueBoolean : FalseBoolean; - case 'I': - bytesRead = 5; - return NetworkOrderDeserializer.ReadInt32(span.Slice(1)); - case 'V': - bytesRead = 1; - return null; - default: - return ReadFieldValueSlow(span, out bytesRead); - } - - // Moved out of outer switch to have a shorter main method (improves performance) - static object ReadFieldValueSlow(ReadOnlySpan span, out int bytesRead) - { - var slice = span.Slice(1); - switch ((char)span[0]) - { - case 'F': - bytesRead = 1 + ReadDictionary(slice, out var dictionary); - return dictionary; - case 'A': - IList arrayResult = ReadArray(slice, out int arrayBytesRead); - bytesRead = 1 + arrayBytesRead; - return arrayResult; - case 'l': - bytesRead = 9; - return NetworkOrderDeserializer.ReadInt64(slice); - case 'i': - bytesRead = 5; - return NetworkOrderDeserializer.ReadUInt32(slice); - case 'D': - bytesRead = 6; - return ReadDecimal(slice); - case 'B': - bytesRead = 2; - return span[1]; - case 'b': - bytesRead = 2; - return (sbyte)span[1]; - case 'd': - bytesRead = 9; - return NetworkOrderDeserializer.ReadDouble(slice); - case 'f': - bytesRead = 5; - return NetworkOrderDeserializer.ReadSingle(slice); - case 's': - bytesRead = 3; - return NetworkOrderDeserializer.ReadInt16(slice); - case 'T': - bytesRead = 1 + ReadTimestamp(slice, out var timestamp); - return timestamp; - case 'x': - bytesRead = 1 + ReadLongstr(slice, out var binaryTableResult); - return new BinaryTableValue(binaryTableResult); - default: - bytesRead = 0; - return ThrowInvalidTableValue((char)span[0]); - } - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ReadLongstr(ReadOnlySpan span, out byte[] value) - { - uint byteCount = NetworkOrderDeserializer.ReadUInt32(span); - if (byteCount > int.MaxValue) - { - value = null; - return ThrowSyntaxErrorException(byteCount); - } - - value = span.Slice(4, (int)byteCount).ToArray(); - return 4 + value.Length; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ReadShortstr(ReadOnlySpan span, out string value) - { - int byteCount = span[0]; - if (byteCount == 0) - { - value = string.Empty; - return 1; - } - - // equals span.Length >= byteCount + 1 - if (span.Length > byteCount) - { -#if NETCOREAPP - value = UTF8.GetString(span.Slice(1, byteCount)); -#else - unsafe - { - fixed (byte* bytes = span.Slice(1)) - { - value = UTF8.GetString(bytes, byteCount); - } - } - -#endif - return 1 + byteCount; - } - - value = string.Empty; - return ThrowArgumentOutOfRangeException(span.Length, byteCount + 1); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ReadBits(ReadOnlySpan span, out bool val) - { - val = (span[0] & 0b0000_0001) != 0; - return 1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ReadBits(ReadOnlySpan span, out bool val1, out bool val2) - { - byte bits = span[0]; - val1 = (bits & 0b0000_0001) != 0; - val2 = (bits & 0b0000_0010) != 0; - return 1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ReadBits(ReadOnlySpan span, out bool val1, out bool val2, out bool val3) - { - byte bits = span[0]; - val1 = (bits & 0b0000_0001) != 0; - val2 = (bits & 0b0000_0010) != 0; - val3 = (bits & 0b0000_0100) != 0; - return 1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ReadBits(ReadOnlySpan span, out bool val1, out bool val2, out bool val3, out bool val4) - { - byte bits = span[0]; - val1 = (bits & 0b0000_0001) != 0; - val2 = (bits & 0b0000_0010) != 0; - val3 = (bits & 0b0000_0100) != 0; - val4 = (bits & 0b0000_1000) != 0; - return 1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ReadBits(ReadOnlySpan span, out bool val1, out bool val2, out bool val3, out bool val4, out bool val5) - { - byte bits = span[0]; - val1 = (bits & 0b0000_0001) != 0; - val2 = (bits & 0b0000_0010) != 0; - val3 = (bits & 0b0000_0100) != 0; - val4 = (bits & 0b0000_1000) != 0; - val5 = (bits & 0b0001_0000) != 0; - return 1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ReadBits(ReadOnlySpan span, - out bool val1, out bool val2, out bool val3, out bool val4, out bool val5, - out bool val6, out bool val7, out bool val8, out bool val9, out bool val10, - out bool val11, out bool val12, out bool val13, out bool val14) - { - byte bits = span[0]; - val1 = (bits & 0b1000_0000) != 0; - val2 = (bits & 0b0100_0000) != 0; - val3 = (bits & 0b0010_0000) != 0; - val4 = (bits & 0b0001_0000) != 0; - val5 = (bits & 0b0000_1000) != 0; - val6 = (bits & 0b0000_0100) != 0; - val7 = (bits & 0b0000_0010) != 0; - val8 = (bits & 0b0000_0001) != 0; - bits = span[1]; - val9 = (bits & 0b1000_0000) != 0; - val10 = (bits & 0b0100_0000) != 0; - val11 = (bits & 0b0010_0000) != 0; - val12 = (bits & 0b0001_0000) != 0; - val13 = (bits & 0b0000_1000) != 0; - val14 = (bits & 0b0000_0100) != 0; - return 2; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ReadShort(ReadOnlySpan span, out ushort value) - { - value = NetworkOrderDeserializer.ReadUInt16(span); - return 2; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ReadLong(ReadOnlySpan span, out uint value) - { - value = NetworkOrderDeserializer.ReadUInt32(span); - return 4; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ReadLonglong(ReadOnlySpan span, out ulong value) - { - value = NetworkOrderDeserializer.ReadUInt64(span); - return 8; - } - - ///Reads an AMQP "table" definition from the reader. - /// - /// Supports the AMQP 0-8/0-9 standard entry types S, I, D, T - /// and F, as well as the QPid-0-8 specific b, d, f, l, s, t, - /// x and V types and the AMQP 0-9-1 A type. - /// - /// A . - public static int ReadDictionary(ReadOnlySpan span, out Dictionary valueDictionary) - { - long tableLength = NetworkOrderDeserializer.ReadUInt32(span); - if (tableLength == 0) - { - valueDictionary = null; - return 4; - } - - span = span.Slice(4); - valueDictionary = new Dictionary(); - int bytesRead = 0; - while (bytesRead < tableLength) - { - bytesRead += ReadShortstr(span.Slice(bytesRead), out string key); - valueDictionary[key] = ReadFieldValue(span.Slice(bytesRead), out int valueBytesRead); - bytesRead += valueBytesRead; - } - - return 4 + bytesRead; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ReadTimestamp(ReadOnlySpan span, out AmqpTimestamp value) - { - // 0-9 is afaict silent on the signedness of the timestamp. - // See also MethodArgumentWriter.WriteTimestamp and AmqpTimestamp itself - value = new AmqpTimestamp((long)NetworkOrderDeserializer.ReadUInt64(span)); - return 8; - } - - public static int WriteArray(Span span, IList val) - { - if (val is null || val.Count == 0) - { - NetworkOrderSerializer.WriteUInt32(span, 0); - return 4; - } - - int bytesWritten = 4; - for (int index = 0; index < val.Count; index++) - { - bytesWritten += WriteFieldValue(span.Slice(bytesWritten), val[index]); - } - - NetworkOrderSerializer.WriteUInt32(span, (uint)bytesWritten - 4u); - return bytesWritten; - } - - public static int GetArrayByteCount(IList val) - { - if (val is null || val.Count == 0) - { - return 4; - } - - int byteCount = 4; - if (val is List valList) - { - for (int index = 0; index < valList.Count; index++) - { - byteCount += GetFieldValueByteCount(valList[index]); - } - } - else - { - for (int index = 0; index < val.Count; index++) - { - byteCount += GetFieldValueByteCount(val[index]); - } - } - - return byteCount; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#if NETCOREAPP - public static int GetByteCount(ReadOnlySpan val) => val.IsEmpty ? 0 : UTF8.GetByteCount(val); -#else - public static int GetByteCount(string val) => string.IsNullOrEmpty(val) ? 0 : UTF8.GetByteCount(val); -#endif - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteDecimal(Span span, decimal value) - { - // Cast the decimal to our struct to avoid the decimal.GetBits allocations. - DecimalData data = Unsafe.As(ref value); - // According to the documentation :- - // - word 0: low-order "mantissa" - // - word 1, word 2: medium- and high-order "mantissa" - // - word 3: mostly reserved; "exponent" and sign bit - // In one way, this is broader than AMQP: the mantissa is larger. - // In another way, smaller: the exponent ranges 0-28 inclusive. - // We need to be careful about the range of word 0, too: we can - // only take 31 bits worth of it, since the sign bit needs to - // fit in there too. - if (data.Mid != 0 || // mantissa extends into middle word - data.Hi != 0 || // mantissa extends into top word - data.Lo < 0) // mantissa extends beyond 31 bits - { - return ThrowWireFormattingException(value); - } - - span[0] = (byte)((data.Flags >> 16) & 0xFF); - WriteLong(span.Slice(1), (data.Flags & 0b1000_0000_0000_0000_0000_0000_0000_0000) | (data.Lo & 0b0111_1111_1111_1111_1111_1111_1111_1111)); - return 5; - } - - public static int WriteFieldValue(Span span, object value) - { - // Order by likelihood of occurrence - Span slice = span.Slice(1); - ref var type = ref span[0]; - switch (value) - { - case null: - type = (byte)'V'; - return 1; - case string val: - type = (byte)'S'; - return 1 + WriteLongstr(slice, val); - case bool val: - type = (byte)'t'; - span[1] = (byte)(val ? 1 : 0); - return 2; - case int val: - type = (byte)'I'; - NetworkOrderSerializer.WriteInt32(slice, val); - return 5; - case byte[] val: - type = (byte)'S'; - return 1 + WriteLongstr(slice, val); - default: - return WriteFieldValueSlow(span, value); - } - - // Moved out of outer switch to have a shorter main method (improves performance) - static int WriteFieldValueSlow(Span span, object value) - { - // Order by likelihood of occurrence - ref var type = ref span[0]; - Span slice = span.Slice(1); - switch (value) - { - case float val: - type = (byte)'f'; - NetworkOrderSerializer.WriteSingle(slice, val); - return 5; - case IDictionary val: - type = (byte)'F'; - return 1 + WriteTable(slice, val); - case IList val: - type = (byte)'A'; - return 1 + WriteArray(slice, val); - case AmqpTimestamp val: - type = (byte)'T'; - return 1 + WriteTimestamp(slice, val); - case double val: - type = (byte)'d'; - NetworkOrderSerializer.WriteDouble(slice, val); - return 9; - case long val: - type = (byte)'l'; - NetworkOrderSerializer.WriteInt64(slice, val); - return 9; - case byte val: - type = (byte)'B'; - span[1] = val; - return 2; - case sbyte val: - type = (byte)'b'; - span[1] = (byte)val; - return 2; - case short val: - type = (byte)'s'; - NetworkOrderSerializer.WriteInt16(slice, val); - return 3; - case uint val: - type = (byte)'i'; - NetworkOrderSerializer.WriteUInt32(slice, val); - return 5; - case decimal val: - type = (byte)'D'; - return 1 + WriteDecimal(slice, val); - case IDictionary val: - type = (byte)'F'; - return 1 + WriteTable(slice, val); - case BinaryTableValue val: - type = (byte)'x'; - return 1 + WriteLongstr(slice, val.Bytes); - default: - return ThrowInvalidTableValue(value); - } - } - } - - public static int GetFieldValueByteCount(object value) - { - // Order by likelihood of occurrence - switch (value) - { - case null: - return 1; - case string val: - return 5 + GetByteCount(val); - case bool _: - return 2; - case int _: - case float _: - return 5; - case byte[] val: - return 5 + val.Length; - case IDictionary val: - return 1 + GetTableByteCount(val); - case IList val: - return 1 + GetArrayByteCount(val); - case AmqpTimestamp _: - case double _: - case long _: - return 9; - case byte _: - case sbyte _: - return 2; - case short _: - return 3; - case uint _: - return 5; - case decimal _: - return 6; - case IDictionary val: - return 1 + GetTableByteCount(val); - case BinaryTableValue val: - return 5 + val.Bytes.Length; - default: - return ThrowInvalidTableValue(value); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteLong(Span span, uint val) - { - NetworkOrderSerializer.WriteUInt32(span, val); - return 4; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteLonglong(Span span, ulong val) - { - NetworkOrderSerializer.WriteUInt64(span, val); - return 8; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteBits(Span span, bool val) - { - span[0] = (byte)(val ? 1 : 0); - return 1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteBits(Span span, bool val1, bool val2) - { - int bits = 0; - if (val1) - { - bits |= 1 << 0; - } - - if (val2) - { - bits |= 1 << 1; - } - span[0] = (byte)bits; - return 1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteBits(Span span, bool val1, bool val2, bool val3) - { - int bits = 0; - if (val1) - { - bits |= 1 << 0; - } - - if (val2) - { - bits |= 1 << 1; - } - - if (val3) - { - bits |= 1 << 2; - } - - span[0] = (byte)bits; - return 1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteBits(Span span, bool val1, bool val2, bool val3, bool val4) - { - int bits = 0; - if (val1) - { - bits |= 1 << 0; - } - - if (val2) - { - bits |= 1 << 1; - } - - if (val3) - { - bits |= 1 << 2; - } - - if (val4) - { - bits |= 1 << 3; - } - - span[0] = (byte)bits; - return 1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteBits(Span span, bool val1, bool val2, bool val3, bool val4, bool val5) - { - int bits = 0; - if (val1) - { - bits |= 1 << 0; - } - - if (val2) - { - bits |= 1 << 1; - } - - if (val3) - { - bits |= 1 << 2; - } - - if (val4) - { - bits |= 1 << 3; - } - - if (val5) - { - bits |= 1 << 4; - } - span[0] = (byte)bits; - return 1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteBits(Span span, - bool val1, bool val2, bool val3, bool val4, bool val5, - bool val6, bool val7, bool val8, bool val9, bool val10, - bool val11, bool val12, bool val13, bool val14) - { - int bits = 0; - if (val9) - { - bits |= 1 << 7; - } - - if (val10) - { - bits |= 1 << 6; - } - - if (val11) - { - bits |= 1 << 5; - } - - if (val12) - { - bits |= 1 << 4; - } - - if (val13) - { - bits |= 1 << 3; - } - - if (val14) - { - bits |= 1 << 2; - } - span[1] = (byte)bits; - - bits = 0; - if (val1) - { - bits |= 1 << 7; - } - - if (val2) - { - bits |= 1 << 6; - } - - if (val3) - { - bits |= 1 << 5; - } - - if (val4) - { - bits |= 1 << 4; - } - - if (val5) - { - bits |= 1 << 3; - } - - if (val6) - { - bits |= 1 << 2; - } - - if (val7) - { - bits |= 1 << 1; - } - - if (val8) - { - bits |= 1 << 0; - } - span[0] = (byte)bits; - return 2; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteLongstr(Span span, ReadOnlySpan val) - { - WriteLong(span, (uint)val.Length); - val.CopyTo(span.Slice(4)); - return 4 + val.Length; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteShort(Span span, ushort val) - { - NetworkOrderSerializer.WriteUInt16(span, val); - return 2; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteShortstr(Span span, ReadOnlySpan value) - { - var length = value.Length; - if (length <= byte.MaxValue) - { - span[0] = (byte)length; - value.CopyTo(span.Slice(1)); - return length + 1; - } - - return ThrowArgumentTooLong(length); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteShortstr(Span span, string val) - { - int bytesWritten = 0; - if (!string.IsNullOrEmpty(val)) - { - int maxLength = span.Length - 1; - if (maxLength > byte.MaxValue) - { - maxLength = byte.MaxValue; - } -#if NETCOREAPP - try - { - bytesWritten = UTF8.GetBytes(val, span.Slice(1, maxLength)); - } - catch (ArgumentException) - { - return ThrowArgumentOutOfRangeException(val, maxLength); - } -#else - unsafe - { - fixed (char* chars = val) - { - try - { - fixed (byte* bytes = span.Slice(1)) - { - bytesWritten = UTF8.GetBytes(chars, val.Length, bytes, maxLength); - } - } - catch (ArgumentException) - { - return ThrowArgumentOutOfRangeException(val, maxLength); - } - } - } -#endif - } - - span[0] = (byte)bytesWritten; - return bytesWritten + 1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#if NETCOREAPP - public static int WriteLongstr(Span span, ReadOnlySpan val) - { - int bytesWritten = val.IsEmpty ? 0 : UTF8.GetBytes(val, span.Slice(4)); -#else - public static int WriteLongstr(Span span, string val) - { - static int GetBytes(Span span, string val) - { - unsafe - { - fixed (char* chars = val) - fixed (byte* bytes = span) - { - return UTF8.GetBytes(chars, val.Length, bytes, span.Length); - } - } - } - - int bytesWritten = string.IsNullOrEmpty(val) ? 0 : GetBytes(span.Slice(4), val); -#endif - NetworkOrderSerializer.WriteUInt32(span, (uint)bytesWritten); - return bytesWritten + 4; - } - - public static int WriteTable(Span span, IDictionary val) - { - if (val is null || val.Count == 0) - { - NetworkOrderSerializer.WriteUInt32(span, 0u); - return 4; - } - - // Let's only write after the length header. - Span slice = span.Slice(4); - int bytesWritten = 0; - foreach (DictionaryEntry entry in val) - { - bytesWritten += WriteShortstr(slice.Slice(bytesWritten), entry.Key.ToString()); - bytesWritten += WriteFieldValue(slice.Slice(bytesWritten), entry.Value); - } - - NetworkOrderSerializer.WriteUInt32(span, (uint)bytesWritten); - return 4 + bytesWritten; - } - - public static int WriteTable(Span span, IDictionary val) - { - if (val is null || val.Count == 0) - { - NetworkOrderSerializer.WriteUInt32(span, 0); - return 4; - } - - // Let's only write after the length header. - Span slice = span.Slice(4); - int bytesWritten = 0; - if (val is Dictionary dict) - { - foreach (KeyValuePair entry in dict) - { - bytesWritten += WriteShortstr(slice.Slice(bytesWritten), entry.Key); - bytesWritten += WriteFieldValue(slice.Slice(bytesWritten), entry.Value); - } - } - else - { - foreach (KeyValuePair entry in val) - { - bytesWritten += WriteShortstr(slice.Slice(bytesWritten), entry.Key); - bytesWritten += WriteFieldValue(slice.Slice(bytesWritten), entry.Value); - } - } - - NetworkOrderSerializer.WriteUInt32(span, (uint)bytesWritten); - return 4 + bytesWritten; - } - - public static int GetTableByteCount(IDictionary val) - { - if (val is null || val.Count == 0) - { - return 4; - } - - int byteCount = 4; - foreach (DictionaryEntry entry in val) - { - byteCount += GetByteCount(entry.Key.ToString()) + 1; - byteCount += GetFieldValueByteCount(entry.Value); - } - - return byteCount; - } - - public static int GetTableByteCount(IDictionary val) - { - if (val is null || val.Count == 0) - { - return 4; - } - - int byteCount = 4; - if (val is Dictionary dict) - { - foreach (KeyValuePair entry in dict) - { - byteCount += GetByteCount(entry.Key) + 1; - byteCount += GetFieldValueByteCount(entry.Value); - } - } - else - { - foreach (KeyValuePair entry in val) - { - byteCount += GetByteCount(entry.Key) + 1; - byteCount += GetFieldValueByteCount(entry.Value); - } - } - - return byteCount; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteTimestamp(Span span, AmqpTimestamp val) - { - // 0-9 is afaict silent on the signedness of the timestamp. - // See also MethodArgumentReader.ReadTimestamp and AmqpTimestamp itself - return WriteLonglong(span, (ulong)val.UnixTime); - } - - public static int ThrowArgumentTooLong(int length) - => throw new ArgumentOutOfRangeException("value", $"Value exceeds the maximum allowed length of 255 bytes, was {length} long."); - - public static int ThrowArgumentOutOfRangeException(int orig, int expected) - => throw new ArgumentOutOfRangeException("span", $"Span has not enough space ({orig} instead of {expected})"); - - public static int ThrowArgumentOutOfRangeException(string val, int maxLength) - => throw new ArgumentOutOfRangeException(nameof(val), val, $"Value exceeds the maximum allowed length of {maxLength} bytes."); - - public static int ThrowSyntaxErrorException(uint byteCount) - => throw new SyntaxErrorException($"Long string too long; byte length={byteCount}, max={int.MaxValue}"); - - private static int ThrowWireFormattingException(decimal value) - => throw new WireFormattingException("Decimal overflow in AMQP encoding", value); - - private static int ThrowInvalidTableValue(char type) - => throw new SyntaxErrorException($"Unrecognised type in table: {type}"); - - private static int ThrowInvalidTableValue(object value) - => throw new WireFormattingException($"Value of type '{value.GetType().Name}' cannot appear as table value", value); - - private static decimal ThrowInvalidDecimalScale(int scale) - => throw new SyntaxErrorException($"Unrepresentable AMQP decimal table field: scale={scale}"); } } diff --git a/projects/RabbitMQ.Client/util/NetworkOrderSerializer.cs b/projects/RabbitMQ.Client/util/NetworkOrderSerializer.cs index dc8732680d..20cb7bc2c5 100644 --- a/projects/RabbitMQ.Client/util/NetworkOrderSerializer.cs +++ b/projects/RabbitMQ.Client/util/NetworkOrderSerializer.cs @@ -7,52 +7,53 @@ namespace RabbitMQ.Util internal static class NetworkOrderSerializer { [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void WriteDouble(Span span, double val) + internal static void WriteDouble(ref byte destination, double val) { - BinaryPrimitives.WriteInt64BigEndian(span, BitConverter.DoubleToInt64Bits(val)); + long tempVal = Unsafe.As(ref val); + Unsafe.WriteUnaligned(ref destination, BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(tempVal) : tempVal); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void WriteInt16(Span span, short val) + internal static void WriteInt16(ref byte destination, short val) { - BinaryPrimitives.WriteInt16BigEndian(span, val); + Unsafe.WriteUnaligned(ref destination, BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(val) : val); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void WriteInt32(Span span, int val) + internal static void WriteInt32(ref byte destination, int val) { - BinaryPrimitives.WriteInt32BigEndian(span, val); + Unsafe.WriteUnaligned(ref destination, BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(val) : val); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void WriteInt64(Span span, long val) + internal static void WriteInt64(ref byte destination, long val) { - BinaryPrimitives.WriteInt64BigEndian(span, val); + Unsafe.WriteUnaligned(ref destination, BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(val) : val); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void WriteSingle(Span span, float val) + internal static void WriteSingle(ref byte destination, float val) { int tempVal = Unsafe.As(ref val); - BinaryPrimitives.WriteInt32BigEndian(span, tempVal); + Unsafe.WriteUnaligned(ref destination, BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(tempVal) : tempVal); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void WriteUInt16(Span span, ushort val) + internal static void WriteUInt16(ref byte destination, ushort val) { - BinaryPrimitives.WriteUInt16BigEndian(span, val); + Unsafe.WriteUnaligned(ref destination, BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(val) : val); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void WriteUInt32(Span span, uint val) + internal static void WriteUInt32(ref byte destination, uint val) { - BinaryPrimitives.WriteUInt32BigEndian(span, val); + Unsafe.WriteUnaligned(ref destination, BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(val) : val); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void WriteUInt64(Span span, ulong val) + internal static void WriteUInt64(ref byte destination, ulong val) { - BinaryPrimitives.WriteUInt64BigEndian(span, val); + Unsafe.WriteUnaligned(ref destination, BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(val) : val); } } } diff --git a/projects/RabbitMQ.Client/util/TypeExtensions.cs b/projects/RabbitMQ.Client/util/TypeExtensions.cs new file mode 100644 index 0000000000..0140321b84 --- /dev/null +++ b/projects/RabbitMQ.Client/util/TypeExtensions.cs @@ -0,0 +1,57 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace RabbitMQ +{ + internal static class TypeExtensions + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref byte GetStart(this ReadOnlySpan span) + { + return ref MemoryMarshal.GetReference(span); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref byte GetStart(this byte[] array) + { + return ref Unsafe.AsRef(array[0]); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref byte GetStart(this Span span) + { + return ref MemoryMarshal.GetReference(span); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref byte GetOffset(this ReadOnlySpan span, int offset) + { + return ref span.GetStart().GetOffset(offset); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref byte GetOffset(this Span span, int offset) + { + return ref span.GetStart().GetOffset(offset); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref byte GetOffset(this ref byte source, int offset) + { + return ref Unsafe.Add(ref source, offset); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte ToByte(this ref bool source) + { + return Unsafe.As(ref source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool ToBool(this ref byte source) + { + return Unsafe.As(ref source); + } + } +} diff --git a/projects/Unit/TestFieldTableFormatting.cs b/projects/Unit/TestFieldTableFormatting.cs index cd13f4ac7d..5cb114a5bf 100644 --- a/projects/Unit/TestFieldTableFormatting.cs +++ b/projects/Unit/TestFieldTableFormatting.cs @@ -63,7 +63,7 @@ public void TestStandardTypes() t["fieldarray"] = array; int bytesNeeded = WireFormatting.GetTableByteCount(t); byte[] bytes = new byte[bytesNeeded]; - WireFormatting.WriteTable(bytes, t); + WireFormatting.WriteTable(ref bytes.GetStart(), t, bytes.Length); int bytesRead = WireFormatting.ReadDictionary(bytes, out var nt); Assert.Equal(bytesNeeded, bytesRead); Assert.Equal(Encoding.UTF8.GetBytes("Hello"), nt["string"]); @@ -87,7 +87,7 @@ public void TestTableEncoding_S() }; int bytesNeeded = WireFormatting.GetTableByteCount(t); byte[] bytes = new byte[bytesNeeded]; - WireFormatting.WriteTable(bytes, t); + WireFormatting.WriteTable(ref bytes.GetStart(), t, bytes.Length); int bytesRead = WireFormatting.ReadDictionary(bytes, out _); Assert.Equal(bytesNeeded, bytesRead); Check(bytes, new byte[] { @@ -107,7 +107,7 @@ public void TestTableEncoding_x() }; int bytesNeeded = WireFormatting.GetTableByteCount(t); byte[] bytes = new byte[bytesNeeded]; - WireFormatting.WriteTable(bytes, t); + WireFormatting.WriteTable(ref bytes.GetStart(), t, bytes.Length); int bytesRead = WireFormatting.ReadDictionary(bytes, out _); Assert.Equal(bytesNeeded, bytesRead); Check(bytes, new byte[] { @@ -129,7 +129,7 @@ [new string('A', TooLarge)] = null int bytesNeeded = WireFormatting.GetTableByteCount(t); byte[] bytes = new byte[bytesNeeded]; - Assert.Throws(() => WireFormatting.WriteTable(bytes, t)); + Assert.Throws(() => WireFormatting.WriteTable(ref bytes.GetStart(), t, bytes.Length)); } [Fact] @@ -150,7 +150,7 @@ public void TestQpidJmsTypes() t["V"] = null; // 2+1 int bytesNeeded = WireFormatting.GetTableByteCount(t); byte[] bytes = new byte[bytesNeeded]; - WireFormatting.WriteTable(bytes, t); + WireFormatting.WriteTable(ref bytes.GetStart(), t, bytes.Length); int bytesRead = WireFormatting.ReadDictionary(bytes, out var nt); Assert.Equal(bytesNeeded, bytesRead); Assert.Equal(typeof(byte), nt["B"].GetType()); Assert.Equal((byte)255, nt["B"]); diff --git a/projects/Unit/TestFieldTableFormattingGeneric.cs b/projects/Unit/TestFieldTableFormattingGeneric.cs index 696714c5c3..d701be894e 100644 --- a/projects/Unit/TestFieldTableFormattingGeneric.cs +++ b/projects/Unit/TestFieldTableFormattingGeneric.cs @@ -65,7 +65,7 @@ public void TestStandardTypes() t["fieldarray"] = array; int bytesNeeded = WireFormatting.GetTableByteCount(t); byte[] bytes = new byte[bytesNeeded]; - WireFormatting.WriteTable(bytes, t); + WireFormatting.WriteTable(ref bytes.GetStart(), t, bytes.Length); int bytesRead = WireFormatting.ReadDictionary(bytes, out var nt); Assert.Equal(bytesNeeded, bytesRead); Assert.Equal(Encoding.UTF8.GetBytes("Hello"), nt["string"]); @@ -89,7 +89,7 @@ public void TestTableEncoding_S() }; int bytesNeeded = WireFormatting.GetTableByteCount(t); byte[] bytes = new byte[bytesNeeded]; - WireFormatting.WriteTable(bytes, t); + WireFormatting.WriteTable(ref bytes.GetStart(), t, bytes.Length); int bytesRead = WireFormatting.ReadDictionary(bytes, out _); Assert.Equal(bytesNeeded, bytesRead); Check(bytes, new byte[] { @@ -109,7 +109,7 @@ public void TestTableEncoding_x() }; int bytesNeeded = WireFormatting.GetTableByteCount(t); byte[] bytes = new byte[bytesNeeded]; - WireFormatting.WriteTable(bytes, t); + WireFormatting.WriteTable(ref bytes.GetStart(), t, bytes.Length); int bytesRead = WireFormatting.ReadDictionary(bytes, out _); Assert.Equal(bytesNeeded, bytesRead); Check(bytes, new byte[] { @@ -138,7 +138,7 @@ public void TestQpidJmsTypes() t["V"] = null; int bytesNeeded = WireFormatting.GetTableByteCount(t); byte[] bytes = new byte[bytesNeeded]; - WireFormatting.WriteTable(bytes, t); + WireFormatting.WriteTable(ref bytes.GetStart(), t, bytes.Length); int bytesRead = WireFormatting.ReadDictionary(bytes, out var nt); Assert.Equal(bytesNeeded, bytesRead); Assert.Equal(typeof(byte), nt["B"].GetType()); Assert.Equal((byte)255, nt["B"]); diff --git a/projects/Unit/TestMethodArgumentCodec.cs b/projects/Unit/TestMethodArgumentCodec.cs index 8acaabff88..274eb5a50e 100644 --- a/projects/Unit/TestMethodArgumentCodec.cs +++ b/projects/Unit/TestMethodArgumentCodec.cs @@ -70,7 +70,7 @@ public void TestTableLengthWrite() int bytesNeeded = WireFormatting.GetTableByteCount(t); byte[] memory = new byte[bytesNeeded]; - int offset = WireFormatting.WriteTable(memory.AsSpan(), t); + int offset = WireFormatting.WriteTable(ref memory.GetStart(), t, memory.Length); Assert.Equal(bytesNeeded, offset); Check(memory, new byte[] { 0x00, 0x00, 0x00, 0x0C, 0x03, 0x61, 0x62, 0x63, @@ -81,11 +81,12 @@ public void TestTableLengthWrite() [Fact] public void TestDictionaryLengthRead() { - WireFormatting.ReadDictionary(new byte[] { + byte[] vs = new byte[] { 0x00, 0x00, 0x00, 0x0C, 0x03, 0x61, 0x62, 0x63, 0x53, 0x00, 0x00, 0x00, - 0x03, 0x64, 0x65, 0x66 }, out var t); + 0x03, 0x64, 0x65, 0x66 }; + WireFormatting.ReadDictionary(vs, out var t); Assert.Equal(Encoding.UTF8.GetBytes("def"), t["abc"]); Assert.Single(t); } @@ -101,7 +102,7 @@ public void TestNestedTableWrite() t["x"] = x; int bytesNeeded = WireFormatting.GetTableByteCount(t); byte[] memory = new byte[bytesNeeded]; - int offset = WireFormatting.WriteTable(memory.AsSpan(), t); + int offset = WireFormatting.WriteTable(ref memory.GetStart(), t, memory.Length); Assert.Equal(bytesNeeded, offset); Check(memory, new byte[] { 0x00, 0x00, 0x00, 0x0E, 0x01, 0x78, 0x46, 0x00, diff --git a/projects/Unit/TestNetworkByteOrderSerialization.cs b/projects/Unit/TestNetworkByteOrderSerialization.cs index ece83fc90c..6b29850613 100644 --- a/projects/Unit/TestNetworkByteOrderSerialization.cs +++ b/projects/Unit/TestNetworkByteOrderSerialization.cs @@ -63,28 +63,28 @@ private void Check(byte[] actual, byte[] expected) [Fact] public void TestSingleDecoding() { - Assert.Equal(1.234f, NetworkOrderDeserializer.ReadSingle(_expectedSingleBytes.AsSpan())); + Assert.Equal(1.234f, NetworkOrderDeserializer.ReadSingle(_expectedSingleBytes)); } [Fact] public void TestSingleEncoding() { byte[] bytes = new byte[4]; - NetworkOrderSerializer.WriteSingle(bytes, 1.234f); + NetworkOrderSerializer.WriteSingle(ref bytes.AsSpan().GetStart(), 1.234f); Check(bytes, _expectedSingleBytes); } [Fact] public void TestDoubleDecoding() { - Assert.Equal(1.234, NetworkOrderDeserializer.ReadDouble(_expectedDoubleBytes.AsSpan())); + Assert.Equal(1.234, NetworkOrderDeserializer.ReadDouble(_expectedDoubleBytes)); } [Fact] public void TestDoubleEncoding() { byte[] bytes = new byte[8]; - NetworkOrderSerializer.WriteDouble(bytes, 1.234); + NetworkOrderSerializer.WriteDouble(ref bytes.AsSpan().GetStart(), 1.234); Check(bytes, _expectedDoubleBytes); } @@ -92,7 +92,7 @@ public void TestDoubleEncoding() public void TestWriteInt16_positive() { byte[] bytes = new byte[2]; - NetworkOrderSerializer.WriteInt16(bytes, 0x1234); + NetworkOrderSerializer.WriteInt16(ref bytes.AsSpan().GetStart(), 0x1234); Check(bytes, new byte[] { 0x12, 0x34 }); } @@ -100,7 +100,7 @@ public void TestWriteInt16_positive() public void TestWriteInt16_negative() { byte[] bytes = new byte[2]; - NetworkOrderSerializer.WriteInt16(bytes, -0x1234); + NetworkOrderSerializer.WriteInt16(ref bytes.AsSpan().GetStart(), -0x1234); Check(bytes, new byte[] { 0xED, 0xCC }); } @@ -108,27 +108,27 @@ public void TestWriteInt16_negative() public void TestWriteUInt16() { byte[] bytes = new byte[2]; - NetworkOrderSerializer.WriteUInt16(bytes, 0x89AB); + NetworkOrderSerializer.WriteUInt16(ref bytes.AsSpan().GetStart(), 0x89AB); Check(bytes, new byte[] { 0x89, 0xAB }); } [Fact] public void TestReadInt16() { - Assert.Equal(0x1234, NetworkOrderDeserializer.ReadInt16(new byte[] { 0x12, 0x34 }.AsSpan())); + Assert.Equal(0x1234, NetworkOrderDeserializer.ReadInt16(new byte[] { 0x12, 0x34 })); } [Fact] public void TestReadUInt16() { - Assert.Equal(0x89AB, NetworkOrderDeserializer.ReadUInt16(new byte[] { 0x89, 0xAB }.AsSpan())); + Assert.Equal(0x89AB, NetworkOrderDeserializer.ReadUInt16(new byte[] { 0x89, 0xAB })); } [Fact] public void TestWriteInt32_positive() { byte[] bytes = new byte[4]; - NetworkOrderSerializer.WriteInt32(bytes, 0x12345678); + NetworkOrderSerializer.WriteInt32(ref bytes.GetStart(), 0x12345678); Check(bytes, new byte[] { 0x12, 0x34, 0x56, 0x78 }); } @@ -136,7 +136,7 @@ public void TestWriteInt32_positive() public void TestWriteInt32_negative() { byte[] bytes = new byte[4]; - NetworkOrderSerializer.WriteInt32(bytes, -0x12345678); + NetworkOrderSerializer.WriteInt32(ref bytes.GetStart(), -0x12345678); Check(bytes, new byte[] { 0xED, 0xCB, 0xA9, 0x88 }); } @@ -144,20 +144,20 @@ public void TestWriteInt32_negative() public void TestWriteUInt32() { byte[] bytes = new byte[4]; - NetworkOrderSerializer.WriteUInt32(bytes, 0x89ABCDEF); + NetworkOrderSerializer.WriteUInt32(ref bytes.GetStart(), 0x89ABCDEF); Check(bytes, new byte[] { 0x89, 0xAB, 0xCD, 0xEF }); } [Fact] public void TestReadInt32() { - Assert.Equal(0x12345678, NetworkOrderDeserializer.ReadInt32(new byte[] { 0x12, 0x34, 0x56, 0x78 }.AsSpan())); + Assert.Equal(0x12345678, NetworkOrderDeserializer.ReadInt32(new byte[] { 0x12, 0x34, 0x56, 0x78 })); } [Fact] public void TestReadUInt32() { - Assert.Equal(0x89ABCDEF, NetworkOrderDeserializer.ReadUInt32(new byte[] { 0x89, 0xAB, 0xCD, 0xEF }.AsSpan())); + Assert.Equal(0x89ABCDEF, NetworkOrderDeserializer.ReadUInt32(new byte[] { 0x89, 0xAB, 0xCD, 0xEF })); } @@ -165,7 +165,7 @@ public void TestReadUInt32() public void TestWriteInt64_positive() { byte[] bytes = new byte[8]; - NetworkOrderSerializer.WriteInt64(bytes, 0x123456789ABCDEF0); + NetworkOrderSerializer.WriteInt64(ref bytes.AsSpan().GetStart(), 0x123456789ABCDEF0); Check(bytes, new byte[] { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0 }); } @@ -173,7 +173,7 @@ public void TestWriteInt64_positive() public void TestWriteInt64_negative() { byte[] bytes = new byte[8]; - NetworkOrderSerializer.WriteInt64(bytes, -0x123456789ABCDEF0); + NetworkOrderSerializer.WriteInt64(ref bytes.AsSpan().GetStart(), -0x123456789ABCDEF0); Check(bytes, new byte[] { 0xED, 0xCB, 0xA9, 0x87, 0x65, 0x43, 0x21, 0x10 }); } @@ -181,20 +181,20 @@ public void TestWriteInt64_negative() public void TestWriteUInt64() { byte[] bytes = new byte[8]; - NetworkOrderSerializer.WriteUInt64(bytes, 0x89ABCDEF01234567); + NetworkOrderSerializer.WriteUInt64(ref bytes.AsSpan().GetStart(), 0x89ABCDEF01234567); Check(bytes, new byte[] { 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67 }); } [Fact] public void TestReadInt64() { - Assert.Equal(0x123456789ABCDEF0, NetworkOrderDeserializer.ReadInt64(new byte[] { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0 }.AsSpan())); + Assert.Equal(0x123456789ABCDEF0, NetworkOrderDeserializer.ReadInt64(new byte[] { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0 })); } [Fact] public void TestReadUInt64() { - Assert.Equal(0x89ABCDEF01234567, NetworkOrderDeserializer.ReadUInt64(new byte[] { 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67 }.AsSpan())); + Assert.Equal(0x89ABCDEF01234567, NetworkOrderDeserializer.ReadUInt64(new byte[] { 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67 })); } } }