123456789_123456789_123456789_123456789_123456789_

Class: Fiddle::Function

Relationships & Source Files
Inherits: Object
Defined in: lib/fiddle/function.rb,
ext/fiddle/pinned.c,
lib/fiddle/ffi_backend.rb

Overview

Description

A representation of a C function

Examples

‘strcpy’

@libc = Fiddle.dlopen "/lib/libc.so.6"
   #=> #<Fiddle::Handle:0x00000001d7a8d8>
f = Fiddle::Function.new(
  @libc['strcpy'],
  [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP],
  Fiddle::TYPE_VOIDP)
   #=> #<Fiddle::Function:0x00000001d8ee00>
buff = "000"
   #=> "000"
str = f.call(buff, "123")
   #=> #<Fiddle::Pointer:0x00000001d0c380 ptr=0x000000018a21b8 size=0 free=0x00000000000000>
str.to_s
#=> "123"

ABI check

@libc = Fiddle.dlopen "/lib/libc.so.6"
   #=> #<Fiddle::Handle:0x00000001d7a8d8>
f = Fiddle::Function.new(@libc['strcpy'], [TYPE_VOIDP, TYPE_VOIDP], TYPE_VOIDP)
   #=> #<Fiddle::Function:0x00000001d8ee00>
f.abi == Fiddle::Function::DEFAULT
   #=> true

Constant Summary

Class Method Summary

Instance Attribute Summary

  • #abi readonly

    The ABI of the Function.

  • #name readonly

    The name of this function.

  • #need_gvl? ⇒ Boolean readonly

    Whether GVL is needed to call this function.

  • #ptr readonly

    The address of this function.

Instance Method Summary

Constructor Details

.new(ptr, args, return_type, abi = DEFAULT, kwargs = nil) ⇒ Function

[ GitHub ]

  
# File 'lib/fiddle/ffi_backend.rb', line 125

def initialize(ptr, args, return_type, abi = DEFAULT, kwargs = nil)
  if kwargs.nil?
    if abi.kind_of? Hash
      kwargs = abi
      abi = DEFAULT
    end
  end
  @name = kwargs[:name] if kwargs.kind_of? Hash
  @ptr, @args, @return_type, @abi = ptr, args, return_type, abi
  raise TypeError.new "invalid argument types" unless args.is_a?(Array)

  ffi_return_type = Fiddle::FFIBackend.to_ffi_type(@return_type)
  ffi_args = @args.map { |t| Fiddle::FFIBackend.to_ffi_type(t) }
  pointer = FFI::Pointer.new(ptr.to_i)
  options = {convention: @abi}
  if ffi_args.last == FFI::Type::Builtin::VARARGS
    @function = FFI::VariadicInvoker.new(
      pointer,
      ffi_args,
      ffi_return_type,
      options
    )
  else
    @function = FFI::Function.new(ffi_return_type, ffi_args, pointer, options)
  end
end

#initialize(object) ⇒ Pinned

Alias for Closure#initialize. Create a new pinned object reference. The Pinned instance will prevent the GC from moving object.

Instance Attribute Details

#abi (readonly)

The ABI of the Function.

[ GitHub ]

  
# File 'lib/fiddle/function.rb', line 5

attr_reader :abi

#name (readonly)

The name of this function

[ GitHub ]

  
# File 'lib/fiddle/function.rb', line 11

attr_reader :name

#need_gvl?Boolean (readonly)

Whether GVL is needed to call this function

[ GitHub ]

  
# File 'lib/fiddle/function.rb', line 14

def need_gvl?
  @need_gvl
end

#ptr (readonly)

The address of this function

[ GitHub ]

  
# File 'lib/fiddle/function.rb', line 8

attr_reader :ptr

Instance Method Details

#call(*args, &block)

[ GitHub ]

  
# File 'lib/fiddle/ffi_backend.rb', line 152

def call(*args, &block)
  if @function.is_a?(FFI::VariadicInvoker)
    n_fixed_args = @args.size - 1
    n_fixed_args.step(args.size - 1, 2) do |i|
      if args[i] == :const_string || args[i] == Types::CONST_STRING
        args[i + 1] = String.try_convert(args[i + 1]) || args[i + 1]
      end
      args[i] = Fiddle::FFIBackend.to_ffi_type(args[i])
    end
  else
    @args.each_with_index do |arg_type, i|
      next unless arg_type == Types::VOIDP

      src = args[i]
      next if src.nil?
      next if src.is_a?(String)
      next if src.is_a?(FFI::AbstractMemory)
      next if src.is_a?(FFI::Struct)

      args[i] = Pointer[src]
    end
  end
  result = @function.call(*args, &block)
  result = Pointer.new(result) if result.is_a?(FFI::Pointer)
  result
end

#to_i

The integer memory location of this function

[ GitHub ]

  
# File 'lib/fiddle/function.rb', line 19

def to_i
  ptr.to_i
end

#to_proc

Turn this function in to a proc

[ GitHub ]

  
# File 'lib/fiddle/function.rb', line 24

def to_proc
  this = self
  lambda { |*args| this.call(*args) }
end