Language Bindings

mino exposes a plain C ABI with simple types: pointers, integers, doubles, and null-terminated strings. Any language with C FFI support can embed it directly, with no wrapper library or code generation step.

The examples below all run the same scenario: build a vector of sensor events, evaluate a mino script that filters, groups, and summarizes the data, and print the result.

C

The baseline reference. Direct API calls, no translation layer.

C++

Same API calls with C++17 patterns: auto, range-for, lambdas. The extern "C" guards in mino.h mean no wrapper is needed.

Java (JNI)

A thin JNI bridge maps native methods to the mino C API. State and environment handles are passed as Java longs.

Other languages

Since mino is a plain C library, most systems languages can call it directly through their standard FFI mechanisms. Below are short sketches showing how the call looks in each language.

Zig

@cImport reads mino.h directly. Zero overhead, full type safety.

const mino = @cImport({
    @cInclude("mino.h");
});

pub fn main() !void {
    const S = mino.mino_state_new();
    defer mino.mino_state_free(S);

    const env = mino.mino_env_new_default(S);
    defer mino.mino_env_free(S, env);

    const result = mino.mino_eval_string(S,
        "(+ 1 2)", env);
    if (result) |r| mino.mino_println(S, r);
}

Rust

extern "C" block with unsafe wrappers. A safe Rust API could be layered on top.

extern "C" {
    fn mino_state_new() -> *mut MinoState;
    fn mino_state_free(s: *mut MinoState);
    fn mino_env_new_default(s: *mut MinoState) -> *mut MinoEnv;
    fn mino_env_free(s: *mut MinoState, e: *mut MinoEnv);
    fn mino_eval_string(
        s: *mut MinoState, src: *const c_char,
        e: *mut MinoEnv,
    ) -> *mut MinoVal;
    fn mino_println(s: *mut MinoState, v: *const MinoVal);
}

fn main() {
    unsafe {
        let s = mino_state_new();
        let e = mino_env_new_default(s);
        let src = CString::new("(+ 1 2)").unwrap();
        let r = mino_eval_string(s, src.as_ptr(), e);
        if !r.is_null() { mino_println(s, r); }
        mino_env_free(s, e);
        mino_state_free(s);
    }
}

C# / .NET

P/Invoke with [DllImport] attributes. Works on .NET Framework, .NET Core, and Mono.

using System.Runtime.InteropServices;

class Mino {
    [DllImport("mino")] static extern IntPtr mino_state_new();
    [DllImport("mino")] static extern void mino_state_free(IntPtr s);
    [DllImport("mino")] static extern IntPtr mino_env_new_default(IntPtr s);
    [DllImport("mino")] static extern void mino_env_free(
        IntPtr s, IntPtr e);
    [DllImport("mino")] static extern IntPtr mino_eval_string(
        IntPtr s, string src, IntPtr e);
    [DllImport("mino")] static extern void mino_println(
        IntPtr s, IntPtr v);

    static void Main() {
        var s = mino_state_new();
        var e = mino_env_new_default(s);
        var r = mino_eval_string(s, "(+ 1 2)", e);
        if (r != IntPtr.Zero) mino_println(s, r);
        mino_env_free(s, e);
        mino_state_free(s);
    }
}

Go

cgo with #include "mino.h" in a magic comment. The Go runtime handles the C-to-Go boundary.

// #cgo LDFLAGS: -lmino -lm
// #include "mino.h"
import "C"

func main() {
    s := C.mino_state_new()
    defer C.mino_state_free(s)

    e := C.mino_env_new_default(s)
    defer C.mino_env_free(s, e)

    src := C.CString("(+ 1 2)")
    defer C.free(unsafe.Pointer(src))

    r := C.mino_eval_string(s, src, e)
    if r != nil { C.mino_println(s, r) }
}

Swift

A C bridging header exposes the mino API to Swift. Optional return types map naturally to nullable pointers.

// Bridging header: #include "mino.h"

let s = mino_state_new()!
defer { mino_state_free(s) }

let e = mino_env_new_default(s)!
defer { mino_env_free(s, e) }

if let r = mino_eval_string(s, "(+ 1 2)", e) {
    mino_println(s, r)
}