class DL::Function

Public Class Methods

new(cfunc, argtypes, abi = nil, &block) click to toggle source
Calls superclass method
# File ext/dl/lib/dl/func.rb, line 51
def initialize cfunc, argtypes, abi = nil, &block
  if DL.fiddle?
    abi ||= CALL_TYPE_TO_ABI[(cfunc.calltype rescue nil)]
    if block_given?
      @cfunc = Class.new(FiddleClosureCFunc) {
        define_method(:call, block)
      }.new(cfunc.ctype, argtypes, abi, cfunc.name)
    else
      @cfunc  = cfunc
    end

    @args   = argtypes
    super(@cfunc, @args.reject { |x| x == TYPE_VOID }, cfunc.ctype, abi)
  else
    @cfunc = cfunc
    @stack = Stack.new(argtypes.collect{|ty| ty.abs})
    if( @cfunc.ctype < 0 )
      @cfunc.ctype = @cfunc.ctype.abs
      @unsigned = true
    else
      @unsigned = false
    end
    if block_given?
      bind(&block)
    end
  end
end

Public Instance Methods

bind(&block) click to toggle source
# File ext/dl/lib/dl/func.rb, line 117
def bind(&block)
  if DL.fiddle?
    @cfunc = Class.new(FiddleClosureCFunc) {
      def initialize ctype, args, abi, name, block
        super(ctype, args, abi, name)
        @block = block
      end

      def call *args
        @block.call(*args)
      end
    }.new(@cfunc.ctype, @args, abi, name, block)
    @ptr = @cfunc
    return nil
  else
    if( !block )
      raise(RuntimeError, "block must be given.")
    end
    unless block.lambda?
      block = Class.new(self.class){define_method(:call, block); def initialize(obj); obj.instance_variables.each{|s| instance_variable_set(s, obj.instance_variable_get(s))}; end}.new(self).method(:call)
    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
      if( @cfunc.ptr == 0 )
        raise(RuntimeException, "can't bind C function.")
      end
    end
  end
end
bind_at_call(&block) click to toggle source
# File ext/dl/lib/dl/func.rb, line 202
def bind_at_call(&block)
  bind(&block)
end
bound?() click to toggle source
# File ext/dl/lib/dl/func.rb, line 198
def bound?()
  @cfunc.ptr != 0
end
call(*args, &block) click to toggle source
Calls superclass method
# File ext/dl/lib/dl/func.rb, line 87
def call(*args, &block)
  if DL.fiddle?
    if block_given?
      args.find { |a| DL::Function === a }.bind_at_call(&block)
    end
    super
  else
    funcs = []
    if $SAFE >= 1 && args.any? { |x| x.tainted? }
      raise SecurityError, "tainted parameter not allowed"
    end
    _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
end
name() click to toggle source
# File ext/dl/lib/dl/func.rb, line 83
def name
  @cfunc.name
end
to_i() click to toggle source
# File ext/dl/lib/dl/func.rb, line 79
def to_i()
  @cfunc.to_i
end
unbind() click to toggle source
# File ext/dl/lib/dl/func.rb, line 165
def unbind()
  if DL.fiddle? then
    if @cfunc.kind_of?(Fiddle::Closure) and @cfunc.ptr != 0 then
      call_type = case abi
                  when CALL_TYPE_TO_ABI[nil]
                    nil
                  when CALL_TYPE_TO_ABI[:stdcall]
                    :stdcall
                  else
                    raise(RuntimeError, "unsupported abi: #{abi}")
                  end
      @cfunc = CFunc.new(0, @cfunc.ctype, name, call_type)
      return 0
    elsif @cfunc.ptr != 0 then
      @cfunc.ptr = 0
      return 0
    else
      return nil
    end
  end
  if( @cfunc.ptr != 0 )
    case @cfunc.calltype
    when :cdecl
      remove_cdecl_callback(@cfunc.ptr, @cfunc.ctype)
    when :stdcall
      remove_stdcall_callback(@cfunc.ptr, @cfunc.ctype)
    else
      raise(RuntimeError, "unsupported calltype: #{@cfunc.calltype}")
    end
    @cfunc.ptr = 0
  end
end
unbind_at_call() click to toggle source
# File ext/dl/lib/dl/func.rb, line 206
def unbind_at_call()
end
wrap_result(r) click to toggle source
# File ext/dl/lib/dl/func.rb, line 105
def wrap_result(r)
  case @cfunc.ctype
  when TYPE_VOIDP
    r = CPtr.new(r)
  else
    if( @unsigned )
      r = unsigned_value(r, @cfunc.ctype)
    end
  end
  r
end