10

I was trying to build a simple rust rss 'harvester' for my soup.io blog and then post those entries to diaspora with node.js (since there is an npm package for that)

I want to learn how to use rust from node so this is why I'm building this project.

My problem is that I don't know how to call the ffi function with the right types.

var lib = ffi.Library('target/debug/libmain', {
    'get_soup': ['Vec<Post>', ['String']]
});

The 'Vec<Post>' doesn't work. I get that I have to use ref for that. But I don't really know how and what that actually does.

I understand that I have to translate the rust types to javascript?

How can I use Vec<Post> in my ffi function?

my github project for that: Realtin/suppe

and here the relevant code:

Rust Code:

extern crate rss;
extern crate hyper;

use rss::Rss;
use std::io::prelude::*;

#[derive(Debug)]
pub struct Post  {
    title: String,
    link: String,
    description: String,
}

fn main() {
    let user = "realtin".to_string();
    let vec = get_soup(&user);
    println!("{:?}", vec[vec.len()-1]);
}

#[no_mangle]
pub extern fn get_soup(user: &str) ->Vec<Post>{
    let url = format!("http://{}.soup.io/rss", user);
    let mut vec = Vec::new();

    let client = hyper::Client::new();
    let mut response = client.get(&url).send().unwrap();

    let mut suppe = String::new();
    let _= response.read_to_string(&mut suppe);

    let rss::Rss(channel) = suppe.parse::<rss::Rss>().unwrap();

    for item in channel.items.into_iter().rev() {
      let item_object = Post {
           title: item.title.unwrap(),
           link: item.link.unwrap(),
           description: item.description.unwrap(),
        };
        vec.push(item_object);
    }
    return vec;
}

NodeJS code:

var ref = require('ref');
var StructType = require("ref-struct");
var ffi = require('ffi');

var Post = StructType({
  title: String,
  link: String,
  description: String,
});
// var vecPost = ref.refType(ref.types.Object);

var lib = ffi.Library('target/debug/libmain', {
    'get_soup': ['Vec<Post>', ['String']]
});

var posts = lib.get_soup("realtin");
3
  • 2
    You may be interested in The Rust FFI Omnibus as well. Commented Aug 20, 2015 at 15:03
  • @Shepmaster oh this is amazing! I was looking for something like this! Commented Aug 21, 2015 at 9:35
  • Great! Be sure to file any issues on Github if you are looking for any specific examples or if anything can be made clearer. Commented Aug 21, 2015 at 12:41

2 Answers 2

10

The short answer: you cannot export any Rust function for FFI bindings, you need to specifically export Rust functions compatible with C.

Specifically, this means that you need to expose only C-struct compatible objects OR expose opaque pointers (which can only be manipulated through Rust functions).

In your case, Vec<Post> is not compatible with usage in FFI, because Vec is not.

You can find more information in the FFI Guide.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! that makes sense :)
-1

Some data types can be passed directly, using your approach

Export Rust using FFI https://svartalf.info/posts/2019-03-01-exposing-ffi-from-the-rust-library/

and then call it from nodejs from using something like https://github.com/node-ffi/node-ffi

May be not using structure that you require, but you can convert data in one or both ends. As a last resort you can use JSON. There will be some overhead but not a lot

https://stackoverflow.com/a/42498913/3232611

can use protocol buffers, if JSON performance is bottleneck, but in most cases its not worth complexity

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.