Skip to content

Commit e3f98a3

Browse files
committed
Add references.
1 parent 92bcaa3 commit e3f98a3

File tree

5 files changed

+264
-5
lines changed

5 files changed

+264
-5
lines changed

source/loaders/node_loader/source/node_loader_port.cpp

Lines changed: 172 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,12 @@
3434
#include <cstdlib>
3535
#include <cstring>
3636

37+
#include <set>
38+
3739
#include <node_api.h>
3840

3941
static const loader_tag node_loader_tag = "node";
42+
static std::set<value> metacall_value_reference_pointers;
4043

4144
napi_value node_loader_port_metacall(napi_env env, napi_callback_info info)
4245
{
@@ -1044,7 +1047,6 @@ napi_value node_loader_port_metacall_inspect(napi_env env, napi_callback_info)
10441047
return result;
10451048
}
10461049

1047-
/* TODO: Add documentation */
10481050
napi_value node_loader_port_metacall_logs(napi_env env, napi_callback_info)
10491051
{
10501052
struct metacall_log_stdio_type log_stdio = { stdout };
@@ -1057,6 +1059,172 @@ napi_value node_loader_port_metacall_logs(napi_env env, napi_callback_info)
10571059
return nullptr;
10581060
}
10591061

1062+
/* TODO: Add documentation */
1063+
napi_value node_loader_port_metacall_value_create_ptr(napi_env env, napi_callback_info info)
1064+
{
1065+
const size_t args_size = 1;
1066+
size_t argc = args_size;
1067+
napi_value argv[args_size];
1068+
void *v;
1069+
1070+
// Get arguments
1071+
napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
1072+
1073+
node_loader_impl_exception(env, status);
1074+
1075+
if (argc == 0)
1076+
{
1077+
v = NULL;
1078+
}
1079+
else if (argc == 1)
1080+
{
1081+
napi_valuetype arg_type;
1082+
1083+
status = napi_typeof(env, argv[0], &arg_type);
1084+
1085+
node_loader_impl_exception(env, status);
1086+
1087+
if (arg_type == napi_undefined)
1088+
{
1089+
v = NULL;
1090+
}
1091+
else if (arg_type == napi_external)
1092+
{
1093+
// Copy the external pointer
1094+
status = napi_get_value_external(env, argv[0], &v);
1095+
1096+
node_loader_impl_exception(env, status);
1097+
}
1098+
else
1099+
{
1100+
napi_throw_type_error(env, nullptr, "Invalid MetaCall value create pointer, you need to pass undefined or external as a parameter");
1101+
}
1102+
}
1103+
else
1104+
{
1105+
napi_throw_error(env, nullptr, "Invalid MetaCall value create pointer, you need to pass 0 or 1 parameters");
1106+
}
1107+
1108+
napi_value result_external;
1109+
1110+
status = napi_create_external(env, &v, NULL, NULL, &result_external);
1111+
1112+
node_loader_impl_exception(env, status);
1113+
1114+
return result_external;
1115+
}
1116+
1117+
static void metacall_value_reference_finalize(napi_env env, void *finalize_data, void *finalize_hint)
1118+
{
1119+
value v = finalize_data;
1120+
(void)env;
1121+
(void)finalize_hint;
1122+
metacall_value_destroy(v);
1123+
metacall_value_reference_pointers.erase(v);
1124+
}
1125+
1126+
/* TODO: Add documentation */
1127+
napi_value node_loader_port_metacall_value_reference(napi_env env, napi_callback_info info)
1128+
{
1129+
const size_t args_size = 1;
1130+
size_t argc = args_size;
1131+
napi_value recv;
1132+
napi_value argv[args_size];
1133+
value v;
1134+
1135+
// Get arguments
1136+
napi_status status = napi_get_cb_info(env, info, &argc, argv, &recv, nullptr);
1137+
1138+
node_loader_impl_exception(env, status);
1139+
1140+
if (argc != 1)
1141+
{
1142+
napi_throw_type_error(env, NULL, "Invalid number of arguments, use it like: metacall_value_reference(obj);");
1143+
return nullptr;
1144+
}
1145+
1146+
/* Obtain NodeJS loader implementation */
1147+
loader_impl impl = loader_get_impl(node_loader_tag);
1148+
loader_impl_node node_impl = (loader_impl_node)loader_impl_get(impl);
1149+
1150+
/* Store current reference of the environment */
1151+
node_loader_impl_env(node_impl, env);
1152+
1153+
v = node_loader_impl_napi_to_value(node_impl, env, recv, argv[0]);
1154+
1155+
if (v == NULL)
1156+
{
1157+
napi_throw_error(env, NULL, "Failed to convert the JavaScript object to MetaCall value.");
1158+
return nullptr;
1159+
}
1160+
1161+
napi_value result_external;
1162+
1163+
status = napi_create_external(env, v, &metacall_value_reference_finalize, nullptr, &result_external);
1164+
1165+
node_loader_impl_exception(env, status);
1166+
1167+
metacall_value_reference_pointers.insert(v);
1168+
1169+
return result_external;
1170+
}
1171+
1172+
/* TODO: Add documentation */
1173+
napi_value node_loader_port_metacall_value_dereference(napi_env env, napi_callback_info info)
1174+
{
1175+
const size_t args_size = 1;
1176+
size_t argc = args_size;
1177+
napi_value recv;
1178+
napi_value argv[args_size];
1179+
value v;
1180+
1181+
// Get arguments
1182+
napi_status status = napi_get_cb_info(env, info, &argc, argv, &recv, nullptr);
1183+
1184+
node_loader_impl_exception(env, status);
1185+
1186+
if (argc != 1)
1187+
{
1188+
napi_throw_type_error(env, NULL, "Invalid number of arguments, use it like: metacall_value_dereference(ptr);");
1189+
return nullptr;
1190+
}
1191+
1192+
napi_valuetype type;
1193+
1194+
status = napi_typeof(env, argv[0], &type);
1195+
node_loader_impl_exception(env, status);
1196+
1197+
if (type != napi_external)
1198+
{
1199+
napi_throw_type_error(env, NULL, "Invalid parameter type in first argument must be a PyCapsule (i.e a previously allocated pointer)");
1200+
return NULL;
1201+
}
1202+
1203+
// Get the external pointer
1204+
status = napi_get_value_external(env, argv[0], &v);
1205+
1206+
node_loader_impl_exception(env, status);
1207+
1208+
// If it is not contained in the set, it is not a valid value
1209+
if (metacall_value_reference_pointers.find(v) == metacall_value_reference_pointers.end())
1210+
{
1211+
napi_throw_type_error(env, NULL, "Invalid reference, argument must be a PyCapsule containing a MetaCall value, use it only with values returned by metacall_value_reference");
1212+
return NULL;
1213+
}
1214+
1215+
/* Obtain NodeJS loader implementation */
1216+
loader_impl impl = loader_get_impl(node_loader_tag);
1217+
loader_impl_node node_impl = (loader_impl_node)loader_impl_get(impl);
1218+
1219+
/* Store current reference of the environment */
1220+
node_loader_impl_env(node_impl, env);
1221+
1222+
/* Get the N-API value */
1223+
napi_value result = node_loader_impl_value_to_napi(node_impl, env, v);
1224+
1225+
return result;
1226+
}
1227+
10601228
napi_value node_loader_port_register_bootstrap_startup(napi_env env, napi_callback_info)
10611229
{
10621230
/* Obtain NodeJS loader implementation */
@@ -1097,6 +1265,9 @@ void node_loader_port_exports(napi_env env, napi_value exports)
10971265
x(metacall_load_from_configuration); \
10981266
x(metacall_load_from_configuration_export); \
10991267
x(metacall_inspect); \
1268+
x(metacall_value_create_ptr); \
1269+
x(metacall_value_reference); \
1270+
x(metacall_value_dereference); \
11001271
x(metacall_logs); \
11011272
x(register_bootstrap_startup);
11021273

source/loaders/py_loader/source/py_loader_port.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -846,7 +846,7 @@ static PyObject *py_loader_port_value_dereference(PyObject *self, PyObject *args
846846

847847
if (name != py_loader_capsule_reference_id)
848848
{
849-
PyErr_SetString(PyExc_TypeErrorPtr(), "Invalid reference, argument must be a PyCapsule from MetaCall");
849+
PyErr_SetString(PyExc_TypeErrorPtr(), "Invalid reference, argument must be a PyCapsule containing a MetaCall value, use it only with values returned by metacall_value_reference");
850850
return Py_ReturnNone();
851851
}
852852

source/ports/node_port/index.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,21 @@ const metacall_inspect = () => {
300300
return {};
301301
};
302302

303+
/* Value API for handling pointers */
304+
const metacall_value_create_ptr = (ptr) => {
305+
return addon.metacall_value_create_ptr(ptr);
306+
};
307+
308+
/* Value API for getting the pointer to a value */
309+
const metacall_value_reference = (v) => {
310+
return addon.metacall_value_reference(v);
311+
};
312+
313+
/* Value API for getting the value of a pointer */
314+
const metacall_value_dereference = (ptr) => {
315+
return addon.metacall_value_dereference(ptr);
316+
};
317+
303318
const metacall_handle = (tag, name) => {
304319
// TODO: This can be implemented with metacall_handle C API, meanwhile we use this trick
305320
const inspect = metacall_inspect();
@@ -337,6 +352,9 @@ const module_exports = {
337352
metacall_load_from_configuration,
338353
metacall_load_from_configuration_export,
339354
metacall_handle,
355+
metacall_value_create_ptr,
356+
metacall_value_reference,
357+
metacall_value_dereference,
340358

341359
/* TODO: Remove this from user or provide better ways of configuring logs */
342360
metacall_logs: () => {

source/scripts/c/compiled/source/compiled.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,14 @@ void alloc_data_args(data_ptr_t *ptr)
5151
printf("alloc_data_args ref %p\n", ptr);
5252
}
5353

54+
int compare_data_value(data_ptr_t left, data_ptr_t right)
55+
{
56+
printf("left %p\n", left);
57+
printf("right %p\n", right);
58+
assert(left == right);
59+
return left == right;
60+
}
61+
5462
void set_data_value(data_ptr_t ptr, int value)
5563
{
5664
printf("set_data_value %p\n", ptr);
@@ -68,3 +76,23 @@ void free_data(data_ptr_t ptr)
6876
printf("free_data %p\n", ptr);
6977
free(ptr);
7078
}
79+
80+
// TODO: When calling from NodeJS it does not work,
81+
// NodeJS emmits double as a call, and this expects long, it needs a casting
82+
/*
83+
void modify_int_ptr(long *l)
84+
{
85+
printf("l %p\n", l);
86+
printf("value %d\n", *l);
87+
assert(*l == 324444L);
88+
*l = 111L;
89+
}
90+
*/
91+
92+
void modify_int_ptr(double *d)
93+
{
94+
printf("d %p\n", d);
95+
printf("value %f\n", *d);
96+
assert(*d == 324444.0);
97+
*d = 111.0;
98+
}

source/tests/metacall_node_port_c_test/source/metacall_node_port_c_test.cpp

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ TEST_F(metacall_node_port_c_test, DefaultConstructor)
3737

3838
static const char buffer[] =
3939
"const assert = require('assert');\n"
40-
"const { metacall_load_from_file_export } = require('" METACALL_NODE_PORT_PATH "');\n"
41-
"const { return_text, process_text, alloc_data, alloc_data_args, set_data_value, get_data_value, free_data } = metacall_load_from_file_export('c', ['compiled.c']);\n"
40+
"const { metacall_load_from_file_export, metacall_value_create_ptr, metacall_value_reference, metacall_value_dereference } = require('" METACALL_NODE_PORT_PATH "');\n"
41+
"const { return_text, process_text, modify_int_ptr, compare_data_value, alloc_data, alloc_data_args, set_data_value, get_data_value, free_data } = metacall_load_from_file_export('c', ['compiled.c']);\n"
4242
// Test strings
4343
"const result = return_text();\n"
4444
"console.log(`'${result}'`);\n"
@@ -51,7 +51,49 @@ TEST_F(metacall_node_port_c_test, DefaultConstructor)
5151
"set_data_value(data_ptr, 12);\n"
5252
"assert(get_data_value(data_ptr) == 12);\n"
5353
"free_data(data_ptr);\n"
54-
// TODO: Implement passing reference by arguments (alloc_data_args)
54+
// Test passing reference by arguments
55+
"int_val = 324444;\n"
56+
"int_val_ref = metacall_value_reference(int_val);\n"
57+
"modify_int_ptr(int_val_ref);\n"
58+
"int_val_deref = metacall_value_dereference(int_val_ref);\n"
59+
"assert(int_val_deref == 111);\n"
60+
// Test passing reference of structs by arguments (with no args on create ptr)
61+
"data_ptr = metacall_value_create_ptr();\n"
62+
"data_ptr_ref = metacall_value_reference(data_ptr);\n"
63+
"console.log(data_ptr);\n"
64+
"console.log(data_ptr_ref);\n"
65+
"alloc_data_args(data_ptr_ref);\n"
66+
"alloc_data_ptr = metacall_value_dereference(data_ptr_ref);\n"
67+
"console.log(alloc_data_ptr);\n"
68+
"set_data_value(alloc_data_ptr, 12);\n"
69+
"assert(get_data_value(alloc_data_ptr) == 12);\n"
70+
"free_data(alloc_data_ptr);\n"
71+
// Test passing reference of structs by arguments (with undefined arg on create ptr)
72+
"data_ptr = metacall_value_create_ptr(undefined);\n"
73+
"data_ptr_ref = metacall_value_reference(data_ptr);\n"
74+
"console.log(data_ptr);\n"
75+
"console.log(data_ptr_ref);\n"
76+
"alloc_data_args(data_ptr_ref);\n"
77+
"alloc_data_ptr = metacall_value_dereference(data_ptr_ref);\n"
78+
"console.log(alloc_data_ptr);\n"
79+
"set_data_value(alloc_data_ptr, 12);\n"
80+
"assert(get_data_value(alloc_data_ptr) == 12);\n"
81+
"free_data(alloc_data_ptr);\n"
82+
// Test passing reference of structs by arguments (with another pointer arg on create ptr)
83+
"data_ptr = metacall_value_create_ptr(undefined);\n"
84+
"copy_data_ptr = metacall_value_create_ptr(data_ptr);\n"
85+
"console.log(data_ptr);\n"
86+
"console.log(copy_data_ptr);\n"
87+
"assert(compare_data_value(data_ptr, copy_data_ptr));\n"
88+
"data_ptr_ref = metacall_value_reference(copy_data_ptr);\n"
89+
"console.log(data_ptr);\n"
90+
"console.log(data_ptr_ref);\n"
91+
"alloc_data_args(data_ptr_ref);\n"
92+
"alloc_data_ptr = metacall_value_dereference(data_ptr_ref);\n"
93+
"console.log(alloc_data_ptr);\n"
94+
"set_data_value(alloc_data_ptr, 12);\n"
95+
"assert(get_data_value(alloc_data_ptr) == 12);\n"
96+
"free_data(alloc_data_ptr);\n"
5597
"\n";
5698

5799
ASSERT_EQ((int)0, (int)metacall_load_from_memory("node", buffer, sizeof(buffer), NULL));

0 commit comments

Comments
 (0)