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)
}