Memory Layout
By default, the Zolo compiler may reorder struct fields
(@repr(zolo)) for internal optimisation. When field order and alignment are
contracts — FFI with C/Rust, GPU uniform buffers, binary protocols —
you declare the layout explicitly with attributes:
@repr(C), @repr(packed), @repr(transparent), @align(N), and @size(N).
13-repr-align-size.zolo
// Feature: `@repr` / `@align` / `@size` — struct layout control
// Syntax:
// @repr(C | packed | transparent | zolo) on the struct
// @align(N) on a field (N must be a power of two)
// @size(N) on a field (forces minimum byte size)
// When to use: FFI with C/Rust plugins, GPU uniform buffers, binary
// protocols, layout-sensitive newtypes. Default `@repr(zolo)` lets
// the compiler reorder fields, which is unsuitable for binary stability.
//
// See `specs/repr-align-size.md` for the full specification.
// 1. @repr(C) — fields kept in declaration order, C-compatible layout.
@repr(C)
struct PacketHeader {
version: int,
flags: int,
length: int,
seq: int,
}
let hdr = PacketHeader { version: 1, flags: 0, length: 256, seq: 42 }
print("hdr.seq = {hdr.seq}")
// 2. @repr(packed) — no padding between fields.
// Useful for wire protocols where every byte matters.
@repr(packed)
struct WireFrame {
magic: int,
payload: int,
}
let w = WireFrame { magic: 0xCAFE, payload: 100 }
print("w.magic = {w.magic}")
// 3. @repr(transparent) — single-field newtype-like with identical
// binary layout to its inner field.
@repr(transparent)
struct Handle {
raw: int,
}
let h = Handle { raw: 42 }
print("h.raw = {h.raw}")
// 4. @align(N) on a field — force alignment under @repr(C).
// Useful for GPU uniform buffers where vec3 must be 16-byte aligned.
@repr(C)
struct CameraUniform {
@align(16) view_proj: float,
@align(16) view_pos: float,
@align(16) time: float,
}
let cam = CameraUniform { view_proj: 1.0, view_pos: 0.0, time: 0.5 }
print("cam.time = {cam.time}")
// 5. @size(N) on a field — pad to a minimum byte size.
@repr(C)
struct PaddedHeader {
@size(64) header: int,
payload: int,
}
let p = PaddedHeader { header: 1, payload: 2 }
print("p.payload = {p.payload}")
// 6. Errors caught at lint/check time (uncomment to see):
//
// @repr(unknown_policy)
// struct X { x: int }
// warning[unknown-repr]: unknown @repr policy `unknown_policy`
//
// @repr(transparent)
// struct Two { a: int, b: int }
// error[transparent-multi-field]: @repr(transparent) requires exactly one field
//
// @repr(C)
// struct Bad {
// @align(3) x: int // not a power of two
// @align(8192) y: int // exceeds 4096
// }
// error[align-not-power-of-two]
// error[align-too-large]
//
// struct DefaultRepr {
// @align(8) x: int // @align without @repr — meaningless
// }
// error[layout-in-default-repr]: `@align` requires an explicit
// `@repr(C|packed|transparent)` on the struct
Quick reference:
@repr(C)— fields in declaration order, compatible with C.@repr(packed)— no padding between fields (network protocol, binary file).@repr(transparent)— requires exactly one field; layout identical to the inner type.@align(N)— on a field, forces alignment toNbytes (power of two, max 4096).@size(N)— on a field, guarantees a minimum size ofNbytes.
@align and @size require the struct to have an explicit @repr (not zolo).
The compiler emits an error at check time if the combination is invalid.
See also