Skip to content

Commit 5b98dee

Browse files
committed
repro finally
1 parent 251a0bd commit 5b98dee

2 files changed

Lines changed: 115 additions & 0 deletions

File tree

ValidCode/StructBuilder/Client.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
using System.Threading;
2+
using System;
3+
using System.Net.Sockets;
4+
5+
namespace ValidCode.StructBuilder;
6+
7+
using System.Net;
8+
using System.Threading.Tasks;
9+
10+
internal sealed class Client : IDisposable
11+
{
12+
private readonly Socket socket = new(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
13+
14+
private bool disposed;
15+
16+
public async Task<int> M()
17+
{
18+
this.ThrowIfDisposed();
19+
var id = Request.GetNextValidId();
20+
using var request = new Request()
21+
.Append(6, "message")
22+
.Append(2, "version")
23+
.Append(true, "subscribe");
24+
await this.socket.SendAsync(request.LengthPrefixed(), SocketFlags.None, CancellationToken.None).ConfigureAwait(false);
25+
return id;
26+
}
27+
28+
public void Dispose()
29+
{
30+
if (this.disposed)
31+
{
32+
return;
33+
}
34+
35+
this.disposed = true;
36+
this.socket.Dispose();
37+
}
38+
39+
internal Task ConnectAsync(int port)
40+
{
41+
return this.socket.ConnectAsync(new IPEndPoint(new IPAddress(new byte[] { 127, 0, 0, 1 }), port));
42+
}
43+
44+
private void ThrowIfDisposed()
45+
{
46+
if (this.disposed)
47+
{
48+
throw new ObjectDisposedException(nameof(Client));
49+
}
50+
}
51+
}

ValidCode/StructBuilder/Request.cs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
namespace ValidCode.StructBuilder;
2+
3+
using System;
4+
using System.Buffers;
5+
using System.Buffers.Binary;
6+
using System.Buffers.Text;
7+
using System.Diagnostics;
8+
using System.Threading;
9+
10+
[DebuggerDisplay("{ToString(),nq}")]
11+
public record struct Request : IDisposable
12+
{
13+
private static int id;
14+
15+
private readonly byte[] bytes = ArrayPool<byte>.Shared.Rent(1024);
16+
private int position = 4;
17+
18+
public Request()
19+
{
20+
}
21+
22+
public void Dispose() => ArrayPool<byte>.Shared.Return(this.bytes);
23+
24+
internal static int GetNextValidId() => Interlocked.Increment(ref id);
25+
26+
#pragma warning disable IDE0060 // Remove unused parameter
27+
internal Request Append(string? value, string? name = null)
28+
#pragma warning restore IDE0060 // Remove unused parameter
29+
{
30+
if (value is not null)
31+
{
32+
foreach (var c in value)
33+
{
34+
this.bytes[this.position] = (byte)c;
35+
this.position++;
36+
}
37+
}
38+
39+
this.bytes[this.position] = 0;
40+
this.position++;
41+
return this;
42+
}
43+
44+
internal Request Append(int value, string? name = null)
45+
{
46+
if (Utf8Formatter.TryFormat(value, this.bytes.AsSpan(this.position), out var bytesWritten))
47+
{
48+
this.position += bytesWritten;
49+
this.bytes[this.position] = 0;
50+
this.position++;
51+
return this;
52+
}
53+
54+
throw new InvalidOperationException($"error writing {name}");
55+
}
56+
57+
internal Request Append(bool value, string? name = null) => this.Append(value ? 1 : 0, name);
58+
59+
internal ReadOnlyMemory<byte> LengthPrefixed()
60+
{
61+
BinaryPrimitives.WriteInt32BigEndian(this.bytes.AsSpan(0), this.position - 4);
62+
return new(this.bytes, 0, this.position);
63+
}
64+
}

0 commit comments

Comments
 (0)