Can I pass a ruby ​​object pointer to a ruby-ffi callback?

I could really use the push in the right direction.

Given this C code:

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);

This Ruby Code:

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

Is there a way to pass the ruby ​​array as callback data, for example:

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)

The problem is that the callback will be called several times, and I need a way to easily build an array of different ruby ​​objects.

I may be a little tired, but it seems to me that there is an easy way to do this, and I just do not see it.

+4
source share
2 answers

I realized after posting this that I can curry Proc and use this as a callback.

So something like:

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) . , , - .

+1

FFI::Pointer Ruby object_id:

# @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 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

! , Ruby , FFI:: Pointer Ruby.

+1

Source: https://habr.com/ru/post/1666056/


All Articles