mrb_value cfunc_type_class_get(mrb_state *mrb, mrb_value klass) { mrb_value pointer; mrb_get_args(mrb, "o", &pointer); struct mrb_ffi_type *mft = rclass_to_mrb_ffi_type(mrb, mrb_class_ptr(klass)); return mft->c_to_mrb(mrb, cfunc_pointer_ptr(pointer)); }
static void cfunc_pointer_mrb_to_c(mrb_state *mrb, mrb_value val, void *p) { if(mrb_nil_p(val)) { *(void**)p = NULL; } else { *(void**)p = cfunc_pointer_ptr(val); } }
mrb_value cfunc_type_class_set(mrb_state *mrb, mrb_value klass) { mrb_value pointer, val; mrb_get_args(mrb, "oo", &pointer, &val); struct mrb_ffi_type *mft = rclass_to_mrb_ffi_type(mrb, mrb_class_ptr(klass)); mft->mrb_to_c(mrb, val, cfunc_pointer_ptr(pointer)); return val; }
// sint64 specific mrb_value cfunc_sint64_class_get(mrb_state *mrb, mrb_value klass) { mrb_value pointer; mrb_get_args(mrb, "o", &pointer); int64_t sint64 = *(int64_t*)cfunc_pointer_ptr(pointer); if(sint64 > INT32_MAX || sint64 < INT32_MIN) { mrb_raise(mrb, E_TYPE_ERROR, "out of range. Use low, high"); } return int64_to_mrb(mrb, sint64); }
// uint64 specific mrb_value cfunc_uint64_class_get(mrb_state *mrb, mrb_value klass) { mrb_value pointer; mrb_get_args(mrb, "o", &pointer); uint64_t uint64 = *(uint64_t*)cfunc_pointer_ptr(pointer); if(uint64 > UINT32_MAX) { mrb_raise(mrb, E_TYPE_ERROR, "too big. Use low, high"); } return int64_to_mrb(mrb, uint64); }
static mrb_value cfunc_type_class_refer(mrb_state *mrb, mrb_value klass) { struct RClass *c = mrb_class_ptr(klass); struct cfunc_type_data *data = mrb_malloc(mrb, sizeof(struct cfunc_type_data)); data->autofree = false; mrb_value pointer; mrb_get_args(mrb, "o", &pointer); data->refer = true; data->value._pointer = cfunc_pointer_ptr(pointer); struct RObject *obj = (struct RObject *)Data_Wrap_Struct(mrb, c, &cfunc_type_data, data); mrb_obj_iv_set(mrb, obj, mrb_intern_cstr(mrb, "parent_pointer"), pointer); // keep for GC return mrb_obj_value(obj); }
mrb_value cfunc_pointer_initialize(mrb_state *mrb, mrb_value self) { struct cfunc_type_data *data; data = mrb_data_check_get_ptr(mrb, self, &cfunc_pointer_data_type); if(!data) { data = mrb_malloc(mrb, sizeof(struct cfunc_type_data)); DATA_PTR(self) = data; DATA_TYPE(self) = &cfunc_pointer_data_type; } data->refer = false; data->autofree = false; mrb_value ptr; int argc = mrb_get_args(mrb, "|o", &ptr); if(argc == 0) { set_cfunc_pointer_data(data, NULL); } else { set_cfunc_pointer_data(data, cfunc_pointer_ptr(ptr)); } return self; }
static mrb_value cfunc_call(mrb_state *mrb, mrb_value self) { int margc; mrb_value mresult_type, mname, *margs; void **values = NULL; ffi_type **args = NULL; mrb_get_args(mrb, "oo*", &mresult_type, &mname, &margs, &margc); void *fp = NULL; if(mrb_string_p(mname) || mrb_symbol_p(mname)) { void *dlh = dlopen(NULL, RTLD_LAZY); fp = dlsym(dlh, mrb_string_value_ptr(mrb, mname)); dlclose(dlh); } else { fp = cfunc_pointer_ptr(mname); } if(fp == NULL) { mrb_raisef(mrb, E_NAME_ERROR, "can't find C function %s", mrb_string_value_ptr(mrb, mname)); goto cfunc_call_exit; } args = malloc(sizeof(ffi_type*) * margc); values = malloc(sizeof(void*) * margc); mrb_sym sym_to_ffi_value = mrb_intern(mrb, "to_ffi_value"); mrb_value nil_ary[1]; nil_ary[0] = mrb_nil_value(); for(int i = 0; i < margc; ++i) { if(mrb_respond_to(mrb, margs[i], sym_to_ffi_value)) { args[i] = mrb_value_to_mrb_ffi_type(mrb, margs[i])->ffi_type_value; values[i] = cfunc_pointer_ptr(mrb_funcall_argv(mrb, margs[i], sym_to_ffi_value, 1, nil_ary)); } else { cfunc_mrb_raise_without_jump(mrb, E_TYPE_ERROR, "ignore argument type %s", mrb_obj_classname(mrb, margs[i])); goto cfunc_call_exit; } } ffi_type *result_type = rclass_to_mrb_ffi_type(mrb, mrb_class_ptr(mresult_type))->ffi_type_value; if (result_type == NULL) { cfunc_mrb_raise_without_jump(mrb, E_ARGUMENT_ERROR, "ignore return type %s", mrb_class_name(mrb, mrb_class_ptr(mresult_type))); goto cfunc_call_exit; } mrb_value mresult = mrb_nil_value(); ffi_cif cif; if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, margc, result_type, args) == FFI_OK) { void *result; if(result_type->size > sizeof(long)) { result = malloc(result_type->size); } else if(result_type->size) { result = malloc(sizeof(long)); } else { result = NULL; } ffi_call(&cif, fp, result, values); if(result) { mrb_value result_ptr = cfunc_pointer_new_with_pointer(mrb, result, true); mresult = mrb_funcall(mrb, mresult_type, "refer", 1, result_ptr); } } else { mrb_raisef(mrb, E_NAME_ERROR, "Can't find C function %s", mname); goto cfunc_call_exit; } cfunc_call_exit: free(values); free(args); return mresult; }
static void cfunc_closure_mrb_to_data(mrb_state *mrb, mrb_value val, struct cfunc_type_data *data) { set_cfunc_pointer_data(data, cfunc_pointer_ptr(val)); }
static void cfunc_closure_mrb_to_c(mrb_state *mrb, mrb_value val, void *p) { *(void**)p = cfunc_pointer_ptr(val); }