@@ -181,28 +181,14 @@ public override void Write(byte[] buffer, int offset, int count)
181
181
182
182
public override async Task < int > ReadAsync ( byte [ ] buffer , int offset , int count , CancellationToken cancellationToken )
183
183
{
184
- var linkedCancellationToken = GetLinkedCancellationToken ( _streamCancellationToken , cancellationToken ) ;
185
- return await _pipeReaderStream . ReadAsync ( buffer . AsMemory ( offset , count ) , linkedCancellationToken ) ;
184
+ using var linkedCts = ValueLinkedCancellationTokenSource . Create ( _streamCancellationToken , cancellationToken ) ;
185
+ return await _pipeReaderStream . ReadAsync ( buffer . AsMemory ( offset , count ) , linkedCts . Token ) ;
186
186
}
187
187
188
188
public override async ValueTask < int > ReadAsync ( Memory < byte > buffer , CancellationToken cancellationToken = default )
189
189
{
190
- var linkedCancellationToken = GetLinkedCancellationToken ( _streamCancellationToken , cancellationToken ) ;
191
- return await _pipeReaderStream . ReadAsync ( buffer , linkedCancellationToken ) ;
192
- }
193
-
194
- private static CancellationToken GetLinkedCancellationToken ( CancellationToken a , CancellationToken b )
195
- {
196
- if ( a . CanBeCanceled && b . CanBeCanceled )
197
- {
198
- return CancellationTokenSource . CreateLinkedTokenSource ( a , b ) . Token ;
199
- }
200
- else if ( a . CanBeCanceled )
201
- {
202
- return a ;
203
- }
204
-
205
- return b ;
190
+ using var linkedCts = ValueLinkedCancellationTokenSource . Create ( _streamCancellationToken , cancellationToken ) ;
191
+ return await _pipeReaderStream . ReadAsync ( buffer , linkedCts . Token ) ;
206
192
}
207
193
208
194
private async Task ThrowOnTimeout ( )
@@ -243,4 +229,45 @@ protected override void Dispose(bool disposing)
243
229
244
230
_disposed = true ;
245
231
}
232
+
233
+ // A helper for creating and disposing linked CancellationTokenSources
234
+ // without allocating, when possible.
235
+ // Internal for testing.
236
+ internal readonly struct ValueLinkedCancellationTokenSource : IDisposable
237
+ {
238
+ private readonly CancellationTokenSource ? _linkedCts ;
239
+
240
+ public readonly CancellationToken Token ;
241
+
242
+ // For testing.
243
+ internal bool HasLinkedCancellationTokenSource => _linkedCts is not null ;
244
+
245
+ public static ValueLinkedCancellationTokenSource Create (
246
+ CancellationToken token1 , CancellationToken token2 )
247
+ {
248
+ if ( ! token1 . CanBeCanceled )
249
+ {
250
+ return new ( linkedCts : null , token2 ) ;
251
+ }
252
+
253
+ if ( ! token2 . CanBeCanceled )
254
+ {
255
+ return new ( linkedCts : null , token1 ) ;
256
+ }
257
+
258
+ var linkedCts = CancellationTokenSource . CreateLinkedTokenSource ( token1 , token2 ) ;
259
+ return new ( linkedCts , linkedCts . Token ) ;
260
+ }
261
+
262
+ private ValueLinkedCancellationTokenSource ( CancellationTokenSource ? linkedCts , CancellationToken token )
263
+ {
264
+ _linkedCts = linkedCts ;
265
+ Token = token ;
266
+ }
267
+
268
+ public void Dispose ( )
269
+ {
270
+ _linkedCts ? . Dispose ( ) ;
271
+ }
272
+ }
246
273
}
0 commit comments