FFI: Calling Rust from Perl

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).