While learning Rust, the question of how to connect Rust to Perl inevitably came up. One possibility via FFi is FFI::Platypus::Lang::Rust:
use anyhow::{Context, Result};
use num_bigint::BigUint;
use std::slice;
fn frob(n: u64) -> Result<BigUint> {
Ok((1..=n)
.into_iter()
.map(|i| BigUint::from(i))
.reduce(|a, b| a * b)
.context("fuba")?)
}
#[unsafe(no_mangle)]
pub extern "C"
fn get_frob(len: *mut usize, n: u64) -> *const u8 {
let big = frob(n).unwrap();
let bytes = big.to_bytes_be();
let boxed_slice = bytes.into_boxed_slice();
let gizmo = boxed_slice.as_ptr();
let length = boxed_slice.len();
std::mem::forget(boxed_slice);
unsafe {
if !len.is_null() {
*len = length;
}
}
gizmo
}
#[unsafe(no_mangle)]
pub extern "C"
fn free_frob(gizmo: *mut u8, len: usize) {
unsafe {
let _ =
Box::from_raw(slice::from_raw_parts_mut(gizmo, len));
}
}
#[cfg(test)]
mod testomato {
use super::*;
#[test]
fn check_get_frob() {
let mut n: usize = 0;
let len = &mut n;
let gizmo = get_frob(len, 3_u64);
assert!(6 == unsafe { *gizmo });
}
#[test]
fn check_frob()->Result<()> {
let result = frob(3_u64)?;
assert!(BigUint::from(6u64) == result);
Ok(())
}
}
The fact that this code works does not necessarily mean that it is correct. However, it works quite well. Here is the corresponding part in Perl:
#/usr/bin/env perl
use strict;
use warnings;
use FFI::Platypus 2.00;
use FFI::Platypus::Buffer qw( buffer_to_scalar );
use Data::Dump;
use Math::BigInt;
use feature qw(say);
my $ffi = FFI::Platypus->new( api => 2, lang => 'Rust' );
$ffi->lib('../target/release/libacme.so');
$ffi->attach( get_frob => [ 'usize*', 'u64' ] => 'opaque' );
$ffi->attach( free_frob => [ 'opaque', 'usize' ] => 'void' );
my $n = shift || 1000;
my $length = 0;
my $gizmo = get_frob( \$length, $n );
my $bytes = buffer_to_scalar( $gizmo, $length );
# dd $bytes;
# dd $length;
my $bigint = Math::BigInt->from_bytes($bytes);
# dd $bigint;
say $bigint;
free_frob( $gizmo, $length );
__END__
I followed the friendly manuals - less or more. Thanks for any advice and hint (preferably on the Rust part).