public override void Write(IChannelHandlerContext ctx, int allowedBytes)
            {
                int queuedData = _queue.ReadableBytes();

                if (!_endOfStream)
                {
                    if (0u >= (uint)queuedData)
                    {
                        if (_queue.IsEmpty())
                        {
                            // When the queue is empty it means we did clear it because of an error(...) call
                            // (as otherwise we will have at least 1 entry in there), which will happen either when called
                            // explicit or when the write itself fails. In this case just set dataSize and padding to 0
                            // which will signal back that the whole frame was consumed.
                            //
                            // See https://github.com/netty/netty/issues/8707.
                            _padding = _dataSize = 0;
                        }
                        else
                        {
                            // There's no need to write any data frames because there are only empty data frames in the
                            // queue and it is not end of stream yet. Just complete their promises by getting the buffer
                            // corresponding to 0 bytes and writing it to the channel (to preserve notification order).
                            var writePromise0 = ctx.NewPromise();
                            AddListener(writePromise0);
                            _ = ctx.WriteAsync(_queue.Remove(0, writePromise0), writePromise0);
                        }
                        return;
                    }

                    if (0u >= (uint)allowedBytes)
                    {
                        return;
                    }
                }

                // Determine how much data to write.
                int writableData = Math.Min(queuedData, allowedBytes);
                var writePromise = ctx.NewPromise();

                AddListener(writePromise);
                var toWrite = _queue.Remove(writableData, writePromise);

                _dataSize = _queue.ReadableBytes();

                // Determine how much padding to write.
                int writablePadding = Math.Min(allowedBytes - writableData, _padding);

                _padding -= writablePadding;

                // Write the frame(s).
                _ = _owner._frameWriter.WriteDataAsync(ctx, _stream.Id, toWrite, writablePadding,
                                                       _endOfStream && 0u >= (uint)Size, writePromise);
            }
        public void ReadExactAddedBufferSizeReturnsOriginal()
        {
            writeQueue.Add(cat, catPromise);
            writeQueue.Add(mouse, NewFutureListener());

            IPromise aggregatePromise = NewPromise();

            Assert.Same(cat, writeQueue.Remove(3, aggregatePromise));
            Assert.False(catPromise.IsSuccess);
            aggregatePromise.Complete();
            Assert.True(catPromise.IsSuccess);
            Assert.Equal(1, cat.ReferenceCount);
            cat.Release();

            aggregatePromise = NewPromise();
            Assert.Same(mouse, writeQueue.Remove(5, aggregatePromise));
            Assert.False(mouseDone);
            aggregatePromise.Complete();
            Assert.True(mouseSuccess);
            Assert.Equal(1, mouse.ReferenceCount);
            mouse.Release();
        }