private async Task <int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken, bool sync)
        {
            using (sync ? _mutex.Lock(cancellationToken) : await _mutex.LockAsync(cancellationToken).ConfigureAwait(false))
            {
                while (Empty && !_completed)
                {
                    if (sync)
                    {
                        _notEmptyOrCompleted.Wait(cancellationToken);
                    }
                    else
                    {
                        await _notEmptyOrCompleted.WaitAsync(cancellationToken).ConfigureAwait(false);
                    }
                }
                cancellationToken.ThrowIfCancellationRequested();

                if (AvailableToRead == 0)
                {
                    return(0);
                }

                // Copy the data from the stream
                var bytesToCopy = Math.Min(count, AvailableToRead);
                Array.Copy(_data.First.Value, _headDataBytesRead, buffer, offset, bytesToCopy);

                // Remove those bytes from the stream
                if (bytesToCopy == AvailableToRead)
                {
                    _data.RemoveFirst();
                    _headDataBytesRead = 0;
                }
                else
                {
                    _headDataBytesRead += bytesToCopy;
                }
                _currentBytes  -= bytesToCopy;
                ReaderPosition += bytesToCopy;

                _notFullOrCompleted.Notify();
                return(bytesToCopy);
            }
        }
        private async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken, bool sync)
        {
            using (sync ? _mutex.Lock(cancellationToken) : await _mutex.LockAsync(cancellationToken).ConfigureAwait(false))
            {
                while (count != 0)
                {
                    while (Full && !_completed)
                    {
                        if (sync)
                        {
                            _notFullOrCompleted.Wait(cancellationToken);
                        }
                        else
                        {
                            await _notFullOrCompleted.WaitAsync(cancellationToken).ConfigureAwait(false);
                        }
                    }
                    if (_completed)
                    {
                        throw new OperationCanceledException("Stream has been closed for writing.");
                    }
                    cancellationToken.ThrowIfCancellationRequested();

                    // Copy the data
                    var bytesToCopy = Math.Min(count, AvailableToWrite);
                    var data        = new byte[bytesToCopy];
                    Array.Copy(buffer, offset, data, 0, bytesToCopy);

                    // Add it to the stream
                    _data.AddLast(data);
                    _currentBytes  += bytesToCopy;
                    WriterPosition += bytesToCopy;

                    // Adjust status of current operation
                    offset += bytesToCopy;
                    count  -= bytesToCopy;

                    _notEmptyOrCompleted.Notify();
                }
            }
        }