Skip to main content

Minimalist high-speed Python-to-Zig FFI bridge via comptime trampolines.

Project description

Nano-FFI

Minimalist Python-to-Zig FFI bridge via comptime trampolines.

Philosophy: Zig Performance. Python Brain. Comptime Safety.


What it is

Nano-FFI lets Python call Zig functions with near-zero overhead. Instead of runtime type inspection (like ctypes/cffi), it uses Zig's comptime engine to generate type-safe wrapper functions at compile time — no branches, no dynamic dispatch, no surprises.

import nano_ffi

result = nano_ffi.call("add", 3, 4)      # → 7
result = nano_ffi.call("mul", 2.5, 4.0)  # → 10.0

Benchmark

Platform Library Avg call overhead vs Nano-FFI
Windows x64 ctypes ~417 ns 3.82x slower
Windows x64 Nano-FFI 109.4 ns baseline
macOS ARM64 ctypes ~152 ns 3.89x slower
macOS ARM64 Nano-FFI 39.2 ns baseline

ReleaseFast build, 100k iterations. Run python tests/test_python.py to reproduce.


Requirements

  • Python >= 3.10
  • Zig 0.15.2
  • A C compiler (for linking against libpython)

Installation

From PyPI (pre-built wheels)

pip install nano-ffi

No Zig required — wheels are pre-compiled for Windows and macOS.

From source

git clone https://github.com/fcarvajalbrown/Nano-FII.git
cd Nano-FII

Windows:

zig build -Doptimize=ReleaseFast `
  -Dpython-include="<path\to\python\include>" `
  -Dpython-lib="<path\to\python\libs>" `
  -Dpython-libname=python314

macOS / Linux:

zig build -Doptimize=ReleaseFast \
  -Dpython-include="$(python3 -c "import sysconfig; print(sysconfig.get_path('include'))")"

The compiled library lands in zig-out/lib/.


Usage

Calling a registered function

import nano_ffi

# Integer addition (built-in example)
result = nano_ffi.call("add", 3, 4)        # → 7

# Float multiplication (built-in example)
result = nano_ffi.call("mul", 2.5, 4.0)   # → 10.0

# Check library version
print(nano_ffi.version())                  # → "0.2.0"

Registering your own Zig function

In your Zig code, use comptime_bridge.makeTrampoline to generate a wrapper and register it:

const bridge = @import("nano_ffi").bridge;
const reg    = @import("nano_ffi").registry;

fn add(a: i64, b: i64) i64 { return a + b; }

const AddTrampoline = bridge.makeTrampoline(add, .{
    .args = &.{
        .{ .name = "a", .typ = .i64 },
        .{ .name = "b", .typ = .i64 },
    },
    .ret = .i64,
});

// Register at init time:
try my_registry.register("add", AddTrampoline.asPtr(), AddTrampoline.sig);

Architecture

src/
├── root.zig            # Entry point, exports PyInit_nano_ffi
├── registry.zig        # StringHashMap storing FnPtr + Signature
├── comptime_bridge.zig # Comptime trampoline generator (core)
├── allocator.zig       # Python-Zig memory boundary management
└── python_ext.zig      # CPython C extension (only file touching Python.h)

Key constraint: only python_ext.zig is allowed to import <Python.h>. Everything else is pure Zig with C-ABI compatible types.

How the speed works: makeTrampoline uses Zig's inline for over the signature at compile time — the compiler sees explicit typed assignments, not a loop. No branches, no runtime type checks in the hot path.


Running tests

# Zig unit tests
zig build test

# Python end-to-end + benchmark
PYTHONPATH=. python tests/test_python.py

Current limitations

  • Supported argument types: i64, f64, bool — slices and strings planned for v0.3.0
  • Max 8 arguments per function call
  • Linux wheels not yet available (coming in v0.3.0)

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

nano_ffi-0.2.0-cp314-cp314-win_amd64.whl (94.7 kB view details)

Uploaded CPython 3.14Windows x86-64

nano_ffi-0.2.0-cp313-cp313-macosx_26_0_universal2.whl (9.8 kB view details)

Uploaded CPython 3.13macOS 26.0+ universal2 (ARM64, x86-64)

File details

Details for the file nano_ffi-0.2.0-cp314-cp314-win_amd64.whl.

File metadata

  • Download URL: nano_ffi-0.2.0-cp314-cp314-win_amd64.whl
  • Upload date:
  • Size: 94.7 kB
  • Tags: CPython 3.14, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for nano_ffi-0.2.0-cp314-cp314-win_amd64.whl
Algorithm Hash digest
SHA256 562a8e034e69e277cbf55114b691c93656a17422cdf5b0660a6b51b444485b74
MD5 dc22c24fbeed7309214164f251290073
BLAKE2b-256 bd755b70fd4d2e3eaf0ace5c2d1b7e8cfd57a8836ede25a40d57b2bcc427c993

See more details on using hashes here.

File details

Details for the file nano_ffi-0.2.0-cp313-cp313-macosx_26_0_universal2.whl.

File metadata

File hashes

Hashes for nano_ffi-0.2.0-cp313-cp313-macosx_26_0_universal2.whl
Algorithm Hash digest
SHA256 8b5b04b58e0699ada4433b77d2c80a0be158cb9991d99df5c689b0c0b67db39e
MD5 ef338fe58e965c051dd9ae428d3a6c3a
BLAKE2b-256 38477b80dac8b2fea8c22902f2be201abeb33d5aaf518703eb80c717242b5c92

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page