Skip to content

A NPM Package and CLI tool that automatically generates TypeScript FFI bindings for Rust libraries, making it easy to call Rust functions from JavaScript/TypeScript in Bun projects

License

Notifications You must be signed in to change notification settings

mmycin/rustport

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

๐Ÿš€ RustPort

RustPort is an NPM package as well as a command-line tool that automates the creation of TypeScript Foreign Function Interface (FFI) bindings for Rust libraries created by Tahcin Ul Karim (Mycin). This means you can call blazing-fast Rust functions from your JavaScript or TypeScript projects effortlessly.

Perfect for Bun-powered apps, RustPort takes care of all the annoying binding work, so you donโ€™t have to.


๐Ÿง Why RustPort?

Because manually writing FFI bindings is like writing assemblyโ€”painful and unnecessary. RustPort offers:

โœ… Zero-Hassle Rust FFI Binding Generation โ€“ Just run a command, and boom, your Rust functions are ready in TypeScript.

โœ… Flawless Integration with Bun โ€“ If youโ€™re using Bun, RustPort is your new best friend.

โœ… Effortless Type Mapping โ€“ Converts Rust types into TypeScript like magic.

โœ… Super Simple CLI โ€“ Generate and clean bindings in seconds with one command.


๐Ÿ“ฆ Installation

RustPort can be installed globally via your favorite package manager:

# Using npm
npm install -g rustport

# Using yarn
yarn global add rustport

# Using bun
bun add -g rustport

๐Ÿš€ Getting Started

Step 1: Set Up Your Project

Inside your project, create a lib/ directory where RustPort will generate its magic:

mkdir -p lib/rs

Step 2: Write Some Rust Code

Create a Rust file, say hello.rs, inside lib/rs/:

#[no_mangle]
pub extern "C" fn say_hello() {
    println!("Hello, Rustacean! ๐Ÿฆ€");
}

Yes, thatโ€™s all you need. No weird macros, no painful setup.

Step 3: Generate the Bindings

Now, let RustPort do its thing:

rustport generate lib/

This will:

โœ… Compile your Rust functions into dynamic libraries (.so / .dll / .dylib).
โœ… Generate TypeScript FFI bindings.
โœ… Create an index.ts file inside lib/.

Step 4: Use Rust Functions in TypeScript

Now, call Rust functions as if they were just another JavaScript function:

import { sayHello } from "./lib";

sayHello(); // Prints: Hello, Rustacean! ๐Ÿฆ€

Step-5. Run it!

Note that for now it only supports Bun, but weโ€™re working on supporting Deno and Node.js. For this, you'll need Bun installed on your machine. Install Bun using npm, yarn, or bun:

npm install -g bun

Now run the file.

bun run fileName.ts

Thatโ€™s it! You just called Rust from TypeScript without touching a single binding manually. ๐ŸŽ‰


๐Ÿ”ฅ CLI Commands

rustport generate <path>

Generates Rust FFI bindings and compiles Rust files to dynamic libraries.

rustport generate lib/

rustport clean

Wipes out all generated files and libraries, leaving no trace of your sins. ๐Ÿ˜ˆ

rustport clean

rustport help

Displays the help menu.

rustport help

โšก Advanced Usage

๐Ÿ—๏ธ Customizing Bindings

Want to rename functions or create wrappers? Just tweak the generated index.ts:

import { sayHello as rustSayHello } from "./lib";

export function sayHello() {
    rustSayHello();
}

๐Ÿงฎ Passing & Returning Numbers

Rust loves numbers. So do we. Let's make them talk:

Rust (math.rs):

#[no_mangle]
pub extern "C" fn add_numbers(a: i32, b: i32) -> i32 {
    a + b
}

Generate bindings:

rustport generate lib/

TypeScript:

import { addNumbers } from "./lib";

console.log("5 + 3 =", addNumbers(5, 3));

๐Ÿ“ Passing & Returning Strings

Rust can return strings too, but remember: memory management is a thing!

Rust (string_utils.rs):

use std::ffi::{CString, CStr};
use std::os::raw::c_char;

#[no_mangle]
pub extern "C" fn greet(name: *const c_char) -> *mut c_char {
    let c_str = unsafe { CStr::from_ptr(name) };
    let r_str = format!("Hello, {}!", c_str.to_str().unwrap());
    CString::new(r_str).unwrap().into_raw()
}

Generate bindings:

rustport generate lib/

TypeScript:

import { greet } from "./lib";

console.log(greet("Alice")); // Prints: Hello, Alice!

Yes, Rust just greeted Alice from TypeScript. Wild, huh? ๐Ÿ˜ฒ


๐Ÿ› ๏ธ Troubleshooting

1. RustPort fails to generate bindings

  • Make sure Rust and Cargo are installed.
  • Check if lib/rs/ contains valid Rust files.
  • Run cargo build inside lib/rs/ to debug compilation issues.

2. TypeScript FFI calls fail

  • Ensure that Rust functions are exported with #[no_mangle].
  • Verify the correct function signatures in TypeScript.

3. Dynamic libraries not loading?

  • On Windows, ensure .dll files are in the correct directory.
  • On macOS, use install_name_tool to set the correct paths.
  • On Linux, check LD_LIBRARY_PATH.

๐Ÿ—๏ธ Example Project

Hereโ€™s what a simple RustPort-powered Bun project might look like:

my-project/
โ”œโ”€โ”€ lib/
โ”‚   โ”œโ”€โ”€ rs/
โ”‚   โ”‚   โ”œโ”€โ”€ hello.rs
โ”‚   โ”‚   โ”œโ”€โ”€ math.rs
โ”‚   โ”‚   โ”œโ”€โ”€ string_utils.rs
โ”‚   โ”‚   โ”œโ”€โ”€ Cargo.toml
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ main.ts
โ”œโ”€โ”€ package.json

main.ts

import { sayHello, addNumbers, greet } from "../lib";

sayHello();
console.log(addNumbers(10, 20));
console.log(greet("Bob"));

๐Ÿ’– Contributing

If you love RustPort and want to make it even better, open an issue or send a PR on GitHub! If this tool saved you time, consider buying us a virtual coffee. โ˜•


๐Ÿ“œ License

RustPort is licensed under MIT. See the LICENSE file for details.

Now go forth and build fast, Rust-powered Bun projects! ๐Ÿš€

Note: Also check out ZigPort for a similar tool that generates TypeScript FFI bindings for Zig libraries.

About

A NPM Package and CLI tool that automatically generates TypeScript FFI bindings for Rust libraries, making it easy to call Rust functions from JavaScript/TypeScript in Bun projects

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Packages

No packages published

Languages