/* PACKET ====== Byte/ 0 | 1 | 2 | 3 | / | | | | |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7| +---------------+---------------+---------------+---------------+ 0/ HEADER / / / / / / / +---------------+---------------+---------------+---------------+ 24/ COMMAND-SPECIFIC EXTRAS (as needed) / +/ (note length in the extras length header field) / +---------------+---------------+---------------+---------------+ m/ Key (as needed) / +/ (note length in key length header field) / +---------------+---------------+---------------+---------------+ n/ Value (as needed) / +/ (note length is total body length header field, minus / +/ sum of the extras and key length body fields) / +---------------+---------------+---------------+---------------+ Total 24 bytes */ bool IRequest.WriteTo(WriteBuffer buffer) { // 0. init header // 1. loop on header // 2. loop on Key, if any // 3. loop on Data, if any // 4. done switch (state) { case STATE_WRITE_HEADER: // this will either get a Span that can fit the header data or nothing // we will not write partial header var span = buffer.Want(Protocol.HeaderLength); if (span.IsEmpty) return true; // header does not fit into the request buffer WriteHeader(span); if (finalBody.IsEmpty) break; // no body, quit writeOffset = 0; if (finalBody.IsSingleSegment) singleSegmentBody = finalBody.First; else bodyCopier = new SequenceCopier(finalBody, buffer); state = STATE_WRITE_BODY; goto case STATE_WRITE_BODY; case STATE_WRITE_BODY: // body is only one span, write it until it's gone if (!singleSegmentBody.IsEmpty) { writeOffset += buffer.TryAppend(singleSegmentBody.Slice(writeOffset).Span); if (writeOffset < singleSegmentBody.Length) return true; Debug.Assert(writeOffset == singleSegmentBody.Length); } else { Debug.Assert(bodyCopier != null); // body consists of munltiple spans; the SequenceCopier will process it if (bodyCopier.Copy()) return true; bodyCopier = default; } break; default: throw new InvalidOperationException("undhandled state: " + state); // should not happen } state = STATE_DONE; //bodyBuilder.Dispose(); finalBody = default; return false; }