std/mem
Memory mapping and bump allocation primitives. Neither hands safe code an address: a mapping's bytes are lent as a slice to a closure (with, withMut, read, write), and a Bump allocation is a BumpSpan handle that goes stale at the next reset. The one way to get a mapping's address, for passing it to C, is the @unsafe MappedMemory.ptr.
This is the byte bump allocator. For a generational arena of typed values with
Handle<T>, seestd/arena, which owns the nameArena.
from "std/mem" import { MappedMemory, Bump, BumpSpan, mmapAnon, mmapFile }Example
var m = mmapAnon(4096)!
let wrote = m.write((bytes: &mut [u8]) => {
bytes[0] = 7
})
print(m.with((bytes: &[u8]): u8 => bytes[0])) // 7
var bump = Bump.new(1024)!
let span = bump.alloc(16)!
print(bump.with(span, (bytes: &[u8]): i64 => bytes.len) ?? 0) // 16
bump.reset()
print(bump.valid(span)) // falseAPI reference
Bump
pub struct BumpBump allocator with automatic cleanup. Named Bump, not Arena: std/arena owns the name Arena for its generational typed-handle arena, and Milo merges every module into one flat namespace, so a program cannot import both under one name. All allocations are 8-byte aligned. Use reset() to reclaim without freeing.
_epoch counts resets; every BumpSpan carries the epoch it was cut in, so a span kept past a reset is rejected instead of aliasing whatever was allocated over it.
Bump.alloc
fn Bump.alloc(self: &mut Bump, size: i64): Result<BumpSpan>Bump-allocate size zeroed bytes (8-byte aligned) and return the span naming them. Errs when the region is full.
Bump.new
fn Bump.new(capacity: i64): Result<Bump>Create a bump allocator over capacity bytes of heap. The whole region is freed when the Bump drops.
Bump.read
fn Bump.read(self: &Bump, s: BumpSpan, f: (&[u8]) => void): boolwith for a closure that returns nothing. False when the span is stale.
Bump.remaining
fn Bump.remaining(self: &Bump): i64Bytes still available.
Bump.reset
fn Bump.reset(self: &mut Bump): voidReclaim every allocation at once. Every span issued before this goes stale.
Bump.valid
fn Bump.valid(self: &Bump, s: BumpSpan): boolWhether s still names live bytes of THIS Bump.
Bump.with
fn Bump.with<R>(self: &Bump, s: BumpSpan, f: (&[u8]) => R): Option<R>Lend the span's bytes to f and return what it returns. None, and f is not called, when the span is from another Bump or from before a reset.
Bump.withMut
fn Bump.withMut<R>(self: &mut Bump, s: BumpSpan, f: (&mut [u8]) => R): Option<R>with with a mutable view: writes land in the span.
Bump.write
fn Bump.write(self: &mut Bump, s: BumpSpan, f: (&mut [u8]) => void): boolwithMut for a closure that returns nothing. False when the span is stale.
BumpSpan
pub struct BumpSpanA copyable token naming len bytes of one Bump, valid until that Bump's next reset. Private fields: only Bump.alloc can make one.
BumpSpan.len
fn BumpSpan.len(self: &BumpSpan): i64Length of the span in bytes.
MappedMemory
pub struct MappedMemoryMemory-mapped region. Automatically unmapped on drop. The fields are private so the only way to hold one is from mmapAnon / mmapFile, which keeps _ptr a live mapping of _len bytes for as long as the value lives.
MappedMemory.isWritable
fn MappedMemory.isWritable(self: &MappedMemory): boolWhether withMut can write this mapping (true for mmapAnon, false for mmapFile).
MappedMemory.len
fn MappedMemory.len(self: &MappedMemory): i64Length of the mapping in bytes.
MappedMemory.ptr
fn MappedMemory.ptr(self: &MappedMemory): *u8The mapping's base address, for handing to C (memchr over a mapped file). The caller must not use it after this MappedMemory drops, and must not write through it when isWritable() is false.
MappedMemory.read
fn MappedMemory.read(self: &MappedMemory, f: (&[u8]) => void): voidwith for a closure that returns nothing.
MappedMemory.with
fn MappedMemory.with<R>(self: &MappedMemory, f: (&[u8]) => R): RLend the mapped bytes to f and return what it returns. The view cannot outlive the call, so it cannot outlive the mapping.
MappedMemory.withMut
fn MappedMemory.withMut<R>(self: &mut MappedMemory, f: (&mut [u8]) => R): Option<R>with with a mutable view. None, and f is not called, when the mapping is read-only: a write there would fault rather than fail.
MappedMemory.write
fn MappedMemory.write(self: &mut MappedMemory, f: (&mut [u8]) => void): boolwithMut for a closure that returns nothing. False, and f is not called, when the mapping is read-only.
Functions
mmapAnon
pub fn mmapAnon(size: i64): Result<MappedMemory>Allocate an anonymous (non-file-backed), zero-filled, writable memory-mapped region.
mmapFile
pub fn mmapFile(f: &File, size: i64): Result<MappedMemory>Memory-map size bytes of an open file for reading. The mapping keeps the pages, not the descriptor: f may close once this returns. The mapping is read-only, so withMut on it returns None.
size may not exceed the file's length. The pages past the end of a file are not backed by anything, so a mapping that covers them used to hand with a view whose tail raised SIGBUS when read. What this cannot rule out is the file shrinking after the map (another process truncating it): that still faults, as in every language.