使用 Rust 語言開發 Erlang NIF

Rustler 項目還不是很成熟, 基本可用. 有興趣的能夠給做者提 Issue.git

Rustler 是一個在安全的用 Rust 編寫 Erlang NIF 的庫. 這裏安全的含義是, 它不會致使 BEAM(Erlang 虛擬機)的崩潰. 該庫提供了一個設施用於生成與BEAM交互的模板, 處理Erlang Term的編碼和解碼. Rustler 適用於 Erlang 和 Elixir, Elixir 是首選的.github

功能

  • 安全性 - 用 Rust 編寫的NIF毫不會致使BEAM崩潰.安全

  • 互操做性 - 編碼和解碼Rust值到Erlang Term就像調用函數同樣容易.app

  • 複合類型 - 能夠用屬性指定某個 Rust 結構爲 Encodable, Decodableide

  • 資源對象 - 能夠安全地傳遞Rust結構到Erlang代碼, 該結構再也不被引用時自動刪除.函數

入門

最簡單的入門方法是, 使用Mix項目生成器工具

運行下面的命令安裝Rustler的Mix項目生成器ui

mix archive.install https://github.com/hansihe/rustler_archives/raw/master/rustler_installer.ez

運行下面的命令建立一個rustler項目編碼

mix rustler.new

須要安裝 Nightly 版本的 Rust. 首先安裝 rustup. 並在項目目錄下執行 rustup override add nightly-2016-05-07-x86_64-apple-darwin.spa

Rust NIF

下面是一個最小的Rust NIF實現, 它只是簡單的實現了一個加法函數返回兩個數字的和.

#![feature(plugin)]
#![plugin(rustler_codegen)]

#![feature(link_args)]
#[link_args = "-flat_namespace -undefined suppress"]
extern {}

#[macro_use]
extern crate rustler;
use rustler::{ NifEnv, NifTerm, NifResult, NifEncoder };

rustler_export_nifs!(
    "Elixir.Test",
    [("add", 2, add)],
    None
);

fn add<'a>(env: &'a NifEnv, args: &Vec<NifTerm>) -> NifResult<NifTerm<'a>> {
    let num1: i64 = try!(args[0].decode());
    let num2: i64 = try!(args[1].decode());
    Ok((num1 + num2).encode(env))
}

OSX下面的編譯問題參考 https://github.com/hansihe/Ru...

與 Mix 項目集成

對於使用Mix的項目, 在Hex上有一個助手包. 這個包包含一個Mix編譯器, 進行自動環境檢查, crate 編譯和nif加載. 若是使用mix,極其推薦使用這個包, 它使你基於Rust開發Erlang NIF更加方便.

要啓動用Rust NIF的自動編譯, 完成以下步驟:

  • 添加 rustler 到 mix.exs 依賴

  • 添加 :rustler 編譯器到項目的 compilers 列表. compilers: [:rustler] ++ Mix.compilers

  • 添加一個 rustler_crates: ["CRATE_PATH"]project 函數, CRATE_PATH 應該是一個到包含 Cargo.toml文件的相對於mix項目更目錄的相對路徑.

完成後 mix.exs 文件看起來像這樣:

defmodule YourProject.Mixfile do
  use Mix.Project
 
  def project do
    [app: :your_project,
     [...]
     compilers: [:rustler] ++ Mix.compilers,
     rustler_crates: ["."],
     deps: deps]
  end

  [...]
 
  defp deps do
    [{:rustler, "~> 0.0.7"}]
  end
end

而後能夠經過 mix compile編譯項目, 若是環境設置有任何問題, rustler編譯器插件應該可以提示相關的說明如何解決.

加載NIF

加載一個Rust NIF和普通的NIF沒什麼區別. 實際的加載是經過調用 Rustler.load_nif(<LIBRARY_NAME>)完成的, 一般在Elixir用@on_load鉤子來實現.

defmodule MyProject.NativeModule do
  @on_load :load_nif

  defp load_nif do
    :ok = Rustler.load_nif("<LIBRARY_NAME>")
  end

  // When loading a NIF module, dummy clauses for all NIF functions are required.
  // NIF dummies usually just error out when called when the NIF is not loaded, as that should
  // never normally happen.
  def my_native_function(_arg1, _arg2), do: exit(:nif_not_loaded)
end

注意 <LIBRARY_NAME>Cargo.toml文件中[lib]中的庫名字.

關於Rustler 的依賴

打開 RustlerCargo.toml 文件咱們看到下面的代碼

[dependencies]
ruster_unsafe = ">=0.4"
libc = ">=0.1"
lazy_static = "0.1.*"

它依賴 ruster_unsafe 了去實現用 Rust 開發 NIF, ruster_unsafe 是一個底層的Erlang NIF的語言綁定, Rustler 只是一個集成到 Elixir 的助手工具.

相關文章
相關標籤/搜索