Perl is great for glue; Rust is great for logic.

Historically, binding Rust to Perl required complex XS modules or specific crates like perl-xs. With Affix::Build, you can treat Rust just like C. By using standard ABI hooks (extern "C"), we can compile and run Rust code dynamically without ever leaving the Perl script.

The Recipe

Let's define a simple Rust library that operates on a Struct and handles strings.

use v5.40;
use Affix qw[:all];
use Affix::Build;
$|++;

# 1. Compile Rust
# Affix::Build detects the 'rs' extension and invokes `rustc`.
my $c = Affix::Build->new( name => 'rust_demo' );

# We define a struct to share between Rust and Perl
$c->add( \<<~'RUST', lang => 'rs' );
    use std::ffi::CStr;
    use std::os::raw::c_char;

    // We must define the struct layout to match C
    #[repr(C)]
    pub struct Point {
        x: i32,
        y: i32,
    }

    // #[no_mangle] keeps the symbol name "add_points"
    // extern "C" ensures the ABI uses standard registers
    #[no_mangle]
    pub extern "C" fn add_points(a: Point, b: Point) -> Point {
        Point {
            x: a.x + b.x,
            y: a.y + b.y
        }
    }

    // Example of reading a Perl string
    // We accept a raw pointer (*const c_char)
    #[no_mangle]
    pub unsafe extern "C" fn hello_rust(name: *const c_char) {
        if !name.is_null() {
            let c_str = CStr::from_ptr(name);
            if let Ok(s) = c_str.to_str() {
                println!("Hello, {} from Rust!", s);
            }
        }
    }
RUST
my $lib = $c->link;

# 2. Define Types
typedef Point => Struct [ x => Int, y => Int ];

# 3. Bind
# We treat Rust structs exactly like C structs.
affix $lib, 'add_points', [ Point(), Point() ] => Point();
affix $lib, 'hello_rust', [String]             => Void;

# 4. Execute
my $p1 = { x => 10, y => 20 };
my $p2 = { x => 5,  y => 5 };

# Pass by value
my $p3 = add_points( $p1, $p2 );
say "Result: $p3->{x}, $p3->{y}";    # 15, 25

# Pass string
hello_rust('Perl');

How It Works

Kitchen Reminders