雰囲気で書き始める Rustler

おはこんばんにちは、 pojiro です。

今回は Nerves は関係なく、Rust をさわったことのない私が [Rustler](https://github.com/rusterlium/rustler) を 雰囲気で書き始める記事になります。

## 環境

変な時間に目が覚めて書いており、手元の環境がいつもと違って Windows です。このまま進めていきます。

- WSL には Ubuntu 20.04 が入っています。
- Elixir & Erlang は asdf でインストール済みです。
- Rust は https://www.rust-lang.org/ja/tools/install の WSL 向けの方法でインストール済みです。

## 導入

Elixir のプロジェクトを作って、

```sh
mix new learn_rustler
...
cd learn_rustler
```

何はなくとも Git 管理の準備をして、

```sh
git init .
git config user.name "Your name"
git config user.email your@email.address
git add .
git commit -m "Initial commit"
```

[Rustler のドキュメント](https://hexdocs.pm/rustler/readme.html)に従って、mix.exs を 開いて deps に rustler を追加して、

```elixir
  defp deps do
    [
      {:rustler, "~> 0.30.0", runtime: false}
    ]
  end
```

> Fetch all necessary dependencies

```sh
mix deps.get
```

> Check your installation by showing help from the installed Mix task

```sh
mix help rustler.new
** (Mix) The task "rustler.new" could not be found
```

あれ？となりますが、これはコンパイルしてないからなので、

```sh
mix compile
mix help rustler.new

                                mix rustler.new                                 

Generates boilerplate for a new Rustler project.

Usage:

    mix rustler.new [--module <Module>] [--name <Name>] [--otp-app <OTP App>]

Location: _build/dev/lib/rustler/ebin
```

あっさりしてます。が、インストールできていることのチェックらしいので、こんなものなんでしょう。

> Generate the boilerplate for a new Rustler project. Follow the instructions to configure your project:

```sh
mix rustler.new # 実行すると対話式になりました。
This is the name of the Elixir module the NIF module will be registered to.
Module name > LearnRustler.Nif # 入力
This is the name used for the generated Rust crate. The default is most likely fine.
Library name (learnrustler_nif) > learn_rustler_nif # default は _ が入ってないのが嫌なので修正
* creating native/learn_rustler_nif/.cargo/config.toml
* creating native/learn_rustler_nif/README.md
* creating native/learn_rustler_nif/Cargo.toml
* creating native/learn_rustler_nif/src/lib.rs
* creating native/learn_rustler_nif/.gitignore
Ready to go! See /home/pojiro/Repos/learn_rustler/native/learn_rustler_nif/README.md for further instructions.
```

出力の最終行に

> See /home/pojiro/Repos/learn_rustler/native/learn_rustler_nif/README.md for further instructions.

とあるので、見ると

```md
## To load the NIF:

```elixir
defmodule LearnRustler.Nif do
  use Rustler, otp_app: :learn_rustler, crate: "learn_rustler_nif"

  # When your NIF is loaded, it will override this function.
  def add(_a, _b), do: :erlang.nif_error(:nif_not_loaded)
end
\```
```

このモジュールを追加すればよさそうです。

```sh
mkdir lib/learn_rustler
vim lib/learn_rustler/nif.ex
# コードの貼り付け
```

実行できるかな？ `iex -S mix` でシェルを立ち上げると

```sh
Compiling 1 file (.ex)
    Updating crates.io index
  Downloaded unreachable v1.0.0
  Downloaded heck v0.4.1
  Downloaded memchr v2.6.4
  Downloaded unicode-ident v1.0.12
  Downloaded quote v1.0.33
  Downloaded proc-macro2 v1.0.70
  Downloaded syn v2.0.41
  Downloaded regex-syntax v0.8.2
  Downloaded regex-automata v0.4.3
  Downloaded regex v1.10.2
  Downloaded void v1.0.2
  Downloaded lazy_static v1.4.0
  Downloaded aho-corasick v1.1.2
  Downloaded rustler_sys v2.3.1
  Downloaded rustler v0.30.0
  Downloaded rustler_codegen v0.30.0
  Downloaded 16 crates (2.0 MB) in 1.27s
Compiling crate learn_rustler_nif in release mode (native/learn_rustler_nif)
   Compiling memchr v2.6.4
   Compiling regex-syntax v0.8.2
   Compiling proc-macro2 v1.0.70
   Compiling unicode-ident v1.0.12
   Compiling void v1.0.2
   Compiling heck v0.4.1
   Compiling lazy_static v1.4.0
   Compiling unreachable v1.0.0
   Compiling aho-corasick v1.1.2
   Compiling quote v1.0.33
   Compiling syn v2.0.41
   Compiling regex-automata v0.4.3
   Compiling regex v1.10.2
   Compiling rustler_sys v2.3.1
Compiling lib/learn_rustler/nif.ex (it's taking more than 10s)
   Compiling rustler_codegen v0.30.0
   Compiling rustler v0.30.0
   Compiling learn_rustler_nif v0.1.0 (/home/pojiro/Repos/learn_rustler/native/learn_rustler_nif)
    Finished release [optimized] target(s) in 9.27s
```

おお、ビルドが走りました。ということは、

```elixir
iex(1)> LearnRustler.Nif.add(1, 2)
3
```

ばっちり、動きました！

ここまではすんなりこれましたが、Rustler から Tuple をどう返すか？ Elixir から List や Tuple をどう渡すのかを知らないと使えるコードが書けないです。

これ以降は随時追記していけたらとおもいます。今日（12/17）はいったんここまで。

## 基礎

続くはず！

いろいろ調べたのですが、 Rustler のテストコードが一番、使い方が分かって良い気がしました。
つまり、👇を見るべし！

https://github.com/rusterlium/rustler/tree/master/rustler_tests/native/rustler_test/src

このテストを見ながら実装したのが [Zenohex v0.2.0](https://github.com/b5g-ex/zenohex/tree/v0.2.0) 👇です！

https://github.com/b5g-ex/zenohex/tree/v0.2.0