Skip to content

Commit c530f6e

Browse files
committed
Add base for supporting callbacks in node port. Refactor of many functionality from reflect function and signature in order to support it, this should not be done in this way, the correct way should be moving all ports to the loaders and merge both with the proper abstraction. Exposing metacall internals should not be the way to go. Meanwhile with this patch we can have callbacks temporally until we solve these design errors.
1 parent 91ccb09 commit c530f6e

File tree

19 files changed

+323
-28
lines changed

19 files changed

+323
-28
lines changed

source/loader/include/loader/loader.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ struct loader_type;
4646

4747
/* -- Type Definitions -- */
4848

49-
typedef value (*loader_register_invoke)(void * []);
49+
typedef value (*loader_register_invoke)(size_t, void * [], void *);
5050

5151
typedef void * loader_data;
5252

source/loader/source/loader.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,13 @@ function_return loader_register_invoke_proxy(function func, function_impl func_i
161161
{
162162
loader_host_invoke host_invoke = (loader_host_invoke)func_impl;
163163

164-
(void)func;
164+
signature s = function_signature(func);
165+
166+
const size_t args_size = signature_count(s);
167+
168+
void * data = function_closure(func);
165169

166-
return host_invoke->invoke(args);
170+
return host_invoke->invoke(args_size, args, data);
167171
}
168172

169173
function_return loader_register_await_proxy(function func, function_impl impl, function_args args, function_resolve_callback resolve_callback, function_reject_callback reject_callback, void * context)

source/loaders/py_loader/source/py_loader_impl.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -791,7 +791,7 @@ static PyObject * py_loader_impl_function_type_invoke(PyObject * self, PyObject
791791

792792
if (args_size != (size_t)callee_args_size)
793793
{
794-
log_write("metacall", LOG_LEVEL_WARNING, "Callback being executed without different number of arguments %ul != %ul", args_size, callee_args_size);
794+
log_write("metacall", LOG_LEVEL_WARNING, "Callback being executed without different number of arguments %u != %u", args_size, callee_args_size);
795795
}
796796

797797
value_args = malloc(sizeof(void *) * min_args_size);

source/metacall/include/metacall/metacall.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,21 @@ METACALL_API void * metacall_function(const char * name);
327327
*/
328328
METACALL_API size_t metacall_function_size(void * func);
329329

330+
/**
331+
* @brief
332+
* Resize the mumber of arguments accepted by function @func
333+
*
334+
* @param[in] func
335+
* Function reference
336+
*
337+
* @param[in] count
338+
* Number of arguments that the function will accept
339+
*
340+
* @return
341+
* Zero if function could be resized, different from zero otherwise
342+
*/
343+
METACALL_API int metacall_function_resize(void * func, size_t count);
344+
330345
/**
331346
* @brief
332347
* Get the handle by @name
@@ -461,7 +476,7 @@ METACALL_API void * metacallfms(void * func, const char * buffer, size_t size, v
461476
* Name of the function
462477
*
463478
* @param[in] invoke
464-
* Pointer to function invoke interface
479+
* Pointer to function invoke interface (argc, argv, data)
465480
*
466481
* @param[in] return_type
467482
* Type of return value
@@ -475,7 +490,7 @@ METACALL_API void * metacallfms(void * func, const char * buffer, size_t size, v
475490
* @return
476491
* Pointer to value containing the result of the call
477492
*/
478-
METACALL_API int metacall_register(const char * name, void * (*invoke)(void *[]), enum metacall_value_id return_type, size_t size, ...);
493+
METACALL_API int metacall_register(const char * name, void * (*invoke)(size_t, void * [], void *), enum metacall_value_id return_type, size_t size, ...);
479494

480495
/**
481496
* @brief

source/metacall/include/metacall/metacall_value.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,21 @@ METACALL_API void * metacall_value_create_future(void * f);
245245
*/
246246
METACALL_API void * metacall_value_create_function(void * f);
247247

248+
/**
249+
* @brief
250+
* Create a value from function @f binding a closure @c to it
251+
*
252+
* @param[in] f
253+
* Pointer to constant data will be copied into value
254+
*
255+
* @param[in] c
256+
* Pointer to closure that will be binded into function @f
257+
*
258+
* @return
259+
* Pointer to value if success, null otherwhise
260+
*/
261+
METACALL_API void * metacall_value_create_function_closure(void * f, void * c);
262+
248263
/**
249264
* @brief
250265
* Create a value of type null

source/metacall/source/metacall.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,18 @@ size_t metacall_function_size(void * func)
475475
return 0;
476476
}
477477

478+
int metacall_function_resize(void * func, size_t count)
479+
{
480+
function f = (function)func;
481+
482+
if (f == NULL)
483+
{
484+
return 1;
485+
}
486+
487+
return function_resize(f, count);
488+
}
489+
478490
void * metacall_handle(const char * tag, const char * name)
479491
{
480492
return (void *)loader_get_handle(tag, name);
@@ -962,7 +974,7 @@ void * metacallfms(void * func, const char * buffer, size_t size, void * allocat
962974
return NULL;
963975
}
964976

965-
int metacall_register(const char * name, void * (*invoke)(void * []), enum metacall_value_id return_type, size_t size, ...)
977+
int metacall_register(const char * name, void * (*invoke)(size_t, void * [], void *), enum metacall_value_id return_type, size_t size, ...)
966978
{
967979
type_id types[METACALL_ARGS_SIZE];
968980

source/metacall/source/metacall_value.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,11 @@ void * metacall_value_create_function(void * f)
147147
return value_create_function(f);
148148
}
149149

150+
void * metacall_value_create_function_closure(void * f, void * c)
151+
{
152+
return value_create_function_closure(f, c);
153+
}
154+
150155
void * metacall_value_create_null()
151156
{
152157
return value_create_null();

source/ports/node_port/source/node_port.cpp

Lines changed: 127 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,69 @@
4040

4141
static inline void metacall_node_exception(napi_env env, napi_status status);
4242

43-
static void * metacall_node_napi_to_value(/* loader_impl_node node_impl,*/ napi_env env, napi_value v);
43+
static void * metacall_node_napi_to_value(/* loader_impl_node node_impl,*/ napi_env env, napi_value recv, napi_value v);
4444

4545
static napi_value metacall_node_value_to_napi(/* loader_impl_node node_impl,*/ napi_env env, void * arg);
4646

47+
static void * metacall_node_callback(size_t argc, void * args[], void * data);
48+
49+
typedef struct metacall_node_callback_closure_type
50+
{
51+
napi_env env;
52+
napi_value callback;
53+
napi_value recv;
54+
55+
} * metacall_node_callback_closure;
56+
4757
/* -- Methods -- */
4858

59+
/* BEGIN-TODO: (Maybe) Implement this in the loader, then remove it from here */
60+
61+
void * metacall_node_callback(size_t argc, void * args[], void * data)
62+
{
63+
metacall_node_callback_closure closure = static_cast<metacall_node_callback_closure>(data);
64+
napi_value ret;
65+
napi_status status;
66+
napi_value * argv = NULL;
67+
68+
if (closure == NULL)
69+
{
70+
return NULL;
71+
}
72+
73+
if (argc > 0)
74+
{
75+
argv = static_cast<napi_value *>(malloc(sizeof(napi_value *) * argc));
76+
77+
if (argv == NULL)
78+
{
79+
free(closure);
80+
return NULL;
81+
}
82+
83+
for (uint32_t args_count = 0; args_count < argc; ++args_count)
84+
{
85+
argv[args_count] = metacall_node_value_to_napi(closure->env, args[args_count]);
86+
}
87+
}
88+
89+
status = napi_call_function(closure->env, closure->recv, closure->callback, argc, argv, &ret);
90+
91+
metacall_node_exception(closure->env, status);
92+
93+
free(closure);
94+
95+
if (argv != NULL)
96+
{
97+
free(argv);
98+
}
99+
100+
/*return metacall_node_napi_to_value(closure->env, closure->recv, ret);*/
101+
return NULL;
102+
}
103+
104+
/* END-TODO */
105+
49106
/* BEGIN-TODO: Remove this, it is duplicated code copied from node loader */
50107

51108
inline void metacall_node_exception(napi_env env, napi_status status)
@@ -132,7 +189,7 @@ inline void metacall_node_exception(napi_env env, napi_status status)
132189
}
133190
}
134191

