Level 1 Where does each field live?
A serializer lays out a record as a run of bytes: its fields are stored one after another in declaration order, the first at byte 0, each field taking a fixed number of bytes and the next one starting right where it ends (no gaps).
Build ObjectLayout(fields) where fields is a list of (name, size) pairs, and implement:
offset(name) -> int: the byte where the field starts.size(name) -> int: its size in bytes.total_size() -> int: the size of the whole record (0with no fields).field_at(byte) -> str | None: the name of the field that covers that byte, orNoneifbyteis outside[0, total_size()).
Errors: a duplicate name or a size below 1 raises ValueError in the constructor; asking offset/size for an unknown name raises KeyError.
layout = ObjectLayout([("tag", 2), ("price", 8), ("qty", 4)])
layout.offset("price") # 2
layout.offset("qty") # 10
layout.total_size() # 14
layout.field_at(9) # "price" (bytes 2..9)
layout.field_at(10) # "qty"
layout.field_at(14) # None
layout.offset("side") # KeyError
A record may have 10**5 fields and the tests ask 10**5 questions, so don't walk the field list on every call.
Show hint
Precompute a list of start offsets in the constructor plus a name -> index dict. field_at is then a bisect_right(starts, byte) - 1.