Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Refinements

A refinement narrows an existing format to a subset of its values. The wire encoding and the Rust type are unchanged, only the set of accepted values shrinks.

Parsing. Parses the underlying format, then tests the predicate. A value outside the refinement is a parse error.

Preparation and serialization. Preparation tests the same predicate on the value and fails if it does not hold. Length and serialization are those of the underlying format.

The predicate is therefore enforced in both directions.

Integer constraints

constrained = {
    exact: u8 | 7,
    range: u16 | 1..1024,
    lower_bounded: u32 | 1..,
    upper_bounded: u16 | ..4096,
    selected: u8 | {1, 4, 9},
    except: u8 | !{0, 255},
}

Vest ranges include both supplied endpoints: 1..1024 accepts 1 through 1024. Either endpoint may be omitted. A set uses braces and commas; prefixing a constraint with ! takes its complement. Values and range endpoints must fit the underlying integer type.

Enum constraints

Named enum formats can be restricted by variant:

kind = enum {
    Request = 1,
    Response = 2,
    Error = 3,
}

messages = {
    request: kind | Request,
    not_error: kind | !Error,
    terminal: kind | {Response, Error},
}

Every named variant must belong to the referenced enum. The generated field still has type Kind; the refinement changes only which values are consistent with the format.