2017-01-07 15 views
4

私は実際にこれに正しい方向にプッシュを使用することができます。ルビーオブジェクトポインタをruby-ffiコールバックに渡すことはできますか?

typedef void cbfunc(void *data); 
void set_callback(cbfunc* cb); 
//do_stuff calls the callback multiple times with data as argument 
void do_stuff(void *data); 

このRubyコード:このCのコードが与えられ

proc = Proc.new do |data| 
    # somehow cast FFI::Pointer to be a ruby array here? 
    data.push(5) 
end 
Lib::set_callback(proc) 
Lib::do_stuff(ptr_to_a_ruby_obj_here) 

module Lib 
    extend FFI::Library 
    # ... 
    callback :cbfunc, [:pointer], :void 
    attach_function :set_callback, [:cbfunc], :void 
    attach_function :do_stuff, [:pointer], :void 
end 

は、私は、コールバックデータとしてのようなものをRubyの配列を渡すことができます任意の方法はあります

問題は、コールバックが複数回呼び出されることです。配列を簡単に構築する方法が必要ですさまざまなルビオブジェクトの

多分私は少し疲れているかもしれませんが、これを行うための簡単な方法があるように感じ、私はそれを見ていません。

+0

C、Rubyのいずれの側で配列作成をしたいですか? – tadman

+1

@tadman Ruby側です。私はちょうど私がprocをカレーすることができることを理解した、私はなぜ前にそれを考えなかったのか分からない。 –

+0

あなたはそれをはっきりと説明したからです。 [厚紙プログラマー](https://en.wikipedia.org/wiki/Rubber_duck_debugging)になると嬉しいです。あなたがそれを働かせることができれば、自己回答の質問は同じジャムの他の人を助けるでしょう。 – tadman

答えて

1

これを投稿した後、私はProcをカレーしてコールバックとして使用できることに気付きました。

だから、のようなもの:私はちょうどここ(C側の要件です)void *型のデータパラメータを無視に切り替え

proc = Proc.new do |results, data| 
    results.push(5) 
end 
results = [] 
callback = proc[results] 
Lib::set_callback(callback) 
Lib::do_stuff(nil) # Not concerned with this pointer anymore 

。 他にもいくつかの方法があるはずです。誰かが共有したいと思うなら、私は彼らのことを聞くことに興味があります。あなたは、そのオブジェクトのobject_idを使ってRubyオブジェクトからFFI::Pointerを作成することができます

1

:それはコールバックで戻っルビーに来るとき

# @param obj [any] Any value 
# @return [::FFI::Pointer] a pointer to the given value 
def ruby_to_pointer(obj) 
    require 'ffi' 
    address = obj.object_id << 1 
    ffi_pointer = ::FFI::Pointer.new(:pointer, address) 
end 

問題は、ポインタのこの種のうち、使用可能なRubyの値を取得しています。 FFIは、このための自然なインタフェースを提供していませんが、それはポインタ型だとルビーstandardlibモジュールfiddleは、ありません:

# @param ffi_pointer [FFI::Pointer, #to_i] 
# @return [any] Ruby object 
def pointer_to_ruby(ffi_pointer) 
    require 'fiddle' 
    address = ffi_pointer.to_i 
    fiddle = ::Fiddle::Pointer.new(address) 
    obj = fiddle.to_value 
end 

は、これは危険な操作です! FFI :: Pointer表現をRubyに戻す前に、オリジナルのRubyオブジェクトがガベージコレクションされていないことに細心の注意を払う必要があります。

関連する問題