npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

zbind

v0.0.11

Published

Zig-TypeScript binding generator

Downloads

38

Readme

zbind

zbind

zbind generates TypeScript bindings for calling Zig code compiled to native code or Wasm, in Node.js or Bun or browsers.

Supported Zig versions are 0.11.0 - 0.13.0 (and at least some 0.14.0 dev versions as well) Zig 0.13.0 seems to have an issue linking with C++ code when targeting Wasm, that has been fixed in later development versions.

Example Zig code lib/main.zig:

const std = @import("std");
const zbind = @import("zbind");

pub fn hello(name: []const u8) void {
    std.debug.print("Hello, {s}!\n", .{ name });
}

comptime {
    zbind.init(@This());
}

It exports a Zig function hello, callable from TypeScript. A wrapper function will be exported that receives a string pointer and length in memory shared between Zig and the JavaScript engine.

Example TypeScript code src/index.ts to call it:

import { hello } from './greet.js';

hello('World');

The automatically generated TypeScript function will encode the string as UTF-8 in a buffer directly accessible by both languages.

The Zig code requires a build.zig script to compile it:

const std = @import("std");
const zbind = @import("node_modules/zbind/zbind.zig");

pub fn build(builder: *std.Build) !void {
    const lib = try zbind.build(.{ //
        .builder = builder,
        .main = "lib/main.zig",
        .out = "dist/addon"
    });

    lib.linkLibC();
}

The zbind.build call returns a *std.Build.Step.Compile object for linking with other libraries if needed.

Run these shell commands to compile the code and generate TypeScript bindings:

npm install --save zbind
npm install --save-dev node-api-headers

# For native
zig build -Doptimize=ReleaseFast
npx zbind dist/addon.node src/greet.ts

# For Wasm
zig build -Doptimize=ReleaseSmall -Dtarget=wasm32-wasi
npx zbind dist/addon.wasm src/greet.ts

The commands compile the Zig code to a native or Wasm binary and then call a TypeScript-based tool to inspect it and generate wrapper functions in src/greet.ts with matching types and necessary marshalling.

To install Zig from NPM you can do:

npm install --save-dev @oven/zig

Supported data types

| Zig | TypeScript | Notes | |--------------|---------------------|-------| | bool | boolean | | | u8 - u32 | number | Conversion from number rounds down, throws if outside range. | | i8 - i32 | number | Conversion from number rounds towards 0, throws if outside range. | | f32, f64 | number | | | u64, i64 | bigint | | | []u8 | Slice, string | Slice of u8 has a toString method for automatic coercion.Strings are passed through a stack. | | struct | OpaqueStruct | TypeScript takes ownership of opaque structs passed by valuesuch as std.mem.Allocator | | ?any above | any above \| null | |

Support is planned for more slice types, pointers, error unions, callbacks and accessing struct fields and methods.

Architecture

Generated TypeScript bindings are identical for Wasm and Node-API. Values are marshalled using a separate one-megabyte stack mostly accessed through a []f64 / Float64Array. Since f64 can represent 53-bit integers, it fits pointers to memory as well. null is passed as a special NaN bit pattern.

When compiled, zbind.zig analyzes argument and return types of Zig functions at comptime, stores the metadata in a compact binary representation and defines special endpoints for querying functions and types. It generates Zig wrapper functions for Zig methods to handle type marshalling and reports a list of pointers to those functions when initialized.

The zbind command line tool loads the compiled binary and queries its metadata endpoints to generate a TypeScript wrapper for each Zig function which calls it automatically converting types. The tool writes out TypeScript source code defining and exporting the wrapper functions.

After importing the generated file in your own TypeScript code and making the first call to Zig code through it, the bindings load the compiled binary.