erlang的nif通常是用C写,然后编译成动态库,在erlang里面通过erlang:load_nif加载动态链接库,在看rust时候发现rust也能变成动态库给c调用,想了下根据原理,rust应该也可以给erlang写nif,并且rust相比c有内存安全,更方便的工程与依赖库管理编译工具的优势。
查了一下,rust已经有现成的工具库实现了。
Rustler, 提供更方便的写法实现rust和erlang之间参数传递,内存安全。rustler和elixir更搭,通过mix,可以轻松组建工程。
erlang_nif-sys, 用于写更底层的erlang nif,rust代码里面都会有unsafe包住。
为验证rust写的nif可以在erlang中使用,随便写了例子玩一下。
rust 安装
`curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh`
测试环境
- centos 7.4
- erlang OTP 20
- rust 1.43
- rustler 0.21
example
rust代码,代码相比用C写,要稍微简洁易懂些。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
extern crate rustler;
use rustler::{Encoder, Env, NifResult, Term};
rustler_export_nifs!(
"test_inf",
[("add", 2, add)],
Some(on_load)
);
fn on_load<'a>(_env: Env<'a>, _load_info: Term<'a>) -> bool {
println!("Runs on library load");
true
}
fn add<'a>(env: Env<'a>, args: &[Term<'a>]) -> NifResult<Term<'a>> {
let num1: i32 = args[0].decode()?;
let num2: i32 = args[1].decode()?;
Ok((num1 + num2).encode(env))
}
rust依赖与编译配置1
2
3
4
5
6
7
8
9
10[package]
name = "rust_in_erlang"
version = "0.1.0"
[lib]
name = "test_inf"
crate-type = ["dylib"]
[dependencies]
rustler = ">=0.13.0"
erlang代码1
2
3
4
5
6
7
8
9
10
11
12-module (test_inf).
-export([add/2]).
-on_load(init/0).
init() ->
ok = erlang:load_nif("target/debug/libtest_inf", none).
add(_X, _Y) ->
exit(nif_library_not_loaded).
整个工程的测试代码已上传github,获取代码
测试
1 | > cargo build |
well well well , it works!