diff options
Diffstat (limited to 'ext/dl/lib/dl/func.rb')
-rw-r--r-- | ext/dl/lib/dl/func.rb | 64 |
1 files changed, 41 insertions, 23 deletions
diff --git a/ext/dl/lib/dl/func.rb b/ext/dl/lib/dl/func.rb index c5a2dda355..7a8b62e325 100644 --- a/ext/dl/lib/dl/func.rb +++ b/ext/dl/lib/dl/func.rb @@ -1,26 +1,26 @@ require 'dl' -require 'dl/closure' require 'dl/callback' require 'dl/stack' require 'dl/value' require 'thread' module DL - class Function < DL::Method + class Function include DL include ValueUtil - def initialize cfunc, argtypes, abi = DEFAULT, &block - if block_given? - @cfunc = Class.new(DL::Closure) { - define_method(:call, block) - }.new(cfunc.ctype, argtypes) + 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 else - @cfunc = cfunc + @unsigned = false + end + if( proc ) + bind(&proc) end - - @args = argtypes - super(@cfunc, @args.reject { |x| x == TYPE_VOID }, cfunc.ctype, abi) end def to_i() @@ -32,10 +32,11 @@ module DL end def call(*args, &block) - if block_given? - args.find { |a| DL::Function === a }.bind_at_call(&block) - end - super + 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) end def wrap_result(r) @@ -51,16 +52,33 @@ module DL end def bind(&block) - @cfunc = Class.new(DL::Closure) { - def initialize ctype, args, block - super(ctype, args) - @block = 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}") end - - def call *args - @block.call(*args) + if( @cfunc.ptr == 0 ) + raise(RuntimeException, "can't bind C function.") end - }.new(@cfunc.ctype, @args, block) + end end def unbind() |