private async Task <object> DecodeAck(IReceiveState state)
        {
            await state.EnsureEnoughData(16);

            var guidBytes = new byte[16];

            Buffer.BlockCopy(state.Buffer, state.Offset, guidBytes, 0, guidBytes.Length);
            var guid = new Guid(guidBytes);

            return(new Ack(guid));
        }
        public async Task <object> Decode(IReceiveState state)
        {
            await state.EnsureEnoughData(4);

            var type = (TransportMessageType)state.Buffer[state.Offset++];

            switch (type)
            {
            case TransportMessageType.Message:
                return(await DecodeMessage(state));

            case TransportMessageType.Ack:
                return(await DecodeAck(state));

            case TransportMessageType.Nak:
                return(await DecodeNak(state));

            default:
                throw new NotSupportedException($"Have not implemented {type} just yet.");
            }
        }
        private async Task <TransportMessage> DecodeMessage(IReceiveState state)
        {
            var headers = new Dictionary <string, string>();

            while (true)
            {
                if (state.BytesLeftInBuffer < 3)
                {
                    await state.EnsureEnoughData(3);
                }

                var featureFlag = state.Buffer[state.Offset++];

                var stringLength = state.Buffer[state.Offset++];
                await state.EnsureEnoughData(stringLength);

                var headerName = Encoding.UTF8.GetString(state.Buffer, state.Offset, stringLength);
                state.Offset += stringLength;

                stringLength = state.Buffer[state.Offset++];
                await state.EnsureEnoughData(stringLength);

                var headerValue = Encoding.UTF8.GetString(state.Buffer, state.Offset, stringLength);
                state.Offset += stringLength;

                headers.Add(headerName, headerValue);

                if ((featureFlag & (byte)TransportHeaderFeatureFlags.EndOfHeaders) != 0)
                {
                    break;
                }
            }

            if (!headers.TryGetValue(Headers.ContentLength, out var contentLengthValue))
            {
                throw new InvalidOperationException($"Expected header '{Headers.ContentLength}' to be specified.");
            }

            Guid messageId;

            if (headers.TryGetValue(Headers.MessageId, out var messageIdStr))
            {
                messageId = Guid.Parse(messageIdStr);
            }
            else
            {
                throw new InvalidOperationException("All messages must have an id.");
            }

            var contentLength = int.Parse(contentLengthValue);

            state.EnsureBufferSize(contentLength);

            var bytesLeft = contentLength - state.BytesLeftInBuffer;
            await state.EnsureEnoughData(bytesLeft);

            var body = _transportSerializer.Deserialize(state.Buffer, state.Offset, contentLength, headers);

            state.Offset += contentLength;

            return(new TransportMessage(body)
            {
                Id = messageId,
                Headers = headers
            });
        }
        public async Task <byte> DecodeHandshake(IReceiveState receiver)
        {
            await receiver.EnsureEnoughData(1);

            return(receiver.Buffer[receiver.Offset++]);
        }