Struct packs and unpacks values according to a declared binary layout, including byte order and field widths.
Python struct: a fixed-endian receipt record with exact byte length
Operation contract
The receipt wire format is exactly nine bytes: a one-byte version, a four-byte identifier and a four-byte amount, all in network byte order. The encoder rejects Boolean values and unsigned overflow before packing. The decoder rejects truncation and trailing bytes before unpacking, then rejects an unsupported version. A file containing several records would need framing and a count or total-byte bound rather than this single-record function.
Failure and ownership boundary
Native alignment depends on the host ABI. The explicit ! prefix avoids silently changing the protocol across machines. The record has no signature or checksum; successfully unpacking bytes does not establish their origin. Python memoryview: shared buffers and explicit release, Python array: fixed-width numeric storage is not a portable wire encoding and Python HMAC envelopes: authenticate exact bytes and separate replay policy cover different ownership and trust boundaries.
Working program
import struct
RECEIPT = struct.Struct("!BII")
def encode_receipt(receipt_id, amount):
if any(type(value) is not int or not 0 <= value <= 0xFFFFFFFF
for value in (receipt_id, amount)):
raise ValueError("unsigned exact integers required")
return RECEIPT.pack(1, receipt_id, amount)
def decode_receipt(payload):
if type(payload) is not bytes or len(payload) != RECEIPT.size:
raise ValueError("exact record bytes required")
version, receipt_id, amount = RECEIPT.unpack(payload)
if version != 1:
raise ValueError("unsupported version")
return receipt_id, amount
payload = encode_receipt(41, 125)
print("bytes:", payload.hex())
print("record:", decode_receipt(payload))
for invalid in (payload[:-1], payload + b"x", bytes([2]) + payload[1:]):
try:
decode_receipt(invalid)
except ValueError:
print("record rejected")Output
bytes: 01000000290000007d
record: (41, 125)
record rejected
record rejected
record rejectedCosts and limits
The format has fixed time and space costs because the field count and widths are fixed. A bytes argument can already be large before this function receives it; bound reception at the transport too. Rejecting an invalid version does not reverse bytes consumed by an earlier reader.
Common Mistakes
- Never use implicit native alignment for a portable wire contract.
- Do not accept a valid prefix while ignoring unexplained trailing bytes.
Connected lessons
Python strings and bytes: reject decoding errors before parsing records, Python strict Base64: reject alternate spellings before decoding a record, Python HMAC envelopes: authenticate exact bytes and separate replay policy.
Follow the ownership and update boundary
Python socket recv: assemble a bounded frame across partial reads.
