Skip to content

Commit c608789

Browse files
committed
* Ensure that AmqpString comparison works the expected way when ReadOnlyMemory<byte> is used.
1 parent b152193 commit c608789

File tree

6 files changed

+49
-45
lines changed

6 files changed

+49
-45
lines changed

projects/RabbitMQ.Client/client/api/AmqpString.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
using System;
3333
using System.Text;
3434
using System.Text.RegularExpressions;
35+
using RabbitMQ.Util;
3536

3637
namespace RabbitMQ.Client
3738
{
@@ -169,7 +170,7 @@ public override int GetHashCode()
169170
{
170171
if (_value == null)
171172
{
172-
return _stringBytes.GetHashCode();
173+
return ReadOnlyMemoryOfByteEqualityComparer.CalculateHashCode(_stringBytes);
173174
}
174175
else
175176
{
@@ -179,7 +180,14 @@ public override int GetHashCode()
179180

180181
public int CompareTo(AmqpString other)
181182
{
182-
return Value.CompareTo(other.Value);
183+
if (_value == null)
184+
{
185+
return GetHashCode().CompareTo(other.GetHashCode());
186+
}
187+
else
188+
{
189+
return Value.CompareTo(other.Value);
190+
}
183191
}
184192

185193
public static bool operator ==(AmqpString amqpString1, AmqpString amqpString2)

projects/RabbitMQ.Client/client/impl/ConsumerDispatching/ConsumerDispatcherBase.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ internal abstract class ConsumerDispatcherBase
1616

1717
protected ConsumerDispatcherBase()
1818
{
19-
_consumers = new Dictionary<ReadOnlyMemory<byte>, (IBasicConsumer, ConsumerTag)>(MemoryOfByteEqualityComparer.Instance);
19+
IEqualityComparer<ReadOnlyMemory<byte>> comparer = new ReadOnlyMemoryOfByteEqualityComparer();
20+
_consumers = new Dictionary<ReadOnlyMemory<byte>, (IBasicConsumer, ConsumerTag)>(comparer);
2021
}
2122

2223
protected void AddConsumer(IBasicConsumer consumer, ConsumerTag consumerTag)

projects/RabbitMQ.Client/client/impl/RabbitMQActivitySource.cs

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
using System;
2-
using System.Collections.Generic;
1+
using System.Collections.Generic;
32
using System.Diagnostics;
43
using System.Net;
54
using System.Net.Sockets;
65
using System.Reflection;
7-
using System.Runtime.CompilerServices;
86
using System.Text;
97
using RabbitMQ.Client.Events;
108
using RabbitMQ.Client.Impl;
@@ -112,28 +110,6 @@ internal static Activity Receive(string routingKey, string exchange, ulong deliv
112110
return activity;
113111
}
114112

115-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
116-
private static string GetString(ReadOnlySpan<byte> span)
117-
{
118-
#if NETSTANDARD
119-
if (span.Length == 0)
120-
{
121-
return string.Empty;
122-
}
123-
124-
unsafe
125-
{
126-
fixed (byte* bytesPtr = span)
127-
{
128-
return Encoding.UTF8.GetString(bytesPtr, span.Length);
129-
}
130-
}
131-
#else
132-
return Encoding.UTF8.GetString(span);
133-
#endif
134-
}
135-
136-
137113
internal static Activity Deliver(BasicDeliverEventArgs deliverEventArgs)
138114
{
139115
if (!s_subscriberSource.HasListeners())

projects/RabbitMQ.Client/client/impl/RecordedQueue.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public async Task<QueueName> RecoverAsync(IChannel channel, CancellationToken ca
8686
cancellationToken: cancellationToken)
8787
.ConfigureAwait(false);
8888

89-
return new QueueName(queueDeclareResult.QueueName);
89+
return (QueueName)queueDeclareResult;
9090
}
9191

9292
public override string ToString()

projects/RabbitMQ.Client/util/MemoryOfByteEqualityComparer.cs renamed to projects/RabbitMQ.Client/util/ReadOnlyMemoryOfByteEqualityComparer.cs

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,34 +35,37 @@
3535

3636
namespace RabbitMQ.Util
3737
{
38-
internal sealed class MemoryOfByteEqualityComparer : IEqualityComparer<ReadOnlyMemory<byte>>
38+
internal sealed class ReadOnlyMemoryOfByteEqualityComparer : IEqualityComparer<ReadOnlyMemory<byte>>
3939
{
40-
public static MemoryOfByteEqualityComparer Instance { get; } = new MemoryOfByteEqualityComparer();
41-
4240
public bool Equals(ReadOnlyMemory<byte> left, ReadOnlyMemory<byte> right)
4341
{
4442
return left.Span.SequenceEqual(right.Span);
4543
}
4644

4745
public int GetHashCode(ReadOnlyMemory<byte> value)
4846
{
47+
return CalculateHashCode(value);
48+
}
49+
50+
public static int CalculateHashCode(ReadOnlyMemory<byte> value)
51+
{
4952
#if NETSTANDARD
50-
unchecked
53+
unchecked
54+
{
55+
int hashCode = 0;
56+
ReadOnlySpan<long> longPart = MemoryMarshal.Cast<byte, long>(value.Span);
57+
foreach (long item in longPart)
5158
{
52-
int hashCode = 0;
53-
var longPart = MemoryMarshal.Cast<byte, long>(value.Span);
54-
foreach (long item in longPart)
55-
{
56-
hashCode = (hashCode * 397) ^ item.GetHashCode();
57-
}
58-
59-
foreach (int item in value.Span.Slice(longPart.Length * 8))
60-
{
61-
hashCode = (hashCode * 397) ^ item.GetHashCode();
62-
}
59+
hashCode = (hashCode * 397) ^ item.GetHashCode();
60+
}
6361

64-
return hashCode;
62+
foreach (int item in value.Span.Slice(longPart.Length * 8))
63+
{
64+
hashCode = (hashCode * 397) ^ item.GetHashCode();
6565
}
66+
67+
return hashCode;
68+
}
6669
#else
6770
HashCode result = default;
6871
result.AddBytes(value.Span);

projects/Test/Unit/TestAmqpString.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
using System;
3333
using System.Text;
3434
using RabbitMQ.Client;
35+
using RabbitMQ.Util;
3536
using Xunit;
3637

3738
namespace Test.Unit
@@ -124,5 +125,20 @@ public void TestExchangeName_InitializeFromMemoryIsLazy(string arg)
124125
Assert.True(e.HasString);
125126
Assert.Equal(arg, estr);
126127
}
128+
129+
[Fact]
130+
public void TestEqualityWhenUsingReadOnlyMemoryOfByte()
131+
{
132+
ReadOnlyMemory<byte> b1 = new byte[] { (byte)'f', (byte)'o', (byte)'o' };
133+
ReadOnlyMemory<byte> b2 = new byte[] { (byte)'f', (byte)'o', (byte)'o' };
134+
135+
Assert.NotEqual(b1.GetHashCode(), b2.GetHashCode());
136+
Assert.Equal(ReadOnlyMemoryOfByteEqualityComparer.CalculateHashCode(b1),
137+
ReadOnlyMemoryOfByteEqualityComparer.CalculateHashCode(b2));
138+
139+
var ex1 = new ExchangeName(b1);
140+
var ex2 = new ExchangeName(b2);
141+
Assert.Equal(ex1, ex2);
142+
}
127143
}
128144
}

0 commit comments

Comments
 (0)