Skip to content

Unsafe and FFI

extern declarations, unsafe blocks, raw pointer authority.

Zmeu’s unsafe model is narrow: only std/sys capsule modules and raw extern calls have unsafe authority. Ordinary safe code should never need unsafe:.

Bodyless C ABI functions live inside an extern "C": block:

extern "C":
def abs(x: c_int) -> c_int

Raw extern declarations are module-private in this language slice; expose them through a thin safe wrapper instead of re-exporting directly.

unsafe: permits (a) unsafe-function calls, (b) raw extern calls, and (c) raw extern-call argument views inside the block:

def main() -> i32:
unsafe:
return abs(-42)

The body of an unsafe def is still checked normally: it is callers of the function that must wrap the call in unsafe:.

For pointer-shaped argument positions, use the raw keywords:

FormMeaning
raw ptr bytes*const u8 view over a byte slice
raw mut ptr buf*mut u8 view over a mutable byte slice
raw cstr "name"*const c_char view over a string literal with implicit NUL terminator
raw cstr view*const c_char view over an existing view CStr
extern "C":
def puts(buf: *const u8) -> c_int
def main() -> i32:
unsafe:
puts(raw cstr "hello from zmeu")
return 0

unsafe def name(params) -> Type: declares a function whose callers must use unsafe:. The body is still checked normally: what’s restricted is the call site.

export unsafe def sys_read(fd: c_int, buf: mut view [u8]) -> c_ssize:
# body checked under normal rules
...

This is how std.sys exposes thin wrappers over raw syscalls without forcing every caller through a manually-tagged unsafe block per call.

There is no general-purpose unsafe { ... } escape hatch over the type system. Borrow- and effect-checking are always on. The only authority unsafe: adds is the ability to call unsafe functions and pass raw views to them.