Type-Level Operations
Metatypes like #int, #bool, or #str are not limited to values: a set of operations are available at the type level via const generics. These allow expressing rich definitions, constraints and conditions. They must be surrounded by curly braces inside type expressions, but may appear naked in other contexts like gen if conditions.
The following operations are supported:
- Arithmetic, on
#ints or#uints:+,-,*,/,%,<<,>>. - Ordering comparisons, on
#ints or#uints:<,>,<=,>=. - Logical comparisons,, on
#bools:!,&&,||,^^ - Equality comparisons, on any metatype:
==,!=.
Some extra function-like operations are supported:
uint::bits_for(x)returns the minimum amount of bits needed to represent as auintvalue. This value can be calculated as . Notably, it does not return , which may be desirable when calculating address widths for a certain element count. Given a collection of elements, addresses range from to , so in that case the correct expression would beuint::bits_for(N - 1).int::bits_for(x)returns the minimum amount of bits needed to represent as anintvalue including the sign bit. The exact value returned is better understood piecewise:- When , the unsigned representation of can be augmented with a sign bit, so the number of bits required for its signed integer representation is
uint::bits_for(x) + 1or . - When , the same number of bits is required to represent than to represent its positive counterpart. Taking into account the asymmetry of two’s complement representation ( maps to , not ), the number of bits required for its signed integer representation is equivalent to
int::bits_for(-x - 1), oruint::bits_for(-x - 1) + 1or .
- When , the unsigned representation of can be augmented with a sign bit, so the number of bits required for its signed integer representation is
Using Const Generics as Values
Type-level operations can also be included in expressions directly using const type { ... }. This provides a shortcut around certain language impositions, for example allowing arbitrary-precision arithmetic and division to be performed freely and unconstrained from concerns like bit widths.
const type { 300 / 7 /* spooky! but it's not actually a divider */ }