Memory
Memory
Section titled “Memory”Janus is built with Zig, but ordinary .jan source does not use Zig expression
builtins. Raw memory exists as named library operations with profile boundaries.
The rule is simple:
Zig may build Janus. Zig may not speak Janus.
Use std.mem only when the code is actually doing raw address or byte work.
Ownership and allocation belong in std.alloc; value conversion belongs in
std.conv.
Canonical Raw Verbs
Section titled “Canonical Raw Verbs”func reinterpret[T](p: *auto) -> *T {.profile: sovereign.}func realign[T](p: *auto) -> !*Tfunc pointer_from[T](addr: usize) -> *T {.profile: sovereign.}func address_of[T](p: *auto) -> usizefunc copy_bytes(dst: *u8, src: *const u8, count: usize) -> voidThe canonical spelling is std.mem.reinterpret[T](p),
std.mem.realign[T](p)?, std.mem.pointer_from[T](addr),
std.mem.address_of[T](p), and std.mem.copy_bytes(...). If an implementation
phase reaches the functions through a temporary alias or stub, that does not
change the documented Janus surface.
reinterpret and pointer_from are dangerous by construction. They require
:sovereign because the caller is asserting facts the compiler cannot prove.
The current source syntax marks that boundary with an inline function profile
pragma before the function body:
func device_register(addr: usize) -> *u32 {.profile: sovereign.} do return std.mem.pointer_from[u32](addr)endrealign is checked. It returns MemError.MisalignedPointer when the address
does not satisfy the target type alignment.
address_of is observational: it exposes the address of an existing pointer as
an integer. That still belongs in raw memory code, not ordinary application
logic.
copy_bytes is raw byte movement. The caller owns the overlap and bounds
contract.
Allocation lives in std.alloc
Section titled “Allocation lives in std.alloc”std.mem no longer re-exports allocator modules. Import ownership APIs from
std.alloc:
use std.alloc.arenause std.alloc.page_allocatorUse std.alloc.arena for caller-owned bump allocation and
std.alloc.page_allocator for page-backed system allocation. Older
three-method allocator consumers use std.alloc.legacy_allocator until they
migrate to the canonical layout-aware std.alloc.trait.Allocator.
Run the doctrine lint before changing standard library boundaries:
janus lint --stdlib-boundariesThe lint rejects allocator APIs in std.mem, raw pointer reinterpretation in
std.alloc, and value conversion helpers in std.mem.
Zig Builtins Are Not Janus Source
Section titled “Zig Builtins Are Not Janus Source”Do not write these in user .jan files:
| Zig expression builtin | Janus surface |
|---|---|
@ptrCast | std.mem.reinterpret[T](p) |
@alignCast | std.mem.realign[T](p)? |
@ptrFromInt | std.mem.pointer_from[T](addr) |
@intFromPtr | std.mem.address_of[T](p) |
@memcpy | std.mem.copy_bytes(dst, src, count) |
@import | use module.path or use zig "bridge.zig" |
If a foreign library or platform boundary needs Zig syntax, isolate it in an
explicit graft or generated bridge. Inline graft zig do ... end bodies are
embedded Zig escape hatches; their Zig syntax is not Janus syntax.
Use The Right Border
Section titled “Use The Right Border”use std.conv as conv
func device_register(addr: usize) -> *u32 {.profile: sovereign.} do return std.mem.pointer_from[u32](addr)end
func buffer_addr(buf: *u8) -> usize do return std.mem.address_of[u8](buf)end
func checked_byte(n: i64) -> !u8 do return conv.to[u8](n)?endpointer_from is for MMIO, boot code, and audited low-level bridges. It is not
a value conversion. Use std.conv for value conversions.
Callable Addresses Are Not Integers
Section titled “Callable Addresses Are Not Integers”Executable authority is not raw data in public Janus APIs. Do not expose
func_addr: u64, handler_addr: usize, callback_addr: u64, or any equivalent
integer-shaped function entry in user-facing code.
Public APIs should accept typed callables, generated actor or grain starters,
opaque handles, executor/task values, or capability-bearing wrapper types. The
compiler and runtime may lower a typed callable to an internal RuntimeEntryId,
but that integer representation is bridge plumbing, not a Janus surface.
Non-Canonical Names
Section titled “Non-Canonical Names”The canonical names are snake_case:
pointer_from, notpointerFromaddress_of, notaddressOfcopy_bytes, notcopyBytesfill_bytes, notfillBytesmove_bytes, notmoveBytes
CamelCase raw-memory names are Zig heritage and should not appear in new documentation, lessons, or examples.