# Types
primate has a small, fixed set of built-in types. Users compose them
into structures with type constructors (`array`, `tuple`, etc.) and
name them with `type` aliases.
## Primitives
### Numbers
| `i32` `i64` | Signed integers. |
| `u32` `u64` | Unsigned integers. |
| `i8` `i16` | **Only as enum backing types in v1.** Widened to `i32` in IR. |
| `u8` `u16` | **Only as enum backing types in v1.** Widened to `u32` in IR. |
| `f32` `f64` | Floats. |
The "only as enum backing" restriction reflects how rare 8/16-bit
constants are in cross-language code; widening to `i32`/`u32` keeps
generators simple. (When fixed-size arrays of `u8` are useful — e.g.
RGB triples — they're *value types*, not constants in the bit-twiddling
sense; see [fixed-size arrays](#fixed-size-arrays).)
### Boolean
```primate
bool ENABLED = true
bool DEBUG = false
```
### `string`
UTF-8. Regular and raw forms:
```primate
string GREETING = "Hello, world!"
string LITERAL = "Has \"quotes\" and \\ backslashes."
string RAW = r"no\\escapes\here"
string RAW_QUOTE = r#"with "quotes" inside"#
```
### `duration`
A length of time. primate normalizes durations to nanoseconds
internally.
```primate
duration TIMEOUT = 30s
duration RETRY_WAIT = 500ms
duration TICK = 16ms
duration RUN_FOR = 2h
duration LEASE = 1d
duration PRECISION = 1ns
```
Suffixes: `ns`, `us` (or `µs`), `ms`, `s`, `min`, `h`, `d`. Generators
emit per target — `std::time::Duration` in Rust, milliseconds-as-`number`
or `Temporal.Duration` in TypeScript (configurable), `timedelta` in
Python.
### Byte sizes are integer literals
Byte sizes aren't a separate type — they're sugar on integer literals.
A literal like `100MiB` is just `104_857_600` of whatever integer type
you declared:
```primate
u64 MAX_UPLOAD = 100MiB
u32 BLOCK_SIZE = 4KiB
u32 PACKET_SIZE = 1500B
```
Suffixes: `B`, `KB`/`MB`/`GB`/`TB` (decimal, ×1000), and
`KiB`/`MiB`/`GiB`/`TiB` (binary, ×1024). Allowed on `i32`, `i64`,
`u32`, and `u64` literals.
primate bounds-checks the suffix-multiplied result against the
declared type. `u32 X = 5GiB` is an `out-of-range` error because
5 GiB exceeds `u32::MAX`.
### `regex`
A regex pattern stored as a string. Validated at parse time.
```primate
regex FILENAME = "(?i)^[a-z][a-z0-9_]*\\.txt$"
```
Regex values are written as ordinary strings (not `/.../` literals).
This keeps `/` free for a future division operator.
### `url`
A URL string, validated at parse time.
```primate
url HOMEPAGE = "https://example.com"
```
## Type constructors
### `array<T>` — variable-length array
```primate
array<u32> QUEUE_DEPTHS = [4, 8, 16, 32]
array<string> ALLOWED_HOSTS = ["api.example.com", "cdn.example.com"]
```
Sugar: `T[]` is equivalent to `array<T>`. The formatter prefers the
sugared form.
### `array<T, N>` — fixed-size array
```primate
type Pixel = array<u32, 3> // RGB triple
type Matrix = array<Pixel, 3> // 3×3 grid
```
Length-mismatch is a hard error: `array<u32, 3> X = [1, 2]` produces a
`length-mismatch` diagnostic.
In Rust this generates `[T; N]`; in TypeScript and Python a
homogeneous tuple of N elements. See the
[matrices cookbook](../cookbook/matrices.md) for a worked example.
### `optional<T>`
```primate
optional<duration> RETRY_AFTER = 30s
optional<duration> NEVER = none
```
Sugar: `T?`. Values are either a regular `T` literal or the keyword
`none`.
### `map<K, V>`
```primate
map<string, u32> SERVICE_PORTS = {
"http": 80,
"https": 443,
"ssh": 22,
}
```
Map keys can be strings, identifiers, or integers; the value type is
arbitrary. Trailing comma triggers multi-line formatting (see
[Values](./values.md)).
### `tuple<A, B, …>`
```primate
type RetrySchedule = tuple<u32, duration, duration>
RetrySchedule DEFAULT = [3, 100ms, 30s]
```
Heterogeneous, fixed-arity. Tuple values use square brackets — see
[Values](./values.md) for the rationale.
## User-defined types
`enum` and `type` declarations introduce types you can use anywhere a
primitive type can go. `type` is *structural*: `type Port = u32` and
`u32` are interchangeable.
Enums and aliases live in their declaring file's namespace.
Cross-namespace references are by qualified path or via [`use`](./use.md):
```primate
core::types::LogLevel DEFAULT_LEVEL = Info
```
## Multi-line type expressions
Inside `<>`, newlines are insignificant. Long type expressions can wrap:
```primate
type ServiceConfig = map<
string,
tuple<duration, u64, optional<url>, regex>,
>
```
Trailing commas are accepted on the type side but don't trigger
multi-line formatting — type expressions tend to be short enough that
the column budget alone suffices.