21.6.6 Field Constraints

It is common for struct fields to be constrained to their values to satisfy some conditions. Obvious examples are magic numbers, and specification-derived constraints.

In Poke you can specify a field’s constraint using the following syntax:

field_type field_name : expression ;

where expression is an arbitrary Poke expression, that should evaluate to an integer value. The result is interpreted as a boolean. As an example, this is how the ELF magic number is checked for:

type Ctf_Preamble =
  struct
  {
    uint<16> ctp_magic : ctp_magic == CTF_MAGIC;
    byte ctp_version;
    byte ctp_flags;
  };

The constraint expression will often include the field where it is installed, but that’s not mandatory.

Field constraints play an important role in mapping. On one side, a map will fail if there is some constraint that fails. On the other, they guide the mapping of unbounded arrays. See Mapping Arrays.

Another common usage of constraint expressions is to alter the global state after decoding a field. For example, this is how mapping an ELF header sets the current endianness, depending on the value of ei_data:

byte ei_data : ei_data == ELFDATA2LSB       \
               ? set_endian (ENDIAN_LITTLE) \
               : set_endian (ENDIAN_BIG);

Note that set_endian always returns 1.