hxn

The Haxe classes of libraries built with hxn: futures, streams, signals, reactive values, atomics, and the macro that binds a packaged library.
https://github.com/hx-n/hxn

To install, run:

haxelib install hxn 0.3.1 

See using Haxelib in Haxelib documentation for more information.

README.md

hxn

hxn

Use the same Rust library from Haxe on HashLink, Ash and hxcpp, natively and on wasm. Annotate the Rust types and methods to expose; hxn generates one set of Haxe classes for every runtime and a native adapter for each target.

See CLI usage, packaging, design and conventions.

Quick setup

You need Rust, Haxe, and HashLink or hxcpp. For hxcpp, use its git version: hxcpp 4.3.2 can crash on Windows when a program exits right after a collection (HaxeFoundation/hxcpp#1470), which is fixed in git.

haxelib git hxcpp https://github.com/HaxeFoundation/hxcpp
cd "$(haxelib libpath hxcpp)/tools/hxcpp" && haxe compile.hxml

Install the hxn command from the latest release:

curl -fsSL https://raw.githubusercontent.com/hx-n/hxn/main/install.sh | bash

The script selects the macOS, Linux or Windows binary for x86-64 or ARM64, verifies its SHA-256 checksum, and installs it in ~/.local/bin. Add that directory to your PATH if it is not already there. On Windows, run it in Git Bash, or download the zip from the releases and put hxn.exe on your PATH. Set HXN_VERSION to select a release tag or HXN_INSTALL_DIR to choose another directory, for example:

curl -fsSL https://raw.githubusercontent.com/hx-n/hxn/main/install.sh | HXN_VERSION=v0.3.1 HXN_INSTALL_DIR="$HOME/.local/bin" bash

To build the command from source, use Cargo:

cargo install --git https://github.com/hx-n/hxn --tag v0.3.1 hxn-cli

Create a library with hxn new:

hxn new greeter
cd greeter

Write the library in src/lib.rs. #[hxn::interface] exposes a Rust struct to Haxe as a class, and #[hxn::methods] exposes its public functions as that class's public Haxe methods. A function outside an impl is marked #[hxn::function] and becomes a static method.

/// Greets people, and counts them.
#[hxn::interface]
pub struct Greeter {
    greeting: String,
    greeted: i32,
}

#[hxn::methods]
impl Greeter {
    pub fn new(greeting: &str) -> Self {
        Self {
            greeting: greeting.to_owned(),
            greeted: 0,
        }
    }

    /// A greeting for `name`. Fails for an empty name.
    pub fn greet(&mut self, name: &str) -> Result<String, &'static str> {
        if name.is_empty() {
            return Err("nobody to greet");
        }
        self.greeted += 1;
        Ok(format!("{}, {name}!", self.greeting))
    }

    /// How many have been greeted.
    pub fn greeted(&self) -> i32 {
        self.greeted
    }
}

Use the generated class from haxe/Main.hx:

class Main {
	static function main() {
		var greeter = new Greeter("Hello");
		Sys.println(greeter.greet("Haxe"));
		Sys.println(greeter.greet("Rust"));
		Sys.println('${greeter.greeted()} greeted');
		try {
			greeter.greet("");
		} catch (error:haxe.Exception) {
			Sys.println('refused: ${error.message}');
		}
		greeter.close();
	}
}

Run it on either target:

hxn run hl
hxn run cpp
Hello, Haxe!
Hello, Rust!
2 greeted
refused: nobody to greet

hxn build hl or hxn build cpp generates the Haxe classes and builds the native library without running anything, and prints the haxe arguments for compiling your own program against them.

Add --wasm to build and run the same program as wasm: hxn run hl --wasm through Ash, and hxn run cpp --wasm through hxcpp and Emscripten. The first needs a nightly Rust toolchain; the second needs Rust's Emscripten target (rustup target add wasm32-unknown-emscripten).

hxn run cppia runs the same program as a CPPIA script: it builds the hxcpp binding into a host executable, which runs the script. The script calls the library through the host, so only the host needs rebuilding when the library changes.

hxn check runs the program on HashLink and hxcpp, or on the runtimes you name, and passes only if their output is identical. hxn doctor lists the targets your machine can build for and what is missing for the others.