135-
void * metacall_node_napi_to_value(/*loader_impl_node node_impl,*/ napi_env env, napi_value v)
192+
void * metacall_node_napi_to_value(/*loader_impl_node node_impl,*/ napi_env env, napi_value recv, napi_value v)
136193
{
137194
void * ret = NULL;
138195

@@ -220,7 +277,7 @@ void * metacall_node_napi_to_value(/*loader_impl_node node_impl,*/ napi_env env,
220277
metacall_node_exception(env, status);
221278

222279
/* TODO: Review recursion overflow */
223-
array_value[iterator] = metacall_node_napi_to_value(/*node_impl,*/ env, element);
280+
array_value[iterator] = metacall_node_napi_to_value(/*node_impl,*/ env, recv, element);
224281
}
225282
}
226283
else if (napi_is_buffer(env, v, &result) == napi_ok && result == true)
@@ -340,15 +397,36 @@ void * metacall_node_napi_to_value(/*loader_impl_node node_impl,*/ napi_env env,
340397
metacall_node_exception(env, status);
341398

342399
/* TODO: Review recursion overflow */
343-
tupla[1] = metacall_node_napi_to_value(/* node_impl,*/ env, element);
400+
tupla[1] = metacall_node_napi_to_value(/* node_impl,*/ env, recv, element);
344401
}
345402
}
346403

