Resume a Retained Length-Prefixed Frame with One Send Cursor
A transport-focused procedure for writing one length-prefixed UTF-8 frame through short writes without regenerating bytes, duplicating the prefix, interleaving frames, or releasing the retained payload too early.
Resume a Retained Length-Prefixed Frame with One Send Cursor
Use this procedure after a length prefix has already been derived from the exact retained UTF-8 payload buffer. Its concern is transport progress: a write call may accept only part of the offered bytes, including part of the prefix or a span that crosses from prefix into payload.
The invariant is that one frame has one immutable byte identity and one monotonic progress position. Never rebuild text, re-encode the payload, restart the prefix, or let another frame interleave while the current frame is incomplete.
Represent the pending frame
Retain this state until completion or terminal failure:
- The fixed encoded prefix bytes.
- The exact UTF-8 payload buffer whose byte length produced that prefix.
- One cursor measured in bytes from the start of the logical frame.
- The logical frame length, equal to prefix length plus payload length.
- Ownership that permits only one writer to advance this connection's outbound frame sequence.
The prefix and payload may remain separate buffers. They form one logical byte sequence for progress accounting, so concatenating them is optional.
Map one cursor to the remaining regions
Before each write attempt, derive the remaining slices from the cursor:
- If the cursor is smaller than the prefix length, offer the unconsumed suffix of the prefix followed by the payload.
- If the cursor is at least the prefix length, subtract the prefix length and offer only the unconsumed suffix of the retained payload.
- If the cursor equals the logical frame length, the frame is complete and no further write is allowed.
- Treat a cursor below zero or beyond the logical frame length as corrupted state.
A gathering-write API may receive both remaining regions at once. A single-buffer API may send the current region and continue with the next region on a later call. Both approaches use the same cursor rule.
Advance only by confirmed progress
For each nonempty write attempt:
- Call the transport with only the slices derived from the current cursor.
- Interpret the result according to that API's documented contract.
- If it reports a positive accepted-byte count, first verify that the count does not exceed the number of bytes offered.
- Add exactly that count to the cursor.
- Do not infer that an offered slice was fully accepted merely because the call returned normally.
- If bytes remain, preserve the same prefix, payload, and cursor for the next writable opportunity.
A short write can end inside the prefix, exactly at the boundary, or inside the payload. The cursor mapping handles all three cases without special reconstruction.
If a nonblocking API reports zero progress for nonempty input, do not advance the cursor and do not spin in a tight retry loop. Wait for its documented readiness signal or apply its documented closed-connection rule. Retryable backpressure preserves the frame state; a terminal transport failure ends the frame without pretending it was completely sent.
Preserve connection ordering
Only one execution path may advance the outbound cursor for a connection at a time. Queue later frames behind the incomplete frame. Allowing another prefix or payload to enter the byte stream before the current cursor reaches completion corrupts framing even when every individual frame was constructed correctly.
If cancellation can race with a write, define which component owns the frame state and transport. Do not hand the same cursor to two writers. If the API leaves the accepted-byte outcome unknown, do not blindly replay the frame on the same byte stream; close or recover according to a higher-level protocol that can resolve ambiguity.
Release at the right boundary
The transport's positive return normally means that it accepted a number of bytes under its own contract, not that the peer parsed or acknowledged the frame. Advance the cursor according to that contract.
Release or reuse the prefix and retained payload only when one of these conditions holds:
- The cursor equals the logical frame length and the API permits caller buffers to be released after acceptance.
- A terminal failure has ended the connection or otherwise made the pending frame unreachable.
Do not release the payload merely because the prefix was accepted. Do not mutate or pool the payload while any unsent suffix still references it. If the API retains caller memory asynchronously, follow its later completion boundary instead of assuming the write call is the lifetime boundary.
Reasoned progress trace
This is a reasoned example, not an executed test.
Assume a two-byte prefix and a five-byte retained payload, so the logical frame length is seven bytes. A first call accepts one byte, leaving the cursor at one inside the prefix. A second gathering write offers the final prefix byte and all five payload bytes; if it accepts three bytes, the cursor becomes four. That means both prefix bytes and the first two payload bytes have been accepted. The next attempt therefore begins at payload offset two. When three more bytes are accepted, the cursor becomes seven and the frame is complete.
At no point is the prefix resent or the payload regenerated.
Verification checklist
Run implementation tests before claiming runtime evidence:
- Short writes at every cursor position from zero through the final byte.
- A write that stops inside the prefix.
- A write that stops exactly at the prefix and payload boundary.
- A gathering write whose accepted count crosses that boundary.
- Repeated zero-progress or retryable-backpressure results without cursor movement or busy looping.
- A reported count larger than the offered remainder, rejected as an API or adapter violation.
- Two queued frames, proving that no byte from the second appears before the first completes.
- Cancellation and error paths, proving there is only one cursor owner.
- Buffer pooling or reuse checks, proving the payload remains unchanged until its documented release boundary.
- A receiver integration test, proving consecutive frames remain aligned under forced short writes.
Until these tests are executed, describe the trace and expected behavior as reasoned properties rather than observed results.