/// <summary> /// Performs copy processing from the reader to the writer. /// </summary> /// <typeparam name="T">The type of the items to copy.</typeparam> /// <param name="reader">The source.</param> /// <param name="writer">The target.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Async execution TPL task.</returns> public static async Task Copy <T>( this IChannelReader <T> reader, IChannelWriter <T> writer, CancellationToken cancellationToken = default, ChannelCompletionPassthroughProc producerCompletionPassthroughProc = null, ChannelCompletionPassthroughProc consumerCompletionPassthroughProc = null, Func <T, ValueTask> handleLostItemsProc = null) { VxArgs.NotNull(reader, nameof(reader)); VxArgs.NotNull(writer, nameof(writer)); CancellationToken readCancellationToken = cancellationToken; if (producerCompletionPassthroughProc == null) { producerCompletionPassthroughProc = (error, isFromChannel) => { writer.TryComplete(error); return(new ValueTask()); }; } if (consumerCompletionPassthroughProc == null) { consumerCompletionPassthroughProc = (error, isFromChannel) => { reader.TryComplete(error); return(new ValueTask()); }; } Exception handlersError = null; try { while (true) { T item; try { if (!reader.TryRead(out item)) { if (!await reader.WaitToReadAsync(readCancellationToken)) { Exception error = null; try { await reader.Completion; } catch (Exception ex) { error = ex; } finally { try { await producerCompletionPassthroughProc(error); } catch (Exception ex) { handlersError = ex; } } return; } else { continue; } } } catch (Exception error) { try { await producerCompletionPassthroughProc(error, false); } catch (Exception ex) { handlersError = ex; } return; } // Trying to write, until target closed, or cancellation raised. while (true) { try { if (writer.TryWrite(item)) { break; } if (!await writer.WaitToWriteAsync(readCancellationToken)) { if (handleLostItemsProc != null) { try { await handleLostItemsProc(item); } catch (Exception ex) { handlersError = ex; } } Exception error = null; try { await writer.Completion; } catch (Exception ex) { error = ex; } finally { try { await consumerCompletionPassthroughProc(error); } catch (Exception ex) { handlersError = ex; } } return; } } catch (Exception error) { try { if (handleLostItemsProc != null) { try { await handleLostItemsProc(item); } catch (Exception ex) { handlersError = ex; } } } finally { try { await consumerCompletionPassthroughProc(error, false); } catch (Exception ex) { handlersError = ex; } } return; } } } } finally { if (handlersError != null) { throw handlersError; } } }