/* https://tools.ietf.org/html/rfc7540#section-4.1
         +-----------------------------------------------+
         |                 Length (24)                   |
         +---------------+---------------+---------------+
         |   Type (8)    |   Flags (8)   |
         +-+-------------+---------------+-------------------------------+
         |R|                 Stream Identifier (31)                      |
         +=+=============================================================+
         |                   Frame Payload (0...)                      ...
         +---------------------------------------------------------------+
         */
        internal static void WriteHeader(Http2Frame frame, PipeWriter output)
        {
            var buffer = output.GetSpan(Http2FrameReader.HeaderLength);

            Bitshifter.WriteUInt24BigEndian(buffer, (uint)frame.PayloadLength);
            buffer = buffer.Slice(3);

            buffer[0] = (byte)frame.Type;
            buffer[1] = frame.Flags;
            buffer    = buffer.Slice(2);

            Bitshifter.WriteUInt31BigEndian(buffer, (uint)frame.StreamId);

            output.Advance(Http2FrameReader.HeaderLength);
        }
        /* https://tools.ietf.org/html/rfc7540#section-6.8
         +-+-------------------------------------------------------------+
         |R|                  Last-Stream-ID (31)                        |
         +-+-------------------------------------------------------------+
         |                      Error Code (32)                          |
         +---------------------------------------------------------------+
         |                  Additional Debug Data (*)                    | (not implemented)
         +---------------------------------------------------------------+
         */
        public Task WriteGoAwayAsync(int lastStreamId, Http2ErrorCode errorCode)
        {
            lock (_writeLock)
            {
                _outgoingFrame.PrepareGoAway(lastStreamId, errorCode);
                WriteHeaderUnsynchronized();

                var buffer = _outputWriter.GetSpan(8);
                Bitshifter.WriteUInt31BigEndian(buffer, (uint)lastStreamId);
                buffer = buffer.Slice(4);
                BinaryPrimitives.WriteUInt32BigEndian(buffer, (uint)errorCode);
                _outputWriter.Advance(8);

                return(TimeFlushUnsynchronizedAsync());
            }
        }
        /* https://tools.ietf.org/html/rfc7540#section-6.9
         +-+-------------------------------------------------------------+
         |R|              Window Size Increment (31)                     |
         +-+-------------------------------------------------------------+
         */
        public Task WriteWindowUpdateAsync(int streamId, int sizeIncrement)
        {
            lock (_writeLock)
            {
                if (_completed)
                {
                    return(Task.CompletedTask);
                }

                _outgoingFrame.PrepareWindowUpdate(streamId, sizeIncrement);
                WriteHeaderUnsynchronized();
                var buffer = _outputWriter.GetSpan(4);
                Bitshifter.WriteUInt31BigEndian(buffer, (uint)sizeIncrement);
                _outputWriter.Advance(4);
                return(TimeFlushUnsynchronizedAsync());
            }
        }