はじめに
わたしは、日頃は Ruby でお仕事をしていて、ここ 1 年ぐらい Rust を勉強しだし、最近では Rust of Us という有志の勉強会をやっています。
この AdventCalender に登録した時点では、Rust でわたしが作りだしたライブラリについて書くつもりでした。しかし、先日の RubyKaigi で発表のあった turboruby が、かなり面白かったのでその紹介をさせていただきます。
turboruby とは
turboruby とは、TILDE という会社によって作られたものです。
TILDE は、Rust Core team の wycats 等がいます。
wycats は各所で Rust の発表を行なっており、本の貸し借りで Rust の Ownership を説明するスライド を見たことがある人もいるでしょう。
彼の働く TILDE では、Ruby on Rails を使ってプロダクトをつくっており、彼の過去の発表では Ruby と Rust を連携させるもの もありました。
このときの発表では、FFI を使って Ruby から Rust のプログラムを呼んでいました。
しかし、今回の RubyKaigi での発表 では、今までの FFI を使っていたところを turboruby というライブラリを使うようになりました。この turboruby により、Ruby でRust のコードの文字列を返すメソッドを記述することで、Ruby の拡張ライブラリを Rust で記述できるようになります。
どうやって動かすの
turboruby のリポジトリにある README は、bundler によって生成されたままの README なので、情報がないです。そこで、integration_spec.rb を参考、String クラスに hello
と返すだけのメソッドを追加するものを作ってみました。
リポジトリに含まれている、run.sh がコマンドの流れ、compile.sh が turboruby のコードをコンパイルするためのスクリプトになります。
まず lib ディレクトリには、src というディレクトリを用意して、その中に trb ファイルを記述します。また、lib ディレクトリには gemspec ファイルも用意しておきます。今回の trb ファイルは、このようになっています。
class String
def hello
<<-RUST
println!("hello");
RUST
end
end
このリポジトリのトップで、bundle exec ruby compile.rb lib out
とすると、out ディレクトリ内にコンパイルされた Rust のコード類が生成されます。実行後の out ディレクトリの構成は以下のようになります。
$ ls -lR out
total 32
-rw-r--r-- 1 takkanm staff 350 12 16 20:05 Cargo.toml
-rw-r--r-- 1 takkanm staff 168 12 16 20:05 extconf.rb
-rw-r--r-- 1 takkanm staff 467 12 16 20:05 hello.c
-rw-r--r-- 1 takkanm staff 463 12 16 20:05 hello.gemspec
drwxr-xr-x 3 takkanm staff 102 12 16 20:05 src/
out/src:
total 8
-rw-r--r-- 1 takkanm staff 305 12 16 20:05 lib.rs
では生成された、lib.rs の中身を見てみましょう。
extern crate libc;
extern crate ffi_buf;
use ffi_buf::Buf;
trait RubyString {
fn trb_hello(&self);
}
impl<'a> RubyString for &'a str {
fn trb_hello(&self) {
println!("hello");
}
}
#[no_mangle]
pub extern "C" fn trb_string_hello(rb_self: Buf) {
rb_self.as_slice().trb_hello()
}
RubyString の中に trb_hello というメソッドができて、 'hello' と表示されるようになっているのがわかります。
この後、run.sh に書かれている手順で、crate の build 、make を行なうと hello.bundle(mac の場合)ができ、その共有ライブラリを Ruby に読み込ませて実行できることがわかります。
最後に
今回は単純に文字を表示するメソッドを追加しただけですが、turboruby のリポジトリにある例のように、Ruby のオブジェクトを Rust 側に渡して値を返すということもできます。
turboruby は、ソースを読むとまだまだ実験的なライブラリで、機能が足りてないことがわかります。
しかし、これが成長すれば普段 Rails で仕事しているような私にはとっても恩恵があるような気がしており、とても楽しみです。