FFI を使って Ruby から Rust の関数を呼び出す(その2)

前回は、引数も戻り値もなかったので、今回は何種類か試してみようと思う。

引数や戻り値を設定する際、Ruby 側では、下記のように引数や戻り値にそれぞれ型を定義する。

# attach_function メソッドの 第1引数が対応する関数名になる。(:perform の部分)
# 第2引数の配列に、対応する関数の引数の型を定義する。(:int の部分)
# 第3引数には関数の戻り値の型を定義する(:double の部分)
# 下記の定義は、Rust 側の fn perform(i: i32) -> f64 という関数に対応する。
attach_function :perform, [:int], :double

設定可能な型の一覧はここに記述されている。 Rust 側では通常通りの関数の定義でOK。

プリミティブ型

まず、数値やブーリアンをいくつか引数で渡して、数値を返す様な関数を定義してみる。

$ cargo build --release
$ bundle exec ruby ffi_sample.rb
1, 2.3, true
2

これは、そのまま使えるようだ。

文字列

次に、文字列を渡して、文字列を返す関数を定義してみる。 Rust 側のプログラムでは、先ほどとは違いRuby から渡せれた文字列を Rust の文字列に変換する必要がある。 また、文字列を返す場合にも、Rust の文字列から Ruby の文字列に変換する必要がある。(正確には、Ruby の文字列ではなく、C の文字列だと思うが)

Ruby から渡された文字列は C の文字列として渡ってくるため、libc の c_char を使用する。 で、渡されたポインタを CStr を使い、Ruby から渡された文字列を Rust の文字列に変換する。

似たような構造体に ```CString```にあるが、こちらは所有権を保持している場合の C の文字列表現。
戻り値では、Rust の文字列を C の文字列に変換するが、こちらは、所有権を保持している文字列から、C の文字列に変換するため、```CString```を使用している。

このプログラムを実行すると

$ cargo build –release $ bundle exec ruby ffi_sample.rb こんにちは、世界

となる。

## 構造体

次は、構造体を使ってみる。
例として、引数と戻り値が構造体になる関数を定義してみる。

Rust と Ruby で同じ構造体をそれぞれ定義する。
Ruby 側では、FFI::Struct を継承したクラスを作成し、layout メソッドで、メンバーを定義する。
Rust 側では、C の構造体と互換性を保証するために、```repr(C)``` をつけて、struct を作成。

<script src="https://gist.github.com/mzumi/710db6eeb0e0943930cd051ddffda1ec.js"></script>
<script src="https://gist.github.com/mzumi/de593a8e711224188d59d48e408efb38.js"></script>

実行結果は、下記のようになる。

$ cargo build –release $ bundle exec ruby ffi_sample.rb i: 2, j:3 ```

Ruby 側のメソッドの引数と戻り値に by_value というメソッドで指定しているが、これは構造体を値渡しにするといった指定になる。参照渡しにする場合には、by_ref というメソッドで指定すれば、参照渡しになる。 参照渡しについては、ポインタによる指定もできるのだが、ポインタについてはまた次回。

Contents

comments powered by Disqus