123456789_123456789_123456789_123456789_123456789_

Class: Fiddle::Closure

Relationships & Source Files
Namespace Children
Classes:
Extension / Inclusion / Inheritance Descendants
Subclasses:
Inherits: Object
Defined in: ext/fiddle/closure.c,
ext/fiddle/pinned.c,
ext/fiddle/lib/fiddle/closure.rb,
ext/fiddle/lib/fiddle/ffi_backend.rb

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

Class Method Summary

Instance Attribute Summary

  • #args readonly

    arguments of the FFI closure.

  • #ctype readonly

    the C type of the return of the FFI closure.

  • #freed? ⇒ Boolean readonly

    Whether this closure was freed explicitly.

Instance Method Summary

Constructor Details

.new(object) ⇒ Pinned

Alias for Pinned.new.

#initialize(ret, args, abi = Function::DEFAULT) ⇒ Closure

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle/ffi_backend.rb', line 180

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

Class Method Details

.create(*args)

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 .new. So using this method without block equals to .new.

Example

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

  
# File 'ext/fiddle/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 Attribute Details

#args (readonly)

arguments of the FFI closure

[ GitHub ]

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

attr_reader :args

#ctype (readonly)

the C type of the return of the FFI closure

[ GitHub ]

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

attr_reader :ctype

#freed?Boolean (readonly)

Whether this closure was freed explicitly.

[ GitHub ]

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

static VALUE
closure_freed_p(VALUE self)
{
    fiddle_closure *closure;
    TypedData_Get_Struct(self, fiddle_closure, &closure_data_type, closure);
    return closure ? RUBY_Qfalse : RUBY_Qtrue;
}

Instance Method Details

#free

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

If this closure is already freed, this does nothing.

[ GitHub ]

  
# File 'ext/fiddle/closure.c', line 369

static VALUE
closure_free(VALUE self)
{
    fiddle_closure *closure;
    TypedData_Get_Struct(self, fiddle_closure, &closure_data_type, closure);
    if (closure) {
        dealloc(closure);
        RTYPEDDATA_DATA(self) = NULL;
    }
    return RUBY_Qnil;
}

#to_i

Returns the memory address for this closure.

[ GitHub ]

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

static VALUE
to_i(VALUE self)
{
    fiddle_closure *closure = get_raw(self);
    return PTR2NUM(closure->code);
}

#to_ptr

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle/ffi_backend.rb', line 195

def to_ptr
  @function
end