summaryrefslogtreecommitdiff
path: root/ext/dl/lib/dl/func.rb
diff options
context:
space:
mode:
Diffstat (limited to 'ext/dl/lib/dl/func.rb')
-rw-r--r--ext/dl/lib/dl/func.rb64
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()