3.4. Conditional Fields#

Conditional fields allow you to define fields in a struct that are included or excluded based on certain conditions. This feature is especially useful when working with versioned formats or optional fields that depend on runtime conditions. You can easily achieve this using context-based lambdas, which are built into the library.

3.4.1. How it works#

By using the with keyword in combination with conditional expressions, you can bind certain fields to a specific condition. This allows you to include or exclude fields dynamically, depending on the value of other fields or context.

Here’s an example demonstrating how to use conditional fields for versioned structs:

Conditional fields (e.g. for versioned structs)#
@struct
class Format:
    version: uint32
    # all following fields will be bound to the condition
    with this.version == 1:
        header: uint8

3.4.2. Key Concepts#

  1. `with` and Conditionals: The with keyword is used to define a block of fields that should only be included if the condition evaluates to True. In the example above, the fields inside with this.version == 1 are included only when the version field has a value of 1.

  2. `ElseIf` for Multiple Conditions: For multiple conditions, use ElseIf rather than Else. The ElseIf construct ensures that the next condition is checked only if the previous one was false. This is safer and more predictable than using a generic Else clause, which could introduce unintended side effects by executing under unanticipated conditions.

3.4.2.1. Example: Versioned Struct#

Conditional fields are particularly useful when dealing with versioned structs, where the structure of the data may change based on the version number or other factors. For example:

Conditional fields (e.g. for versioned structs)#
@struct
class Format:
    version: uint32
    # all following fields will be bound to the condition
    with this.version == 1:
        length: uint8
        extra: uint8
        data: Bytes(this.length)
    # Use else-if over 'Else' alone
    with ElseIf(this.version == 2):
        name: CString(16)
        data: Prefixed(uint8)

3.4.3. Best Practices#

  • Avoid Using `Else`: It is strongly recommended to avoid using Else for conditional field inclusion, as it can introduce unintended behavior if not properly managed. Instead, always use ElseIf with an inverted condition to ensure more predictable and controlled struct parsing.

Note

When using conditional fields, it’s essential to remember that the struct’s layout can change dynamically depending on the conditions. This flexibility makes it possible to define complex, version-dependent data structures.