|
|
|
|
|
by Arnavion
710 days ago
|
|
I'm not sure what part of that is supposed to be a pain. The sans-io equivalent would be: handle_input(buf) -> Result {
if len(buf) < 4 { return Error::IncompletePacket }
len = toInt(buf[0..4])
if len(buf) < 4 + len { return Error::IncompletePacket }
packet = buf[4..(4 + len)]
return Ok { packet: packet, consumed: 4 + len }
}
where the semantics of `Error::IncompletePacket` are that the caller reads more into the buffer from its actual IO layer and then calls handle_input() again. So your "while not received required bytes: accumulate in buf" simply become "if len < required: return Error::IncompletePacket" |
|
In effect, you have to be thoughtful (and explicit!) about the event loop semantics demanded by each state machine and, as the event loop implementer, you have to satisfy all of those semantics faithfully.
A few alternatives include your version, one where `handle_input` returns something like `Result<Option<Packet>>` covering both error cases and successful partial consumption cases, one where `handle_input` tells the event loop how much additional input it knows it needs whenever it finishes parsing a length field and requires that the event loop not call it again until it can hand it exactly that many bytes.
This can all be pretty non-trivial. And then you'd want to compose state machines with different anticipated semantics. It's not obvious how to do this well.