On this page
article
Chapter 14: C FFI (Foreign Function Interface)
Calling C Functions
const c = #cImport({
#cInclude("stdio.h");
#cInclude("string.h");
});
fn countOccurrences(haystack: []const u8, needle: u8): usize {
var count: usize = 0;
for b in haystack {
if b.* = needle { count += 1; }
}
return count;
}
fn main(): void {
-- calling C functions requires unsafe
unsafe {
_ = c.printf("Hello from C!\n");
}
}
Exporting Violet Functions to C
-- Violet function callable from C
export fn violetAdd(a: i32, b: i32): i32 {
return a + b;
}
-- with custom C name
export("violet_compute") fn compute(data: [*c]const u8, len: usize): u64 {
unsafe {
return hashBytes(data[0..len]);
}
}
Generate a C header: violet build --emit-header mylib.h
C Callbacks With Context
The user_data: *anyopaque pattern:
const ffi = import("std/ffi");
type CallbackCtx = struct {
alloc: Allocator,
results: *List[i32],
};
extern("C") fn myCallback(value: i32, user_data: *anyopaque): void {
unsafe {
var ctx = ffi.restore(*CallbackCtx, user_data);
ctx.results.push(ctx.alloc, value) catch {};
}
}
fn collectResults(
alloc: Allocator,
lib_func: fn(i32, fn(i32, *anyopaque): void, *anyopaque): void,
): !List[i32] {
var results = List[i32]::new();
errdefer results.deinit(alloc);
var ctx = CallbackCtx { .alloc = alloc, .results = &results };
unsafe {
lib_func(42, myCallback, &ctx as *anyopaque);
}
return results;
}
C-Compatible Types
type WireHeader = extern packed struct {
magic: u16,
version: u8,
flags: u8,
length: u32,
};
#assert(#sizeOf(WireHeader) = 8);
type Status = extern enum(u32) {
Ok = 0,
Error = 1,
Pending = 2,
};