Expressions and operators for specifications
Verus extends Rust’s syntax with additional operators and expressions useful for writing specifications. For example:
forall|i: int, j: int| 0 <= i <= j < len ==> f(i, j)
This snippet illustrates:
- the
forallquantifier, which we will cover later - chained operators
- implication operators
Here, we’ll discuss the last two, along with Verus notation for conjunction, disjunction, and field access.
Chained inequalities
Specifications can chain together multiple <=, <, >=, and > operations.
For example,
0 <= i <= j < len has the same meaning as 0 <= i && i <= j && j < len.
Logical implication
To make specifications more readable, Verus supports an implication operator ==>.
The expression a ==> b (pronounced “a implies b”) is logically equivalent to !a || b.
As an example, the expression
forall|i: int, j: int| 0 <= i <= j < len ==> f(i, j)
means that for every pair i and j such that 0 <= i <= j < len, f(i, j) is true.
Note that ==> has lower precedence that most other boolean operations.
For example, a ==> b && c means a ==> (b && c).
Verus also supports two-way implication for booleans (<==>) with even lower precedence,
so that a <==> b && c is equivalent to a == (b && c).
See the reference for a full description of precedence
in Verus.
Conjunction and disjunction
Because &&, ||, and ==> are so common in Verus specifications, it is often desirable to have
low precedence versions of && and ||. Verus also supports “triple-and” (&&&) and
“triple-or” (|||) which are equivalent to && and || except for their precedence.
Implication ==> and equivalence <==> bind more tightly than either &&& or |||.
&&& and ||| are also convenient for the “bulleted list” form:
&&& a ==> b
&&& c
&&& d <==> e && f
This has the same meaning as (a ==> b) && c && (d <==> (e && f)).
Accessing fields of a struct or enum
Verus has ->, is, and matches syntax for accessing fields
of structs
and matching variants of enums.