Subject: [ruby-ffi] Re: cannot define function pointers that take function pointer arguments in jruby struct layout |
From: Aman Gupta |
Date: 9/21/09 4:45 PM |
To: ruby-ffi@googlegroups.com |
On Thu, Sep 17, 2009 at 8:13 PM, Wayne Meissner <wmeissner@gmail.com> wrote:
<themastermind1@gmail.com>:2009/9/14 Aman GuptaI'm using ffi-swig-generator on: typedef void (*MyCallback) (void *data); typedef struct { void (*member) (MyCallback cb); } MyStruct; which generates: callback(:MyCallback, [ :pointer ], :void) class MyStruct < FFI::Struct layout( :member, callback([ :MyCallback ], :void) ) endThe root problem here is the resolution of :MyCallback - it will fail on both JRuby and 1.9 (or at least it does for me). The best way to ensure this works is to define a constant in enclosing module, and use that on the layout line. e.g. module Foo extend FFI::Library MyCallback = callback(:MyCallback, [ :pointer ], :void class MyStruct < FFI::Struct layout(:member, callback(MyCallback, :void)) end end
I like this syntax, although it only works if the callback is capitalized.
Alternatively you can look it up using Foo.find_type(:MyCallback) module Foo extend FFI::Library callback(:MyCallback, [ :pointer ], :void class MyStruct < FFI::Struct layout(:member, callback(Foo.find_type(:MyCallback), :void)) end end
This one is harder to implement, since ffi-swig-generator doesn't necessarily know the name of the enclosing module.
ffi-swig-generator should be altered to do one of the above.
How about: diff --git a/lib/generator/function.rb b/lib/generator/function.rb index e0b9ac2..7432747 100644 --- a/lib/generator/function.rb +++ b/lib/generator/function.rb @@ -40,7 +40,7 @@ module FFI end def to_s unless @inline - @indent_str + "callback(:#{@symname}, [ #{get_params.join(', ')} ], #{get_rtype})" + @indent_str + "CB_#{@symname} = callback(:#{@symname}, [ #{get_params.join(', ')} ], #{get_rtype})" else @indent_str + "callback([ #{get_params.join(', ')} ], #{get_rtype})" end diff --git a/lib/generator/type.rb b/lib/generator/type.rb index 8846f60..9c01202 100644 --- a/lib/generator/type.rb +++ b/lib/generator/type.rb @@ -99,7 +99,7 @@ module FFI ffi_type_from(Generator::TYPES['int']) if @declaration.is_enum? end def callback - ":#{@full_decl.scan(/^callback\s(\w+)/).flatten[0]}" if @declaration.is_callback? + "CB_#{@full_decl.scan(/^callback\s(\w+)/).flatten[0]}" if @declaration.is_callback? end def inline_callback Callback.new(:node => @node, :inline => true, :typedefs => @typedefs).to_s if @declaration.is_inline_callback? This works for my use case, although I don't particularly like the CB_ prefix. Maybe C_, Callback_ or just C? Aman
Struct#find_type tries to emulate this behaviour, and fails - ruby does not appear to have anyway of getting the lexical enclosing module of a subclass, when accessed from a method of the superclass. If anyone knows a way, I'd be interested.