diff options
Diffstat (limited to 'ext/dl/lib/dl/func.rb')
-rw-r--r-- | ext/dl/lib/dl/func.rb | 62 |
1 files changed, 22 insertions, 40 deletions
diff --git a/ext/dl/lib/dl/func.rb b/ext/dl/lib/dl/func.rb index 7a8b62e325..0ee2df1f23 100644 --- a/ext/dl/lib/dl/func.rb +++ b/ext/dl/lib/dl/func.rb @@ -1,4 +1,5 @@ require 'dl' +require 'dl/closure' require 'dl/callback' require 'dl/stack' require 'dl/value' @@ -9,18 +10,17 @@ module DL include DL include ValueUtil - def initialize(cfunc, argtypes, &proc) - @cfunc = cfunc - @stack = Stack.new(argtypes.collect{|ty| ty.abs}) - if( @cfunc.ctype < 0 ) - @cfunc.ctype = @cfunc.ctype.abs - @unsigned = true + def initialize cfunc, argtypes, abi = DEFAULT, &block + if block_given? + @cfunc = Class.new(DL::Closure) { + define_method(:call, block) + }.new(cfunc.ctype, argtypes) else - @unsigned = false - end - if( proc ) - bind(&proc) + @cfunc = cfunc end + + @args = argtypes + native_init(@args.reject { |x| x == TYPE_VOID }, cfunc.ctype, abi) end def to_i() @@ -32,11 +32,10 @@ module DL end def call(*args, &block) - funcs = [] - args = wrap_args(args, @stack.types, funcs, &block) - r = @cfunc.call(@stack.pack(args)) - funcs.each{|f| f.unbind_at_call()} - return wrap_result(r) + if block_given? + args.find { |a| DL::Function === a }.bind_at_call(&block) + end + native_call(*args) end def wrap_result(r) @@ -52,33 +51,16 @@ module DL end def bind(&block) - if( !block ) - raise(RuntimeError, "block must be given.") - end - if( @cfunc.ptr == 0 ) - cb = Proc.new{|*args| - ary = @stack.unpack(args) - @stack.types.each_with_index{|ty, idx| - case ty - when TYPE_VOIDP - ary[idx] = CPtr.new(ary[idx]) - end - } - r = block.call(*ary) - wrap_arg(r, @cfunc.ctype, []) - } - case @cfunc.calltype - when :cdecl - @cfunc.ptr = set_cdecl_callback(@cfunc.ctype, @stack.size, &cb) - when :stdcall - @cfunc.ptr = set_stdcall_callback(@cfunc.ctype, @stack.size, &cb) - else - raise(RuntimeError, "unsupported calltype: #{@cfunc.calltype}") + @cfunc = Class.new(DL::Closure) { + def initialize ctype, args, block + super(ctype, args) + @block = block end - if( @cfunc.ptr == 0 ) - raise(RuntimeException, "can't bind C function.") + + def call *args + @block.call(*args) end - end + }.new(@cfunc.ctype, @args, block) end def unbind() |