Open deltaluca opened 10 years ago
Well... this works! (and no warnings from gcc about my code in particular)
extern class CCallback
{
@:native("c_callback") public static function _(wrapper:Int->Pointer<Void>->Void, x:Int, closure:Int->Void):Void;
}
@:headerCode("
#ifndef MAIN_HEADER_CODE
#define MAIN_HEADER_CODE
static inline void c_callback(void (*f)(int,void*), int x, void* userData) {
f(x, userData);
}
#endif
")
class Main
{
static function c_callback_wrapper(x:Int, cb:Pointer<Void>) untyped (cb : Int->Void)(x);
public function new() {}
static function staticCallback(x:Int) trace(x);
public function memberCallback(x:Int) trace(x);
static function main()
{
var self = new Main();
CCallback._(c_callback_wrapper, 1, function (x:Int) staticCallback(x));
CCallback._(c_callback_wrapper, 2, function (x:Int) self.memberCallback(x));
CCallback._(c_callback_wrapper, 3, function (x:Int) trace(x)); // obviously will work given the above, but still this is the last case of using a closure to c function.
generated code like:
#include "Main.h"
#include "Array.h"
#include "Dynamic.h"
#include "hxc.h"
#include "c/Closure.h"
#include "c/TypeReference.h"
#include "c/VTable.h"
#include "c/_hx_anon_5.h"
#include "c/_hx_anon_6.h"
const c_TypeReference Main__hx_typeref = {
"Main",
NULL,
sizeof(Main),
Main_new,
Main__hx_alloc,
NULL
};
void Main_memberCallback(Main* this,int x){
printf("%s:%d: %d\n","Main.hx",23,x);
}
Array* Main__hx_func_8(Main* v0){
Array* arr;
arr = Array___new_64(1);
Array___set_64(arr,0,((hx_int64) (v0)));
return arr;
}
void Main__hx_func_7(c__hx_anon_5* _hx_ctx,int x){
printf("%s:%d: %d\n","Main.hx",31,x);
}
void Main__hx_func_6(c__hx_anon_6* _hx_ctx,int x){
Main_memberCallback(((Main*) (Array___get_64(((Array*) ((_hx_ctx)->self)),0))),x);
}
void Main__hx_func_5(c__hx_anon_5* _hx_ctx,int x){
Main_staticCallback(x);
}
Main* Main__hx_alloc(){
Main* this = calloc(1,sizeof(Main));
return this;
}
void Main__hx_initInstance(Main* this){ }
void Main_c_callback_wrapper(int x,void *cb){
if((((c_Closure*) (cb)))->_this != NULL){
((void (*)(void*,int)) ((((c_Closure*) (cb)))->_func))((((c_Closure*) (cb)))->_this,x);
} else {
((void (*)(int)) ((((c_Closure*) (cb)))->_func))(x);
}
}
void Main_staticCallback(int x){
printf("%s:%d: %d\n","Main.hx",22,x);
}
void Main_main(){
Array* self;c_Closure* _g;c_Closure* _g1;c_Closure* _g2;
self = Main__hx_func_8(Main_new());
_g = c_Closure_new(((void* (*)()) (Main__hx_func_5)),new_c__hx_anon_5());
c_callback(Main_c_callback_wrapper,1,_g);
_g1 = c_Closure_new(((void* (*)()) (Main__hx_func_6)),new_c__hx_anon_6(self));
c_callback(Main_c_callback_wrapper,2,_g1);
_g2 = c_Closure_new(((void* (*)()) (Main__hx_func_7)),new_c__hx_anon_5());
c_callback(Main_c_callback_wrapper,3,_g2);
}
Main* Main_new(){
Main* this = Main__hx_alloc();
Main__hx_initInstance(this);
return this;
}
void Main__hx_init(){
hxc_registerType(&Main__hx_typeref);
}
Ignoring compatibility with C libs taking callbacks and 'not' exposing a userData field for context forwarding...
Eg:
as a typical pattern of C libs (not necessarigly always sadly)
Currently we compile functions in one of 3 ways. If it's member we have the implicit Self* arg, if it's a closure we have the implicit _hx_ctx pointer arg, and static functions are compiled with no additional implicit arg as we don't have any context to forward presently.
We can have automatic interfacing with such C functions, aka in the case of calling such a c function with a member function we can generate code (in the general case where argument order might not match as is the case here)
And similarly for closure function arguments and static function arguments.
Obviously, this can not ever work if someone tries to call the C binding with a Dynamic value since we need to generate the wrapper function, and ontop of that need to know what sort of function is being passed to C to generate an appropriate wrapper.
Struggling however, to come up with a good method of signifying what Haxe function argument has to be tranformed, and how the extra arguments need to be arranged in the generated code, since it's not guaranteed (like with my example) that the userData argument will be in any specific position relative to the function argument, and that the function would be expected to receive the userData forwarded in any specific argument...
aka the c function could be any one of