# class Fiddle::Closure

## 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

### Attributes

args[R]

arguments of the FFI closure

ctype[R]

the C type of the return of the FFI closure

### Public Class Methods

new(ret, args, abi = Fiddle::DEFAULT) click to toggle source

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.

    static VALUE
    initialize(int rbargc, VALUE argv[], VALUE self)
    {
        VALUE ret;
        VALUE args;
        VALUE normalized_args;
        VALUE abi;
        fiddle_closure * cl;
        ffi_cif * cif;
        ffi_closure *pcl;
        ffi_status result;
        int i, argc;

        if (2 == rb_scan_args(rbargc, argv, "21", &ret, &args, &abi))
            abi = INT2NUM(FFI_DEFAULT_ABI);

        Check_Type(args, T_ARRAY);

        argc = RARRAY_LENINT(args);

        TypedData_Get_Struct(self, fiddle_closure, &closure_data_type, cl);

        cl->argv = (ffi_type **)xcalloc(argc + 1, sizeof(ffi_type *));

        normalized_args = rb_ary_new_capa(argc);
        for (i = 0; i < argc; i++) {
            VALUE arg = rb_fiddle_type_ensure(RARRAY_AREF(args, i));
            rb_ary_push(normalized_args, arg);
            cl->argv[i] = rb_fiddle_int_to_ffi_type(NUM2INT(arg));
        }
        cl->argv[argc] = NULL;

        ret = rb_fiddle_type_ensure(ret);
        rb_iv_set(self, "@ctype", ret);
        rb_iv_set(self, "@args", normalized_args);

        cif = &cl->cif;
        pcl = cl->pcl;

        result = ffi_prep_cif(cif,
                              NUM2INT(abi),
                              argc,
                              rb_fiddle_int_to_ffi_type(NUM2INT(ret)),
                              cl->argv);

        if (FFI_OK != result)
            rb_raise(rb_eRuntimeError, "error prepping CIF %d", result);

    #if USE_FFI_CLOSURE_ALLOC
        result = ffi_prep_closure_loc(pcl, cif, callback,
                    (void *)self, cl->code);
    #else
        result = ffi_prep_closure(pcl, cif, callback, (void *)self);
        cl->code = (void *)pcl;
        i = mprotect(pcl, sizeof(*pcl), PROT_READ | PROT_EXEC);
        if (i) {
            rb_sys_fail("mprotect");
        }
    #endif

        if (FFI_OK != result)
            rb_raise(rb_eRuntimeError, "error prepping closure %d", result);

        return self;
    }

### Public Instance Methods

to_i() click to toggle source

Returns the memory address for this closure

    static VALUE
    to_i(VALUE self)
    {
        fiddle_closure * cl;
        void *code;

        TypedData_Get_Struct(self, fiddle_closure, &closure_data_type, cl);

        code = cl->code;

        return PTR2NUM(code);
    }