turnloop_websocket::Received has the same two independent zero cases as http1::Step and http2::Step, and the same absence of any words about them.
consumed == 0 means "I need more input, wait".
consumed > 0 with no event means "progress was made, call me again" — the frame header of a message whose payload has not arrived, a control frame handled internally, a continuation.
A host that loops while "an event came back" stalls on the second case. A host that loops while "bytes were consumed" spins on the first. Neither is stated, and the type's shape does not distinguish them.
Why this one is worth doing on its own
This is the fourth instance of the same class in this crate:
PR #85 closes the observed class for turnloop-http: both its decoders now carry a stated contract with tests that fail when it is violated, including tests asserting that each wrong loop condition actually breaks. turnloop_websocket::Received is the same shape in a different crate and was not in that PR's scope.
What would fix it
Document both zero cases on Received, and add the same pair of tests turnloop-http now has: one proving a host that loops on "an event came back" stalls, and one proving a host that loops on "bytes were consumed" spins. A stated contract that nothing tests is how the previous three got shipped.
Worth checking receive's idempotence while there: the HTTP/2 work found that http2::Connection::receive is not idempotent, so a host that stalls and retries the same input fails the connection rather than making progress — a second-order trap that only appears once the first one bites.
Not this issue
A workspace-wide contract — one trait plus a turnloop-contract conformance suite across all four step-like types and the five database protocols that have no step type at all — is a larger, breaking change and deserves its own review. This issue is the single-type version, which needs no design settled.
turnloop_websocket::Receivedhas the same two independent zero cases ashttp1::Stepandhttp2::Step, and the same absence of any words about them.consumed == 0means "I need more input, wait".consumed > 0with no event means "progress was made, call me again" — the frame header of a message whose payload has not arrived, a control frame handled internally, a continuation.A host that loops while "an event came back" stalls on the second case. A host that loops while "bytes were consumed" spins on the first. Neither is stated, and the type's shape does not distinguish them.
Why this one is worth doing on its own
This is the fourth instance of the same class in this crate:
http1::Decodernever raisesEvent::Upgradeon the request side; the asymmetry betweenMode::RequestandMode::Responseis undocumented. Cost Perry's P5 lane a debugging cycle.http1::DecoderraisesEvent::Endfrom a step that consumes zero bytes. Cost two lanes a cycle each; the second one produced a client that worked and was five seconds slower per request.http2::Step's two zero cases, found by Perry's HTTP/2 lane, which stalled at the client preface. Fixed in PR A terminated HTTP/2 stream no longer takes the connection with it #85, which also states and tests the contract for bothturnloop-httpdecoders.PR #85 closes the observed class for
turnloop-http: both its decoders now carry a stated contract with tests that fail when it is violated, including tests asserting that each wrong loop condition actually breaks.turnloop_websocket::Receivedis the same shape in a different crate and was not in that PR's scope.What would fix it
Document both zero cases on
Received, and add the same pair of teststurnloop-httpnow has: one proving a host that loops on "an event came back" stalls, and one proving a host that loops on "bytes were consumed" spins. A stated contract that nothing tests is how the previous three got shipped.Worth checking
receive's idempotence while there: the HTTP/2 work found thathttp2::Connection::receiveis not idempotent, so a host that stalls and retries the same input fails the connection rather than making progress — a second-order trap that only appears once the first one bites.Not this issue
A workspace-wide contract — one trait plus a
turnloop-contractconformance suite across all four step-like types and the five database protocols that have no step type at all — is a larger, breaking change and deserves its own review. This issue is the single-type version, which needs no design settled.