4. Try partial input

This continues the frame defined in 2. Define and pack a structure. A relay reads client connections with socket.recv(), which returns whatever bytes happened to be available – not necessarily a whole frame. unpack() would raise on a buffer that just ends early; there would be no way to tell “wait for more” apart from “this is corrupt.” rustruct.Struct.parse() makes that distinction: it returns rustruct.Incomplete rather than throwing when more bytes could complete the value:

from rustruct import Incomplete, Struct, U8, U16, U32, digest, slice


class ChatFrame(Struct, byteorder="network"):
    kind: U8
    seq: U16
    body_length: U16
    body: bytes = slice(len="body_length")
    crc: U32 = digest("crc32", over="*")


wire = ChatFrame(kind=2, seq=1, body=b"hello").pack()

result = ChatFrame.parse(wire[:3])
assert isinstance(result, Incomplete)
assert result.needed > 0

decoded, position = ChatFrame.parse(wire)

A relay’s read loop keeps calling recv() and appending to a buffer until parse() stops returning rustruct.Incomplete – reading at least rustruct.Incomplete.needed additional bytes before trying again. Invalid complete data still raises rustruct.InvalidDataError.

Previous: 3. Decode the message. Next: 5. Inspect an error.