/// <summary>
        /// Tries to propagate completion from the reader to the writer.
        /// </summary>
        /// <typeparam name="T">The type of the items in the reader and writer.</typeparam>
        /// <param name="reader">The reader.</param>
        /// <param name="writer">The writer.</param>
        /// <param name="passthroughError"><see langword="true"/> - passthrough error, <see langword="false"/> - mute error.</param>
        /// <returns>true, if completion was propagated, false otherwise.</returns>
        public static bool TryPropagateCompletion <T>(
            this IChannelReader <T> reader,
            IChannelWriter <T> writer,
            bool passthroughError = true)
        {
            VxArgs.NotNull(reader, nameof(reader));
            VxArgs.NotNull(writer, nameof(writer));

            if (reader.Completion.IsCompleted)
            {
                Exception error = null;
                try
                {
                    reader.Completion.GetAwaiter().GetResult();
                }
                catch (Exception ex)
                {
                    if (passthroughError)
                    {
                        error = ex;
                    }
                }

                return(writer.TryComplete(error));
            }

            return(false);
        }
        /// <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;
                }
            }
        }