Messages
Message
A message is a list-like composite of structs:
from hydration import * class Header(Struct): magic = UInt32(0xDEADBEEF) class Body(Struct): param1 = Float(2.875) param2 = Int8(-128)
>>> msg = Header() / Body() # Create a message by using the division operator on structs >>> print(msg) Header: magic: UInt32(3735928559) Body: param1: Float(2.875) param2: Int8(-128) >>> bytes(msg) b'\xef\xbe\xad\xde\x00\x008@\x80'
MetaField
Messages allow the usage of another type of field, called MetaField,
Length
Let's assume you want to include the length of the struct in the header.
The value of the InclusiveLengthField will be equal to the length of the
following structs of the message (including its own struct):
from hydration import * class Header1(Struct): message_len = InclusiveLengthField(UInt16) class Body1(Struct): some_data = UInt64(0xAABB)
print(Header1() / Body1()) Header1: message_len: UInt16(10) Body1: some_data: UInt64(43707)
As you can see, the value of message_len is 10. (2 byte-long header, and 8 byte-long body)
You can also use an ExclusiveLengthField. In which case, the field's length calculation
excludes the length of its own struct:
from hydration import * class Header2(Struct): message_len = ExclusiveLengthField(UInt16)
>>> print(Header2() / Body1()) Header2: message_len: UInt16(8) Body1: some_data: UInt64(43707)
Now the value of message_len is 8.
Opcode
An OpcodeField will update automatically based on a given mapping
from hydration import * class Body2(Struct): data2 = UInt32(20) class Body3(Struct): data3 = UInt64(40) opcode_dict = { Body2: 1, Body3: 2, } class Header3(Struct): opcode = OpcodeField(UInt32, opcode_dict)
>>> print(Header3() / Body2()) Header3: opcode: UInt32(1) Body2: data2: UInt32(20) >>> print(Header3() / Body3()) Header3: opcode: UInt32(2) Body3: data3: UInt64(40)