我可以将 ruby 对象指针传递给 ruby-ffi 回调吗?
Can I pass a ruby object pointer to a ruby-ffi callback?
我真的可以在正确的方向上推动这一点。
鉴于此 C 代码:
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代码:
module Lib
extend FFI::Library
# ...
callback :cbfunc, [:pointer], :void
attach_function :set_callback, [:cbfunc], :void
attach_function :do_stuff, [:pointer], :void
end
有什么方法可以传递 ruby 数组作为回调数据,例如:
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)
问题是回调将被调用多次,我需要一种方法来轻松构建各种 ruby 对象的数组。
也许我只是有点累了,但感觉有一种简单的方法可以完成这项工作,只是我没有看到。
我发帖后意识到我可以柯里化 Proc 并将其用作回调。
所以像这样:
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
我这里只是切换到忽略void*数据参数(这是C端的要求)。
肯定还有其他一些方法,如果有人想分享,我很想知道它们。
您可以使用 object_id
对象的 object_id
:
从 Ruby 对象创建 FFI::Pointer
# @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 值,当它在回调中返回到 Ruby 时。 FFI 没有为此提供自然接口,但是 Ruby 标准库模块 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 对象没有被垃圾回收
我真的可以在正确的方向上推动这一点。
鉴于此 C 代码:
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代码:
module Lib
extend FFI::Library
# ...
callback :cbfunc, [:pointer], :void
attach_function :set_callback, [:cbfunc], :void
attach_function :do_stuff, [:pointer], :void
end
有什么方法可以传递 ruby 数组作为回调数据,例如:
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)
问题是回调将被调用多次,我需要一种方法来轻松构建各种 ruby 对象的数组。
也许我只是有点累了,但感觉有一种简单的方法可以完成这项工作,只是我没有看到。
我发帖后意识到我可以柯里化 Proc 并将其用作回调。
所以像这样:
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
我这里只是切换到忽略void*数据参数(这是C端的要求)。 肯定还有其他一些方法,如果有人想分享,我很想知道它们。
您可以使用 object_id
对象的 object_id
:
FFI::Pointer
# @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 值,当它在回调中返回到 Ruby 时。 FFI 没有为此提供自然接口,但是 Ruby 标准库模块 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 对象没有被垃圾回收