Deno
Using unffi on Deno — permissions, pointer helpers, structs by value, async calls.
unffi on Deno wraps Deno.dlopen. Scalar calls use V8's fast API path and compile to near-native after warmup.
Permissions
Deno gates FFI access. Pass --allow-ffi (or a path to scope it):
deno run --allow-ffi main.ts
deno run --allow-ffi=./libmath.dylib main.tsWithout it, dlopen throws a descriptive error with a link to the Deno FFI docs.
Quick start
import { , } from 'unffi'
const = await ('./libmath.dylib', {
: { : [., .], : . },
: { : [.], : . },
})
const sum = ..(3, 4)const root = ..(2.0)Pointer-sized integers
Use t.deno.usize / t.deno.isize for size_t / ssize_t. They always return bigint:
import { dlopen, t } from 'unffi'
const lib = await dlopen('./alloc.dylib', {
malloc: { args: [t.deno.usize], returns: t.pointer },
})
const ptr = lib.symbols.malloc(256n) // bigint | nullZero-copy buffers
Pass a TypedArray where t.buffer is expected:
import { , } from 'unffi'
const = await ('./fill.dylib', {
: { : [., .], : . },
})
const = new (1024)
..(, .)
// buf is populated in-place — no copyFor an offset pointer or long-lived pointer:
const p = t.deno.ptrOf(buf) // Deno.PointerValue from TypedArray
t.deno.readCString(p) // decode NUL-terminated string
t.deno.readArrayBuffer(p, byteLen) // read raw bytesStructs by value
t.deno.struct(fields) takes an array of CType tokens and creates a by-value struct type. Pass/receive as a Uint8Array matching the struct's byte layout:
import { dlopen, t } from 'unffi'
// struct Point { float x; float y; } → 8 bytes
const Point = t.deno.struct([t.f32, t.f32])
const lib = await dlopen('./geom.dylib', {
length: { args: [Point], returns: t.f32 },
})
const point = new Uint8Array(8)
new DataView(point.buffer).setFloat32(0, 3.0, true)
new DataView(point.buffer).setFloat32(4, 4.0, true)
lib.symbols.length(point) // → 5.0Async / nonblocking calls
import { , } from 'unffi'
const = await ('./codec.dylib', {
: { : [., .], : ., : true },
})
const outLen = await ..(new (1024), 1024)Callbacks
import { , } from 'unffi'
const = await ('./sorter.dylib', {
: {
: [., ., .([., .], .)],
: .,
},
})
..(new (10), 10, (a, ) => { return -
})Deno callbacks must be invoked from the main thread. Cross-thread invocations require a native queue.