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,
};