Class: Fiddle::Closure

Inherits:
Object
  • Object
show all
Defined in:
ext/fiddle/closure.c,
lib/fiddle/closure.rb,
lib/fiddle/ffi_backend.rb,
ext/fiddle/closure.c

Overview

Description

An FFI closure wrapper, for handling callbacks.

Example

closure = Class.new(Fiddle::Closure) {
  def call
    10
  end
}.new(Fiddle::TYPE_INT, [])
  #=> #<#<Class:0x0000000150d308>:0x0000000150d240>
func = Fiddle::Function.new(closure, [], Fiddle::TYPE_INT)
  #=> #<Fiddle::Function:0x00000001516e58>
func.call
  #=> 10

Direct Known Subclasses

BlockCaller

Defined Under Namespace

Classes: BlockCaller

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Object

call-seq: new(ret, args, abi = Fiddle::DEFAULT)

Construct a new Closure object.

  • ret is the C type to be returned

  • args is an Array of arguments, passed to the callback function

  • abi is the abi of the closure

If there is an error in preparing the ffi_cif or ffi_prep_closure, then a RuntimeError will be raised.



351
352
353
354
355
356
357
358
359
360
361
362
363
364
# File 'ext/fiddle/closure.c', line 351

def initialize(ret, args, abi = Function::DEFAULT)
  raise TypeError.new "invalid argument types" unless args.is_a?(Array)

  @ctype, @args = ret, args
  ffi_args = @args.map { |t| Fiddle::FFIBackend.to_ffi_type(t) }
  if ffi_args.size == 1 && ffi_args[0] == FFI::Type::Builtin::VOID
    ffi_args = []
  end
  return_type = Fiddle::FFIBackend.to_ffi_type(@ctype)
  raise "#{self.class} must implement #call" unless respond_to?(:call)
  callable = method(:call)
  @function = FFI::Function.new(return_type, ffi_args, callable, convention: abi)
  @freed = false
end

Instance Attribute Details

#argsObject (readonly)

arguments of the FFI closure



34
35
36
# File 'lib/fiddle/closure.rb', line 34

def args
  @args
end

#ctypeObject (readonly)

the C type of the return of the FFI closure



31
32
33
# File 'lib/fiddle/closure.rb', line 31

def ctype
  @ctype
end

Class Method Details

.create(*args) ⇒ Object

Create a new closure. If a block is given, the created closure is automatically freed after the given block is executed.

The all given arguments are passed to Fiddle::Closure.new. So using this method without block equals to Fiddle::Closure.new.

Example

Fiddle::Closure.create(TYPE_INT, [TYPE_INT]) do |closure|
  # closure is freed automatically when this block is finished.
end


16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/fiddle/closure.rb', line 16

def create(*args)
  if block_given?
    closure = new(*args)
    begin
      yield(closure)
    ensure
      closure.free
    end
  else
    new(*args)
  end
end

Instance Method Details

#freeObject

Free this closure explicitly. You can’t use this closure anymore.

If this closure is already freed, this does nothing.



369
370
371
372
373
# File 'ext/fiddle/closure.c', line 369

def free
  return if @freed
  @function.free
  @freed = true
end

#freed?Boolean

Whether this closure was freed explicitly.

Returns:

  • (Boolean)


381
382
383
# File 'ext/fiddle/closure.c', line 381

def freed?
  @freed
end

#to_iObject

Returns the memory address for this closure.



362
363
364
# File 'ext/fiddle/closure.c', line 362

def to_i
  @function.to_i
end

#to_ptrObject



196
197
198
# File 'lib/fiddle/ffi_backend.rb', line 196

def to_ptr
  @function
end