hxn package builds the library for both runtimes and collects the Haxe classes, headers and native libraries into a haxelib directory. Haxe projects can compile against this package without the library's Rust source:

hxn package --release --out ../greeter-haxelib
haxelib git hxn https://github.com/hx-n/hxn
haxelib dev greeter ../greeter-haxelib
haxe -lib greeter -cp src -main Main -hl main.hl

The package depends on the hxn haxelib, this repository, for hxn's own classes, so every hxn library a program uses shares them. -lib greeter runs the macro hxn.Bind.lib("greeter"), which adds the package's classes, passes hxcpp the header and library paths, and for HashLink copies greeter.hdll next to main.hl. The package contains native libraries for the machine it was built on. To add more, run hxn package with the same output directory on another machine, or with --wasm. The hxcpp library can also be cross-compiled, including for iOS and Android:

rustup target add aarch64-apple-ios aarch64-linux-android
hxn package cpp --target aarch64-apple-ios --out ../greeter-haxelib
hxn package cpp --target aarch64-linux-android --out ../greeter-haxelib

Compiling with hxcpp's defines for that platform (-D iphoneos, or -D android -D HXCPP_ARM64) selects the matching library.

A HashLink program can run on iOS and Android as well, built by Ash. A program on those platforms cannot load an .hdll, so --target packages the HashLink library as a static archive, and Ash links it into the executable:

hxn package hl --target aarch64-linux-android --out ../greeter-haxelib
haxe -lib greeter -D hxn_triple=aarch64-linux-android -cp src -main Main -hl main.hl
ash --build main --target aarch64-linux-android --native-lib libgreeter.a main.hl

-D hxn_triple selects the Android library from the package, and hxn.Bind copies it, libgreeter.a, next to main.hl. For the iOS simulator the triple is aarch64-apple-ios-sim. Ash also links its own runtime for the platform, which it finds beside the ash command or takes from --runtime.

haxelib submit requires a few more fields. Set repository and license in Cargo.toml, and the haxelib contributors and a release note under [package.metadata.hxn]:

[package.metadata.hxn]
contributors = ["your-haxelib-name"]
releasenote = "First release."

Binding a C library

hxn import uses clang to read a C header and generate a Rust library crate. The hxn generator then creates Haxe bindings from that crate.

hxn import vendor/tally.h --source vendor/tally.c
cd tally

The crate's API is in tally.webidl, generated from the header. Review it and add what a header cannot express: [HxnStatus] on a function whose int return value is a status code, [HxnFree=function] where returned text or an object must be freed. Each hxn build regenerates src/bindings.rs from it. A C callback the library calls during the call is passed a Haxe function; one it keeps to call later, such as the one sqlite3_update_hook registers, is returned as a stream of its calls. Use --link <library> instead of --source to link a library that is already built. See Importing C libraries for supported declarations and import restrictions.

Examples

examples/ contains greeter and six other libraries. Each example has a Rust crate and a Haxe program that you can run from a checkout:

ExampleFeatures
greeterA struct exposed as a Haxe class, string parameters and return values, and an error thrown as an exception.
pictureA Haxe callback called by the library, a byte array return value, and an object passed as a parameter to another object's method.
primesWork done on another thread: a future that can be awaited or given a completion callback, and a stream.
downloadsAn async fn, a value shared between the library and Haxe, and an atomic counter that Haxe reads without a native call.
thermostatA value the library updates, observed from Haxe as a signal.
pantryRecords and enums passed by value, an optional field, a list of records returned, and a typed error.
documentWraps an existing crate (serde_json): JSON values as a recursive enum, objects as a map, and parse errors as a typed exception with line and column.
cargo install --path crates/hxn-cli
cd examples/primes
hxn run hl

To work on hxn itself, see AGENTS.md.

License

Licensed under Apache-2.0. See LICENSE.

Contributors
darmie
Version
0.3.1
Published
1 day ago
License
Apache

All libraries are free

Every month, more than a thousand developers use Haxelib to find, share, and reuse code — and assemble it in powerful new ways. Enjoy Haxe; It is great!

Explore Haxe

Haxe Manual

Haxe Code Cookbook

Haxe API documentation

You can try Haxe in the browser! try.haxe.org

Join us on GitHub!

Haxe is being developed on GitHub. Feel free to contribute or report issues to our projects.

Haxe on GitHub

⌂