hxn

TUTORIAL / 03

Pass data and handle errors

Use records, enums, sets and tuples from Haxe, then catch a typed Rust error.

1. Pass a record

The pantry example marks plain values with #[hxn::data]. Haxe gets a record class and an enum; the Rust library stays independent of the runtime.

lib.rs · excerpt
#[hxn::data]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Unit {
    Each,
    Kilo,
    Litre,
}

/// An item on a shelf. Haxe gets a class with these fields.
#[hxn::data]
#[derive(Clone)]
pub struct Item {
    pub name: String,
    pub quantity: i32,
    #[hxn(default = "Item::default_unit")]
    pub unit: Unit,
    /// An optional field can be omitted in Haxe.
    pub note: Option<String>,
}
Main.hx · excerpt
var pantry = new Pantry();

// Rust fills the omitted unit with Item::default_unit; note is null.
pantry.stock({name: "eggs", quantity: 12});
pantry.stock({name: "flour", quantity: 2, unit: Unit.Kilo, note: "wholemeal"});
var rice:Item = {name: "rice", quantity: 1, unit: Unit.Kilo};
Sys.println('${pantry.stock(rice)} items stocked');

Omitted unit uses Item::default_unit(); omitted note becomes null. Rust stores a copy. Changing rice.quantity in Haxe after stocking leaves the pantry unchanged.

2. Use tuples and sets

Main.hx · excerpt
var quantities = pantry.quantities();
Sys.println('shelves: ${[for (pair in quantities) '${pair[0]}=${pair[1]}'].join(", ")}');
Main.hx · excerpt
var wanted = new hxn.Set(["rice", "salt"]);
wanted.add("salt");
wanted.add("oil");
Sys.println('to buy: ${pantry.missing(wanted).toArray().join(" and ")}');

Rust’s Vec<(String, i32)> arrives as an array of hxn.Tuple values. Indexed access returns Dynamic; pair.at(0) preserves the position’s static type. hxn.Set supports membership and insertion. This example returns a BTreeSet, so the result is sorted by Rust.

3. Catch a typed error

lib.rs · excerpt
#[hxn::data]
#[derive(Clone, Debug)]
pub enum PantryError {
    /// No item has that name.
    Unknown(String),
    /// Fewer are in stock than requested.
    Short { name: String, left: i32 },
}
Main.hx · excerpt
for (wanted in ["eggs", "salt"]) {
	try {
		pantry.take(wanted, 50);
	} catch (refused:PantryException) {
		switch (refused.error) {
			case Short(name, left):
				Sys.println('only $left of $name');
			case Unknown(name):
				Sys.println('no $name at all');
		}
		Sys.println('  ${refused.message}');
	}
}

take returns Result<Item, PantryError>. Haxe catches PantryException: its error field is the enum, and its message comes from Rust’s Display implementation. Call pantry.close() when finished.

Run the example

From the repository root, run the complete example:

Run pantry
cd examples/pantry
hxn run hl

Full Rust and Haxe source ↗ · Use hxn run cpp for hxcpp.