Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling Rust from NodeJS

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");
like image 493
anderspree Avatar asked Aug 20 '15 13:08

anderspree


1 Answers

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.

like image 195
Matthieu M. Avatar answered Oct 12 '22 21:10

Matthieu M.