6

Per the Rust FFI Omnibus the following should work.

This is a rust cdylib lib.rs named "foo" made with cargo build...

use std::convert::From;

// Rust FFI Omnibus: Tuples 
// http://jakegoulding.com/rust-ffi-omnibus/tuples/

// A Rust function that accepts a tuple
fn flip_things_around_rust(tup: (u32, u32)) -> (u32, u32) {
    let (a, b) = tup;
    (b + 1, a - 1)
}

// A struct that can be passed between C and Rust
#[repr(C)]
pub struct Tuple {
    x: u32,
    y: u32,
}

// Conversion functions
impl From<(u32, u32)> for Tuple {
    fn from(tup: (u32, u32)) -> Tuple {
        Tuple { x: tup.0, y: tup.1 }
    }   
}

impl From<Tuple> for (u32, u32) {
    fn from(tup: Tuple) -> (u32, u32) {
        (tup.x, tup.y)
    }   
}

// The exported C method - ORIG
//#[no_mangle]
//pub extern "C" fn flip_things_around(tup: Tuple) -> Tuple {
//    flip_things_around_rust(tup.into()).into()
//}

// The exported C method - EDIT per Christoph
#[no_mangle]
pub extern "C" fn flip_things_around(tup: Tuple) -> *const Tuple {
    &flip_things_around_rust(tup.into()).into()
}

And this is the raku script ffi-omnibus.raku that consumes the library via Nativecall

use NativeCall; 
constant $n-path = './ffi-omnibus/target/debug/foo';

## Rust FFI Omnibus: Tuples 
## http:##jakegoulding.com/rust-ffi-omnibus/tuples/

class Tuple is repr('CStruct') {
    has uint32 $.x;
    has uint32 $.y;
}
sub flip_things_around(Tuple) returns Tuple is native($n-path) { * } 

my \initial = Tuple.new( x => 10, y => 20 );
my \result  = flip_things_around(initial);
dd result;
say result.x, result.y;

There are 6 types of examples in the Rust FFI Omnibus and this is the only one that I cannot debug. It kinda works if you remove the returns Tuple and just have a Tuple argument, but no return type.

I have made a DRAFT raku module over here that has simple guidance of how to set this up (Dockerfile, cargo new ...) so you can just git clone https://github.com/p6steve/raku-Inline-Rust.git and uncomment the failing code in these two files.

Oh, and the error is Segmentation fault (core dumped) (on ubuntu)

Welcome to Rakudo™ v2022.04.
Implementing the Raku® Programming Language v6.d.
Built on MoarVM version 2022.04.

Any help / guidance much appreciated!

EDIT - Thanks to Christoph comment the segfault is now fixed.

BUT - I now have a new issue, the result is jumbled like this:

Tuple.new(x => 4252849424, y => 65535)   #I added a dd
425284942465535

So looks like there is some error still ;-(

As before any help much appreciated!

librasteve
  • 6,832
  • 8
  • 30
  • 3
    can you produce a backtrace from your core dump? [how](https://askubuntu.com/questions/1349047/where-do-i-find-core-dump-files-and-how-do-i-view-and-analyze-the-backtrace-st) – Sahandevs May 29 '22 at 02:32
  • 1
    Hi @Sahandevs - I tried setting ```export RUST_BACKTRACE=1``` nothing new. Ah - maybe I should read your how link! – librasteve May 29 '22 at 22:11
  • 1
    No luck with finding a ```core``` file anywhere in the src (or target) dirs. I tried adding a hashbang to the script and ```gdb ./ffi-omnibus.raku``` - that gives an error ```No executable file specified. Use the "file" or "exec-file" command.``` to get ```(gdb) exec-file ffi-omnibus.raku "/root/raku-Inline-Rust/ffi-omnibus.raku": not in executable format: file format not recognized``` my guess is that rakudo needs some prep to work nice with gdb. – librasteve May 29 '22 at 22:26
  • 1
    I also tried ```rakudo-debug ffi-omnibus.raku``` and that gets me this... ```>>> LOADING ffi-omnibus.raku >>> LOADING EVAL_1 + EVAL_1 (1 - 1) | CompUnit::DependencySpecification.new(:short-name) > r >>> LOADING EVAL_2 >>> LOADING EVAL_3 >>> LOADING EVAL_4 3 14 na na na na na Batman! 12 Segmentation fault (core dumped)``` – librasteve May 29 '22 at 22:30
  • 2
    Rakudo passes structs by pointer, not by value, resulting in an attempt to interpret your tuple values as a memory address... – Christoph May 30 '22 at 22:22
  • @Christoph - that's great ... thanks! Now it's just my values that are wrong (see EDIT) – librasteve May 31 '22 at 12:15
  • I don't know any Rust, but I suspect the function prototype should read something like `fn flip_things_around(tup: *Tuple)`, ie the parameter should have pointer type as well... – Christoph May 31 '22 at 21:29

0 Answers0