347404
}
348405
}
349406
else if (valuetype == napi_function)
350407
{
351-
/* TODO */
408+
void * f = metacall_function("__metacall_node_callback__");
409+
metacall_node_callback_closure closure = static_cast<metacall_node_callback_closure>(malloc(sizeof(struct metacall_node_callback_closure_type)));
410+
napi_value length;
411+
uint32_t argc;
412+
413+
closure->env = env;
414+
closure->callback = v;
415+
closure->recv = recv;
416+
417+
// Get number of arguments to the callback (this workaround should be reviewed)
418+
status = napi_get_named_property(env, v, "length", &length);
419+
420+
metacall_node_exception(env, status);
421+
422+
status = napi_get_value_uint32(env, length, &argc);
423+
424+
metacall_node_exception(env, status);
425+
426+
// Workaround for accepting variable arguments
427+
metacall_function_resize(f, (size_t)argc);
428+
429+
return metacall_value_create_function_closure(f, (void *)closure);
352430
}
353431
else if (valuetype == napi_external)
354432
{
@@ -503,6 +581,18 @@ napi_value metacall_node_value_to_napi(/* loader_impl_node node_impl,*/ napi_env
503581
{
504582
/* TODO: Implement promise properly for await */
505583
}
584+
else if (id == METACALL_FUNCTION)
585+
{
586+
/* TODO: Implement function to pass callbacks through the callback again */
587+
/*
588+
void * f = metacall_value_to_function(arg_value);
589+
590+
// TODO:
591+
status = napi_create_double(env, double_value, &v);
592+
593+
metacall_node_exception(env, status);
594+
*/
595+
}
506596
else
507597
{
508598
status = napi_get_undefined(env, &v);
@@ -519,22 +609,37 @@ napi_value metacall_node_value_to_napi(/* loader_impl_node node_impl,*/ napi_env
519609
napi_value metacall_node_call(napi_env env, napi_callback_info info)
520610
{
521611
size_t argc = 0;
612+
522613
napi_get_cb_info(env, info, &argc, NULL, NULL, NULL);
614+
523615
napi_value argv[argc];
524-
void *metacallArgs[argc - 1];
525-
napi_get_cb_info(env, info, &argc, argv, NULL, NULL);
526-
char functionName[FUNCTION_NAME_LENGTH];
527-
size_t writeNumber;
528-
napi_get_value_string_utf8(env, argv[0], functionName, FUNCTION_NAME_LENGTH, &writeNumber);
616+
void * args[argc - 1];
617+
napi_value recv;
618+
619+
napi_get_cb_info(env, info, &argc, argv, &recv, NULL);
620+
621+
char name[FUNCTION_NAME_LENGTH];
622+
size_t name_length;
623+
624+
napi_get_value_string_utf8(env, argv[0], name, FUNCTION_NAME_LENGTH, &name_length);
625+
529626
for (size_t i = 1; i < argc; i++)
530627
{
531-
metacallArgs[i - 1] = metacall_node_napi_to_value(env, argv[i]);
628+
args[i - 1] = metacall_node_napi_to_value(env, recv, argv[i]);
629+
}
630+
631+
void * ret = metacallv(name, args);
632+
633+
for (size_t args_count = 0; args_count < argc - 1; ++args_count)
634+
{
635+
metacall_value_destroy(args[args_count]);
532636
}
533637

534-
// Phew!!!.... after we are done converting JS types to Metacall Type into a single Array Above
535-
void * ptr = metacallv(functionName, metacallArgs);
638+
napi_value result = metacall_node_value_to_napi(env, ret);
536639

537-
return metacall_node_value_to_napi(env, ptr);
640+
metacall_value_destroy(ret);
641+
642+
return result;
538643
}
539644

540645
// this function is the handler of the "metacall_load_from_file"
@@ -732,6 +837,14 @@ napi_value metacall_node_initialize(napi_env env, napi_value exports)
732837
return NULL;
733838
}
734839

840+
if (metacall_register("__metacall_node_callback__", metacall_node_callback, METACALL_INVALID, 0) != 0)
841+
{
842+
/* TODO: Show error message (when error handling is properly implemented in the core lib) */
843+
napi_throw_error(env, NULL, "MetaCall failed to initialize callback support");
844+
845+
return NULL;
846+
}
847+
735848
metacall_node_exports(env, exports);
736849

737850
return exports;

source/ports/node_port/test/index.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,17 @@ describe('metacall', () => {
106106
assert.strictEqual(metacall('get_second', 5, 12), 12);
107107
});
108108
});
109+
110+
describe('callback', () => {
111+
it('callback (py)', () => {
112+
const f = require('function.py');
113+
const c = 5;
114+
assert.notStrictEqual(f, undefined);
115+
assert.strictEqual(f.function_with_args((a, b) => {
116+
const result = a + b + c;
117+
console.log(`${a} + ${b} + ${c} = ${result}`);
118+
return result;
119+
}, 2, 3), 10);
120+
});
121+
});
109122
});

source/reflect/include/reflect/reflect_function.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,17 @@ typedef struct function_interface_type
6262
typedef function_interface (*function_impl_interface_singleton)(void);
6363

6464
REFLECT_API function function_create(const char * name, size_t args_count, function_impl impl, function_impl_interface_singleton singleton);
65+
66+
REFLECT_API int function_resize(function func, size_t count);
6567

6668
REFLECT_API int function_increment_reference(function func);
6769

6870
REFLECT_API int function_decrement_reference(function func);
6971

72+
REFLECT_API void function_bind(function func, void * data);
73+
74+
REFLECT_API void * function_closure(function func);
75+
7076
REFLECT_API const char * function_name(function func);
7177

7278
REFLECT_API signature function_signature(function func);

0 commit comments

Comments
 (0)