• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef _CONVERTORS_NAPI_H_
17 #define _CONVERTORS_NAPI_H_
18 
19 #ifdef KOALA_NAPI
20 
21 #include <unordered_map>
22 #include <vector>
23 #include <string>
24 
25 #ifndef KOALA_NAPI_OHOS
26 #include <node_api.h>
27 #else
28 #include <native_api.h>
29 #include <native_node_api.h>
30 #endif
31 #include "koala-types.h"
32 #include "interop-types.h"
33 
34 template<class T>
35 struct InteropTypeConverter {
36     using InteropType = T;
convertFromInteropTypeConverter37     static T convertFrom(napi_env env, InteropType value) { return value; }
convertToInteropTypeConverter38     static InteropType convertTo(napi_env env, T value) { return value; }
releaseInteropTypeConverter39     static void release(napi_env env, InteropType value, T converted) {}
40 };
41 
42 template <typename Type>
makeResult(napi_env env,Type value)43 inline typename InteropTypeConverter<Type>::InteropType makeResult(napi_env env, Type value) {
44   return InteropTypeConverter<Type>::convertTo(env, value);
45 }
46 
47 template <typename Type>
getArgument(napi_env env,typename InteropTypeConverter<Type>::InteropType arg)48 inline Type getArgument(napi_env env, typename InteropTypeConverter<Type>::InteropType arg) {
49   return InteropTypeConverter<Type>::convertFrom(env, arg);
50 }
51 
52 template <typename Type>
releaseArgument(napi_env env,typename InteropTypeConverter<Type>::InteropType arg,Type data)53 inline void releaseArgument(napi_env env, typename InteropTypeConverter<Type>::InteropType arg, Type data) {
54   InteropTypeConverter<Type>::release(env, arg, data);
55 }
56 
57 template<>
58 struct InteropTypeConverter<KInteropBuffer> {
59     using InteropType = napi_value;
60     static KInteropBuffer convertFrom(napi_env env, InteropType value) {
61       KInteropBuffer result = { 0 };
62       bool isArrayBuffer = false;
63       napi_is_arraybuffer(env, value, &isArrayBuffer);
64       if (isArrayBuffer) {
65         napi_get_arraybuffer_info(env, value, &result.data, (size_t*)&result.length);
66       } else {
67         bool isDataView = false;
68         napi_is_dataview(env, value, &isDataView);
69         if (isDataView) {
70           napi_get_dataview_info(env, value, (size_t*)&result.length, &result.data, nullptr, nullptr);
71         }
72       }
73       return result;
74     }
75     static InteropType convertTo(napi_env env, KInteropBuffer value) {
76       KInteropBuffer* copy = new KInteropBuffer(value);
77       napi_value result;
78       napi_status status = napi_create_external_arraybuffer(
79         env,
80         value.data,
81         value.length,
82         [](napi_env env, void* finalize_data, void* finalize_hint) {
83           KInteropBuffer* buffer = reinterpret_cast<KInteropBuffer*>(finalize_hint);
84           buffer->dispose(buffer->resourceId);
85           delete buffer;
86         },
87         (void*)copy,
88         &result
89       );
90       return result;
91     };
92     static void release(napi_env env, InteropType value, KInteropBuffer converted) {}
93 };
94 
95 template<>
96 struct InteropTypeConverter<KStringPtr> {
97     using InteropType = napi_value;
98     static KStringPtr convertFrom(napi_env env, InteropType value) {
99         if (value == nullptr) return KStringPtr();
100         KStringPtr result;
101         size_t length = 0;
102         napi_status status = napi_get_value_string_utf8(env, value, nullptr, 0, &length);
103         if (status != 0) return result;
104         result.resize(length);
105         status = napi_get_value_string_utf8(env, value, result.data(), length + 1, nullptr);
106         return result;
107     }
108     static InteropType convertTo(napi_env env, const KStringPtr& value) {
109       napi_value result;
110       napi_create_string_utf8(env, value.c_str(), value.length(), &result);
111       return result;
112     }
113     static void release(napi_env env, InteropType value, const KStringPtr& converted) {}
114 };
115 
116 template<>
117 struct InteropTypeConverter<KInteropNumber> {
118     using InteropType = napi_value;
119     static KInteropNumber convertFrom(napi_env env, InteropType interopValue) {
120         double value = 0.0;
121         napi_get_value_double(env, interopValue, &value);
122         return KInteropNumber::fromDouble(value);
123     }
124     static InteropType convertTo(napi_env env, KInteropNumber value) {
125       napi_value result;
126       napi_create_double(env, value.asDouble(), &result);
127       return result;
128     }
129     static void release(napi_env env, InteropType value, KInteropNumber converted) {}
130 };
131 
132 template<>
133 struct InteropTypeConverter<KVMObjectHandle> {
134     using InteropType = napi_value;
135     static inline KVMObjectHandle convertFrom(napi_env env, InteropType value) {
136         return reinterpret_cast<KVMObjectHandle>(value);
137     }
138     static InteropType convertTo(napi_env env, KVMObjectHandle value) {
139       return reinterpret_cast<napi_value>(value);
140     }
141     static inline void release(napi_env env, InteropType value, KVMObjectHandle converted) {
142     }
143 };
144 
145 template<>
146 struct InteropTypeConverter<KInteropReturnBuffer> {
147     using InteropType = napi_value;
148     static inline KInteropReturnBuffer convertFrom(napi_env env, InteropType value) = delete;
149     static void disposer(napi_env env, void* data, void* hint) {
150       KInteropReturnBuffer* bufferCopy = (KInteropReturnBuffer*)hint;
151       bufferCopy->dispose(bufferCopy->data, bufferCopy->length);
152       delete bufferCopy;
153     }
154     static InteropType convertTo(napi_env env, KInteropReturnBuffer value) {
155       napi_value result = nullptr;
156       napi_value arrayBuffer = nullptr;
157       auto clone = new KInteropReturnBuffer();
158       *clone = value;
159       napi_create_external_arraybuffer(env, value.data, value.length, disposer, clone, &arrayBuffer);
160       napi_create_typedarray(env, napi_uint8_array, value.length, arrayBuffer, 0, &result);
161       return result;
162     }
163     static inline void release(napi_env env, InteropType value, const KInteropReturnBuffer& converted) = delete;
164 };
165 
166 
167 #define KOALA_INTEROP_THROW(vmcontext, object, ...) \
168    do { \
169      napi_env env = (napi_env)vmcontext; \
170      napi_handle_scope scope = nullptr; \
171      napi_open_handle_scope(env, &scope); \
172      napi_throw((napi_env)vmcontext, object); \
173      napi_close_handle_scope(env, scope); \
174      return __VA_ARGS__;  \
175    } while (0)
176 
177 #define KOALA_INTEROP_THROW_STRING(vmContext, message, ...) \
178   do { \
179     napi_value value; \
180     napi_create_string_utf8((napi_env)vmContext, message, strlen(message), &value); \
181     KOALA_INTEROP_THROW(vmContext, value, __VA_ARGS__); \
182   } while (0)
183 
184 #define NAPI_ASSERT_INDEX(info, index, result)              \
185     do {                                                    \
186         if (static_cast<size_t>(index) >= info.Length()) {  \
187           napi_throw_error(info.Env(), nullptr, "No such element");\
188           return result;                                  \
189         }                                                   \
190     } while (0)
191 
192 // Helpers from node-addon-api
193 #define KOALA_NAPI_THROW_IF_FAILED(env, status, ...)                                 \
194   if ((status) != napi_ok) {                                                   \
195     const napi_extended_error_info* errorInfo;                                 \
196     napi_get_last_error_info(env, &errorInfo);                                 \
197     napi_throw_error(env, nullptr, errorInfo->error_message);                  \
198     return __VA_ARGS__;                                                        \
199   }
200 #define KOALA_NAPI_THROW_IF_FAILED_VOID(env, status)                                 \
201   if ((status) != napi_ok) {                                                   \
202     const napi_extended_error_info* errorInfo;                                 \
203     napi_get_last_error_info(env, &errorInfo);                                 \
204     napi_throw_error(env, nullptr, errorInfo->error_message);                  \
205     return;                                                        \
206   }
207 
208 class CallbackInfo {
209 public:
210   CallbackInfo(napi_env env, napi_callback_info info) : _env(env) {
211     size_t size = 0;
212     napi_status status;
213     status = napi_get_cb_info(env, info, &size, nullptr, nullptr, nullptr);
214     KOALA_NAPI_THROW_IF_FAILED_VOID(env, status);
215     if (size > 0) {
216       args.resize(size);  // TODO statically allocate small array for common case with few arguments passed
217       status = napi_get_cb_info(env, info, &size, args.data(), nullptr, nullptr);
218       KOALA_NAPI_THROW_IF_FAILED_VOID(env, status);
219     }
220   }
221 
222   napi_value operator[](size_t idx) const {
223     if (idx >= Length()) {
224       napi_value result;
225       napi_get_undefined(_env, &result);
226       return result;
227     }
228     return args[idx];
229   }
230 
231   napi_env Env() const {
232     return _env;
233   }
234 
235   size_t Length() const {
236     return args.size();
237   }
238 private:
239   napi_env _env;
240   std::vector<napi_value> args;
241 };
242 
243 template <typename ElemType>
244 inline napi_typedarray_type getNapiType() = delete;
245 
246 template <>
247 inline napi_typedarray_type getNapiType<float>() {
248   return napi_float32_array;
249 }
250 
251 template <>
252 inline napi_typedarray_type getNapiType<int8_t>() {
253   return napi_int8_array;
254 }
255 
256 template <>
257 inline napi_typedarray_type getNapiType<uint8_t>() {
258   return napi_uint8_array;
259 }
260 
261 template <>
262 inline napi_typedarray_type getNapiType<int16_t>() {
263   return napi_int16_array;
264 }
265 
266 template <>
267 inline napi_typedarray_type getNapiType<uint16_t>() {
268   return napi_uint16_array;
269 }
270 
271 template <>
272 inline napi_typedarray_type getNapiType<int32_t>() {
273   return napi_int32_array;
274 }
275 
276 template <>
277 inline napi_typedarray_type getNapiType<uint32_t>() {
278   return napi_uint32_array;
279 }
280 
281 template <>
282 inline napi_typedarray_type getNapiType<KNativePointer>() {
283   return napi_biguint64_array;
284 }
285 
286 napi_valuetype getValueTypeChecked(napi_env env, napi_value value);
287 bool isTypedArray(napi_env env, napi_value value);
288 
289 template <typename ElemType>
290 inline ElemType* getTypedElements(napi_env env, napi_value value) {
291   napi_valuetype valueType = getValueTypeChecked(env, value);
292   if (valueType == napi_null) {
293     return nullptr;
294   }
295   if (!isTypedArray(env, value)) {
296     napi_throw_error(env, nullptr, "Expected TypedArray");
297     return nullptr;
298   }
299   napi_value arrayBuffer;
300   void* data = nullptr;
301   size_t byteLength;
302   size_t byteOffset;
303   napi_typedarray_type type;
304   napi_status status = napi_get_typedarray_info(env,
305                                                 value,
306                                                 &type,
307                                                 &byteLength,
308                                                 &data,
309                                                 &arrayBuffer,
310                                                 &byteOffset);
311   KOALA_NAPI_THROW_IF_FAILED(env, status, nullptr);
312   if (type != getNapiType<ElemType>()) {
313     printf("Array type mismatch. Expected %d got %d\n", getNapiType<ElemType>(), type);
314     napi_throw_error(env, nullptr, "Array type mismatch");
315     return nullptr;
316   }
317   return reinterpret_cast<ElemType*>(data);
318 }
319 
320 template <typename ElemType>
321 inline ElemType* getTypedElements(const CallbackInfo& info, int index) {
322     NAPI_ASSERT_INDEX(info, index, nullptr);
323     return getTypedElements<ElemType>(info.Env(), info[index]);
324 }
325 
326 inline uint8_t* getUInt8Elements(const CallbackInfo& info, int index) {
327   return getTypedElements<uint8_t>(info, index);
328 }
329 
330 inline int8_t* getInt8Elements(const CallbackInfo& info, int index) {
331   return getTypedElements<int8_t>(info, index);
332 }
333 
334 inline uint16_t* getUInt16Elements(const CallbackInfo& info, int index) {
335   return getTypedElements<uint16_t>(info, index);
336 }
337 
338 inline int16_t* getInt16Elements(const CallbackInfo& info, int index) {
339   return getTypedElements<int16_t>(info, index);
340 }
341 
342 inline uint32_t* getUInt32Elements(const CallbackInfo& info, int index) {
343   return getTypedElements<uint32_t>(info, index);
344 }
345 
346 inline uint32_t* getUInt32Elements(napi_env env, napi_value value) {
347     return getTypedElements<uint32_t>(env, value);
348 }
349 
350 inline int32_t* getInt32Elements(const CallbackInfo& info, int index) {
351   return getTypedElements<int32_t>(info, index);
352 }
353 
354 inline float* getFloat32Elements(const CallbackInfo& info, int index) {
355   return getTypedElements<float>(info, index);
356 }
357 
358 inline KNativePointer* getPointerElements(const CallbackInfo& info, int index) {
359   return getTypedElements<KNativePointer>(info, index);
360 }
361 
362 KInt getInt32(napi_env env, napi_value value);
363 inline int32_t getInt32(const CallbackInfo& info, int index) {
364   NAPI_ASSERT_INDEX(info, index, 0);
365   return getInt32(info.Env(), info[index]);
366 }
367 KUInt getUInt32(napi_env env, napi_value value);
368 inline uint32_t getUInt32(const CallbackInfo& info, int index) {
369   NAPI_ASSERT_INDEX(info, index, 0);
370   return getUInt32(info.Env(), info[index]);
371 }
372 KFloat getFloat32(napi_env env, napi_value value);
373 inline float getFloat32(const CallbackInfo& info, int index) {
374   NAPI_ASSERT_INDEX(info, index, 0.0f);
375   return getFloat32(info.Env(), info[index]);
376 }
377 KDouble getFloat64(napi_env env, napi_value value);
378 inline KDouble getFloat64(const CallbackInfo& info, int index) {
379   NAPI_ASSERT_INDEX(info, index, 0.0);
380   return getFloat64(info.Env(), info[index]);
381 }
382 KStringPtr getString(napi_env env, napi_value value);
383 inline KStringPtr getString(const CallbackInfo& info, int index) {
384   NAPI_ASSERT_INDEX(info, index, KStringPtr());
385   return getString(info.Env(), info[index]);
386 }
387 void* getPointer(napi_env env, napi_value value);
388 inline void* getPointer(const CallbackInfo& info, int index) {
389     NAPI_ASSERT_INDEX(info, index, nullptr);
390     return getPointer(info.Env(), info[index]);
391 }
392 KULong getUInt64(napi_env env, napi_value value);
393 inline KULong getUInt64(const CallbackInfo& info, int index) {
394     NAPI_ASSERT_INDEX(info, index, 0);
395     return getUInt64(info.Env(), info[index]);
396 }
397 KLong getInt64(napi_env env, napi_value value);
398 inline KLong getInt64(const CallbackInfo& info, int index) {
399     NAPI_ASSERT_INDEX(info, index, 0);
400     return getInt64(info.Env(), info[index]);
401 }
402 KBoolean getBoolean(napi_env env, napi_value value);
403 inline KBoolean getBoolean(const CallbackInfo& info, int index) {
404   NAPI_ASSERT_INDEX(info, index, false);
405   return getBoolean(info.Env(), info[index]);
406 }
407 
408 template <typename Type>
409 inline Type getArgument(const CallbackInfo& info, int index) = delete;
410 
411 template <>
412 inline KBoolean getArgument<KBoolean>(const CallbackInfo& info, int index) {
413   return getBoolean(info, index);
414 }
415 
416 template <>
417 inline KUInt getArgument<uint32_t>(const CallbackInfo& info, int index) {
418   return getUInt32(info, index);
419 }
420 
421 template <>
422 inline KInt getArgument<int32_t>(const CallbackInfo& info, int index) {
423   return getInt32(info, index);
424 }
425 
426 template <>
427 inline KInteropNumber getArgument<KInteropNumber>(const CallbackInfo& info, int index) {
428   NAPI_ASSERT_INDEX(info, index, { 0 });
429   return getArgument<KInteropNumber>(info.Env(), info[index]);
430 }
431 
432 template <>
433 inline KLength getArgument<KLength>(const CallbackInfo& info, int index) {
434   KLength result = { 0 };
435   NAPI_ASSERT_INDEX(info, index, result);
436   auto value = info[index];
437   napi_valuetype type;
438   auto status = napi_typeof(info.Env(), value, &type);
439   if (status != 0) return result;
440   switch (type) {
441     case napi_number: {
442       result.value = getFloat32(info.Env(), value);
443       result.unit = 1;
444       result.type = 0;
445       break;
446     }
447     case napi_string: {
448       KStringPtr string = getString(info.Env(), value);
449       parseKLength(string, &result);
450       result.type = 1;
451       result.resource = 0;
452       break;
453     }
454     case napi_object: {
455       result.value = 0;
456       result.unit = 1;
457       result.type = 2;
458       napi_value field;
459       napi_status status = napi_get_named_property(info.Env(), value, "id", &field);
460       if (status == 0) {
461         status = napi_get_value_int32(info.Env(), field, &result.resource);
462         if (status != 0) result.resource = 0;
463       } else {
464         result.resource = 0;
465       }
466       break;
467     }
468     default:
469       INTEROP_FATAL("Error, unexpected KLength type");
470   }
471   return result;
472 }
473 
474 
475 template <>
476 inline KInteropBuffer getArgument<KInteropBuffer>(const CallbackInfo& info, int index) {
477   NAPI_ASSERT_INDEX(info, index, { 0 });
478   return getArgument<KInteropBuffer>((napi_env)info.Env(), (napi_value)info[index]);
479 }
480 
481 template <>
482 inline KFloat getArgument<KFloat>(const CallbackInfo& info, int index) {
483   return getFloat32(info, index);
484 }
485 
486 template <>
487 inline KDouble getArgument<KDouble>(const CallbackInfo& info, int index) {
488   return getFloat64(info, index);
489 }
490 
491 template <>
492 inline KNativePointer getArgument<KNativePointer>(const CallbackInfo& info, int index) {
493   return getPointer(info, index);
494 }
495 
496 template <>
497 inline KLong getArgument<KLong>(const CallbackInfo& info, int index) {
498   return getInt64(info, index);
499 }
500 
501 template <>
502 inline KULong getArgument<KULong>(const CallbackInfo& info, int index) {
503   return getUInt64(info, index);
504 }
505 
506 template <>
507 inline KNativePointerArray getArgument<KNativePointerArray>(const CallbackInfo& info, int index) {
508   return getPointerElements(info, index);
509 }
510 
511 template <>
512 inline uint8_t* getArgument<uint8_t*>(const CallbackInfo& info, int index) {
513   return getUInt8Elements(info, index);
514 }
515 
516 template <>
517 inline const uint8_t* getArgument<const uint8_t*>(const CallbackInfo& info, int index) {
518   return getUInt8Elements(info, index);
519 }
520 
521 template <>
522 inline int8_t* getArgument<int8_t*>(const CallbackInfo& info, int index) {
523   return getInt8Elements(info, index);
524 }
525 
526 template <>
527 inline int16_t* getArgument<int16_t*>(const CallbackInfo& info, int index) {
528   return getInt16Elements(info, index);
529 }
530 
531 template <>
532 inline uint16_t* getArgument<uint16_t*>(const CallbackInfo& info, int index) {
533   return getUInt16Elements(info, index);
534 }
535 
536 template <>
537 inline int32_t* getArgument<int32_t*>(const CallbackInfo& info, int index) {
538   return getInt32Elements(info, index);
539 }
540 
541 template <>
542 inline uint32_t* getArgument<uint32_t*>(const CallbackInfo& info, int index) {
543   return getUInt32Elements(info, index);
544 }
545 
546 template <>
547 inline float* getArgument<float*>(const CallbackInfo& info, int index) {
548   return getFloat32Elements(info, index);
549 }
550 
551 template <>
552 inline KStringPtr getArgument<KStringPtr>(const CallbackInfo& info, int index) {
553   return getString(info, index);
554 }
555 
556 napi_value makeString(napi_env env, KStringPtr value);
557 napi_value makeString(napi_env env, const std::string& value);
558 napi_value makeBoolean(napi_env env, KBoolean value);
559 napi_value makeInt32(napi_env env, int32_t value);
560 napi_value makeUInt32(napi_env env, uint32_t value);
561 napi_value makeInt64(napi_env env, int32_t value);
562 napi_value makeUInt64(napi_env env, uint32_t value);
563 napi_value makeFloat32(napi_env env, float value);
564 napi_value makePointer(napi_env env, void* value);
565 napi_value makeVoid(napi_env env);
566 
567 inline napi_value makeVoid(const CallbackInfo& info) {
568   return makeVoid(info.Env());
569 }
570 
571 template <typename Type>
572 inline napi_value makeResult(const CallbackInfo& info, Type value) = delete;
573 
574 template <>
575 inline napi_value makeResult<KBoolean>(const CallbackInfo& info, KBoolean value) {
576   return makeBoolean(info.Env(), value);
577 }
578 
579 template <>
580 inline napi_value makeResult<int32_t>(const CallbackInfo& info, int32_t value) {
581   return makeInt32(info.Env(), value);
582 }
583 
584 template <>
585 inline napi_value makeResult<uint32_t>(const CallbackInfo& info, uint32_t value) {
586   return makeUInt32(info.Env(), value);
587 }
588 
589 template <>
590 inline napi_value makeResult<KLong>(const CallbackInfo& info, int64_t value) {
591   return makeInt64(info.Env(), value);
592 }
593 
594 template <>
595 inline napi_value makeResult<KULong>(const CallbackInfo& info, uint64_t value) {
596   return makeUInt64(info.Env(), value);
597 }
598 
599 template <>
600 inline napi_value makeResult<float>(const CallbackInfo& info, float value) {
601   return makeFloat32(info.Env(), value);
602 }
603 
604 template <>
605 inline napi_value makeResult<KNativePointer>(const CallbackInfo& info, KNativePointer value) {
606   return makePointer(info.Env(), value);
607 }
608 
609 template <>
610 inline napi_value makeResult<KVMObjectHandle>(const CallbackInfo& info, KVMObjectHandle value) {
611   return InteropTypeConverter<KVMObjectHandle>::convertTo(info.Env(), value);
612 }
613 
614 template <>
615 inline napi_value makeResult<KStringPtr>(const CallbackInfo& info, KStringPtr value) {
616   return InteropTypeConverter<KStringPtr>::convertTo(info.Env(), value);
617 }
618 
619 template <>
620 inline napi_value makeResult<KInteropBuffer>(const CallbackInfo& info, KInteropBuffer value) {
621   return InteropTypeConverter<KInteropBuffer>::convertTo(info.Env(), value);
622 }
623 
624 template <>
625 inline napi_value makeResult<KInteropReturnBuffer>(const CallbackInfo& info, KInteropReturnBuffer value) {
626   return InteropTypeConverter<KInteropReturnBuffer>::convertTo(info.Env(), value);
627 }
628 
629 template <>
630 inline napi_value makeResult<KInteropNumber>(const CallbackInfo& info, KInteropNumber value) {
631   return InteropTypeConverter<KInteropNumber>::convertTo(info.Env(), value);
632 }
633 
634 typedef napi_value (*napi_type_t)(napi_env, napi_callback_info);
635 
636 class Exports {
637     std::unordered_map<std::string,
638       std::vector<std::pair<std::string, napi_type_t>>> implementations;
639 
640 public:
641     static Exports* getInstance();
642 
643     std::vector<std::string> getModules();
644     void addMethod(const char* module, const char* name, napi_type_t impl);
645     const std::vector<std::pair<std::string, napi_type_t>>& getMethods(const std::string& module);
646 };
647 
648 #define QUOTE(x) #x
649 
650 #ifdef _MSC_VER
651 #define MAKE_NODE_EXPORT(module, name)                                  \
652     static void __init_##name() {                               \
653         Exports::getInstance()->addMethod(QUOTE(module), "_"#name, Node_##name); \
654     }                                                           \
655     namespace {                                                 \
656       struct __Init_##name {                                    \
657         __Init_##name() {  __init_##name(); }                   \
658       } __Init_##name##_v;                                      \
659     }
660 #else
661 #define MAKE_NODE_EXPORT(module, name) \
662     __attribute__((constructor)) \
663     static void __init_##name() { \
664         Exports::getInstance()->addMethod(QUOTE(module), "_"#name, Node_##name); \
665     }
666 #endif
667 
668 #ifndef KOALA_INTEROP_MODULE
669 #error KOALA_INTEROP_MODULE is undefined
670 #endif
671 
672 #define MAKE_INTEROP_NODE_EXPORT(name) MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
673 
674 #define KOALA_INTEROP_0(name, Ret) \
675   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
676       KOALA_MAYBE_LOG(name)                        \
677       CallbackInfo info(env, cbinfo);              \
678       return makeResult<Ret>(info, impl_##name()); \
679   } \
680   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
681 
682 #define KOALA_INTEROP_1(name, Ret, P0) \
683   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
684       KOALA_MAYBE_LOG(name)                   \
685       CallbackInfo info(env, cbinfo);              \
686       P0 p0 = getArgument<P0>(info, 0); \
687       return makeResult<Ret>(info, impl_##name(p0)); \
688   } \
689   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
690 
691 #define KOALA_INTEROP_2(name, Ret, P0, P1) \
692   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
693       KOALA_MAYBE_LOG(name)                   \
694       CallbackInfo info(env, cbinfo);              \
695       P0 p0 = getArgument<P0>(info, 0); \
696       P1 p1 = getArgument<P1>(info, 1); \
697       return makeResult<Ret>(info, impl_##name(p0, p1)); \
698   } \
699   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
700 
701 #define KOALA_INTEROP_3(name, Ret, P0, P1, P2) \
702   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
703       KOALA_MAYBE_LOG(name)                   \
704       CallbackInfo info(env, cbinfo);              \
705       P0 p0 = getArgument<P0>(info, 0); \
706       P1 p1 = getArgument<P1>(info, 1); \
707       P2 p2 = getArgument<P2>(info, 2); \
708       return makeResult<Ret>(info, impl_##name(p0, p1, p2)); \
709   } \
710   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
711 
712 #define KOALA_INTEROP_4(name, Ret, P0, P1, P2, P3) \
713   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
714       KOALA_MAYBE_LOG(name)                   \
715       CallbackInfo info(env, cbinfo);              \
716       P0 p0 = getArgument<P0>(info, 0); \
717       P1 p1 = getArgument<P1>(info, 1); \
718       P2 p2 = getArgument<P2>(info, 2); \
719       P3 p3 = getArgument<P3>(info, 3); \
720       return makeResult<Ret>(info, impl_##name(p0, p1, p2, p3)); \
721   } \
722   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
723 
724 #define KOALA_INTEROP_5(name, Ret, P0, P1, P2, P3, P4) \
725   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
726       KOALA_MAYBE_LOG(name)                   \
727       CallbackInfo info(env, cbinfo);              \
728       P0 p0 = getArgument<P0>(info, 0); \
729       P1 p1 = getArgument<P1>(info, 1); \
730       P2 p2 = getArgument<P2>(info, 2); \
731       P3 p3 = getArgument<P3>(info, 3); \
732       P4 p4 = getArgument<P4>(info, 4); \
733       return makeResult<Ret>(info, impl_##name(p0, p1, p2, p3, p4)); \
734   } \
735   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
736 
737 #define KOALA_INTEROP_6(name, Ret, P0, P1, P2, P3, P4, P5) \
738   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
739       KOALA_MAYBE_LOG(name)                   \
740       CallbackInfo info(env, cbinfo);              \
741       P0 p0 = getArgument<P0>(info, 0); \
742       P1 p1 = getArgument<P1>(info, 1); \
743       P2 p2 = getArgument<P2>(info, 2); \
744       P3 p3 = getArgument<P3>(info, 3); \
745       P4 p4 = getArgument<P4>(info, 4); \
746       P5 p5 = getArgument<P5>(info, 5); \
747       return makeResult<Ret>(info, impl_##name(p0, p1, p2, p3, p4, p5)); \
748   } \
749   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
750 
751 #define KOALA_INTEROP_7(name, Ret, P0, P1, P2, P3, P4, P5, P6) \
752   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
753       KOALA_MAYBE_LOG(name)                   \
754       CallbackInfo info(env, cbinfo);              \
755       P0 p0 = getArgument<P0>(info, 0); \
756       P1 p1 = getArgument<P1>(info, 1); \
757       P2 p2 = getArgument<P2>(info, 2); \
758       P3 p3 = getArgument<P3>(info, 3); \
759       P4 p4 = getArgument<P4>(info, 4); \
760       P5 p5 = getArgument<P5>(info, 5); \
761       P6 p6 = getArgument<P6>(info, 6); \
762       return makeResult<Ret>(info, impl_##name(p0, p1, p2, p3, p4, p5, p6)); \
763   } \
764   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
765 
766 #define KOALA_INTEROP_8(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7) \
767   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
768       KOALA_MAYBE_LOG(name)                   \
769       CallbackInfo info(env, cbinfo);              \
770       P0 p0 = getArgument<P0>(info, 0); \
771       P1 p1 = getArgument<P1>(info, 1); \
772       P2 p2 = getArgument<P2>(info, 2); \
773       P3 p3 = getArgument<P3>(info, 3); \
774       P4 p4 = getArgument<P4>(info, 4); \
775       P5 p5 = getArgument<P5>(info, 5); \
776       P6 p6 = getArgument<P6>(info, 6); \
777       P7 p7 = getArgument<P7>(info, 7); \
778       return makeResult<Ret>(info, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7)); \
779   } \
780   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
781 
782 #define KOALA_INTEROP_9(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8) \
783   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
784       KOALA_MAYBE_LOG(name)                   \
785       CallbackInfo info(env, cbinfo);              \
786       P0 p0 = getArgument<P0>(info, 0); \
787       P1 p1 = getArgument<P1>(info, 1); \
788       P2 p2 = getArgument<P2>(info, 2); \
789       P3 p3 = getArgument<P3>(info, 3); \
790       P4 p4 = getArgument<P4>(info, 4); \
791       P5 p5 = getArgument<P5>(info, 5); \
792       P6 p6 = getArgument<P6>(info, 6); \
793       P7 p7 = getArgument<P7>(info, 7); \
794       P8 p8 = getArgument<P8>(info, 8); \
795       return makeResult<Ret>(info, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8)); \
796   } \
797   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
798 
799 #define KOALA_INTEROP_10(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \
800   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
801       KOALA_MAYBE_LOG(name)                   \
802       CallbackInfo info(env, cbinfo);              \
803       P0 p0 = getArgument<P0>(info, 0); \
804       P1 p1 = getArgument<P1>(info, 1); \
805       P2 p2 = getArgument<P2>(info, 2); \
806       P3 p3 = getArgument<P3>(info, 3); \
807       P4 p4 = getArgument<P4>(info, 4); \
808       P5 p5 = getArgument<P5>(info, 5); \
809       P6 p6 = getArgument<P6>(info, 6); \
810       P7 p7 = getArgument<P7>(info, 7); \
811       P8 p8 = getArgument<P8>(info, 8); \
812       P9 p9 = getArgument<P9>(info, 9); \
813       return makeResult<Ret>(info, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)); \
814   } \
815   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
816 
817 #define KOALA_INTEROP_11(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \
818   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
819       KOALA_MAYBE_LOG(name)                   \
820       CallbackInfo info(env, cbinfo);              \
821       P0 p0 = getArgument<P0>(info, 0); \
822       P1 p1 = getArgument<P1>(info, 1); \
823       P2 p2 = getArgument<P2>(info, 2); \
824       P3 p3 = getArgument<P3>(info, 3); \
825       P4 p4 = getArgument<P4>(info, 4); \
826       P5 p5 = getArgument<P5>(info, 5); \
827       P6 p6 = getArgument<P6>(info, 6); \
828       P7 p7 = getArgument<P7>(info, 7); \
829       P8 p8 = getArgument<P8>(info, 8); \
830       P9 p9 = getArgument<P9>(info, 9); \
831       P10 p10 = getArgument<P10>(info, 10); \
832       return makeResult<Ret>(info, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)); \
833   } \
834   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
835 
836 #define KOALA_INTEROP_12(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) \
837   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
838       KOALA_MAYBE_LOG(name)                   \
839       CallbackInfo info(env, cbinfo);              \
840       P0 p0 = getArgument<P0>(info, 0); \
841       P1 p1 = getArgument<P1>(info, 1); \
842       P2 p2 = getArgument<P2>(info, 2); \
843       P3 p3 = getArgument<P3>(info, 3); \
844       P4 p4 = getArgument<P4>(info, 4); \
845       P5 p5 = getArgument<P5>(info, 5); \
846       P6 p6 = getArgument<P6>(info, 6); \
847       P7 p7 = getArgument<P7>(info, 7); \
848       P8 p8 = getArgument<P8>(info, 8); \
849       P9 p9 = getArgument<P9>(info, 9); \
850       P10 p10 = getArgument<P10>(info, 10); \
851       P11 p11 = getArgument<P11>(info, 11); \
852       return makeResult<Ret>(info, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11)); \
853   } \
854   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
855 
856 #define KOALA_INTEROP_13(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) \
857   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
858       KOALA_MAYBE_LOG(name)                   \
859       CallbackInfo info(env, cbinfo);              \
860       P0 p0 = getArgument<P0>(info, 0); \
861       P1 p1 = getArgument<P1>(info, 1); \
862       P2 p2 = getArgument<P2>(info, 2); \
863       P3 p3 = getArgument<P3>(info, 3); \
864       P4 p4 = getArgument<P4>(info, 4); \
865       P5 p5 = getArgument<P5>(info, 5); \
866       P6 p6 = getArgument<P6>(info, 6); \
867       P7 p7 = getArgument<P7>(info, 7); \
868       P8 p8 = getArgument<P8>(info, 8); \
869       P9 p9 = getArgument<P9>(info, 9); \
870       P10 p10 = getArgument<P10>(info, 10); \
871       P11 p11 = getArgument<P11>(info, 11); \
872       P12 p12 = getArgument<P12>(info, 12); \
873       return makeResult<Ret>(info, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12)); \
874   } \
875   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
876 
877 #define KOALA_INTEROP_14(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) \
878   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
879       KOALA_MAYBE_LOG(name)                   \
880       CallbackInfo info(env, cbinfo);              \
881       P0 p0 = getArgument<P0>(info, 0); \
882       P1 p1 = getArgument<P1>(info, 1); \
883       P2 p2 = getArgument<P2>(info, 2); \
884       P3 p3 = getArgument<P3>(info, 3); \
885       P4 p4 = getArgument<P4>(info, 4); \
886       P5 p5 = getArgument<P5>(info, 5); \
887       P6 p6 = getArgument<P6>(info, 6); \
888       P7 p7 = getArgument<P7>(info, 7); \
889       P8 p8 = getArgument<P8>(info, 8); \
890       P9 p9 = getArgument<P9>(info, 9); \
891       P10 p10 = getArgument<P10>(info, 10); \
892       P11 p11 = getArgument<P11>(info, 11); \
893       P12 p12 = getArgument<P12>(info, 12); \
894       P13 p13 = getArgument<P13>(info, 13); \
895       return makeResult<Ret>(info, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13)); \
896   } \
897   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
898 
899 #define KOALA_INTEROP_V0(name) \
900   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
901       KOALA_MAYBE_LOG(name)                   \
902       CallbackInfo info(env, cbinfo);              \
903       impl_##name(); \
904       return makeVoid(info); \
905   } \
906   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
907 
908 #define KOALA_INTEROP_V1(name, P0) \
909   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
910       KOALA_MAYBE_LOG(name)                   \
911       CallbackInfo info(env, cbinfo);              \
912       P0 p0 = getArgument<P0>(info, 0); \
913       impl_##name(p0); \
914       return makeVoid(info); \
915   } \
916   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
917 
918 #define KOALA_INTEROP_V2(name, P0, P1) \
919   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
920       KOALA_MAYBE_LOG(name)                   \
921       CallbackInfo info(env, cbinfo);              \
922       P0 p0 = getArgument<P0>(info, 0); \
923       P1 p1 = getArgument<P1>(info, 1); \
924       impl_##name(p0, p1); \
925       return makeVoid(info); \
926   } \
927   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
928 
929 #define KOALA_INTEROP_V3(name, P0, P1, P2) \
930   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
931       KOALA_MAYBE_LOG(name)                   \
932       CallbackInfo info(env, cbinfo);              \
933       P0 p0 = getArgument<P0>(info, 0); \
934       P1 p1 = getArgument<P1>(info, 1); \
935       P2 p2 = getArgument<P2>(info, 2); \
936       impl_##name(p0, p1, p2); \
937       return makeVoid(info); \
938   } \
939   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
940 
941 #define KOALA_INTEROP_V4(name, P0, P1, P2, P3) \
942   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
943       KOALA_MAYBE_LOG(name)                   \
944       CallbackInfo info(env, cbinfo);              \
945       P0 p0 = getArgument<P0>(info, 0); \
946       P1 p1 = getArgument<P1>(info, 1); \
947       P2 p2 = getArgument<P2>(info, 2); \
948       P3 p3 = getArgument<P3>(info, 3); \
949       impl_##name(p0, p1, p2, p3); \
950       return makeVoid(info); \
951   } \
952   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
953 
954 #define KOALA_INTEROP_V5(name, P0, P1, P2, P3, P4) \
955   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
956       KOALA_MAYBE_LOG(name)                   \
957       CallbackInfo info(env, cbinfo);              \
958       P0 p0 = getArgument<P0>(info, 0); \
959       P1 p1 = getArgument<P1>(info, 1); \
960       P2 p2 = getArgument<P2>(info, 2); \
961       P3 p3 = getArgument<P3>(info, 3); \
962       P4 p4 = getArgument<P4>(info, 4); \
963       impl_##name(p0, p1, p2, p3, p4); \
964       return makeVoid(info); \
965   } \
966   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
967 
968 #define KOALA_INTEROP_V6(name, P0, P1, P2, P3, P4, P5) \
969   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
970       KOALA_MAYBE_LOG(name)                   \
971       CallbackInfo info(env, cbinfo);              \
972       P0 p0 = getArgument<P0>(info, 0); \
973       P1 p1 = getArgument<P1>(info, 1); \
974       P2 p2 = getArgument<P2>(info, 2); \
975       P3 p3 = getArgument<P3>(info, 3); \
976       P4 p4 = getArgument<P4>(info, 4); \
977       P5 p5 = getArgument<P5>(info, 5); \
978       impl_##name(p0, p1, p2, p3, p4, p5); \
979       return makeVoid(info); \
980   } \
981   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
982 
983 #define KOALA_INTEROP_V7(name, P0, P1, P2, P3, P4, P5, P6) \
984   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
985       KOALA_MAYBE_LOG(name)                   \
986       CallbackInfo info(env, cbinfo);              \
987       P0 p0 = getArgument<P0>(info, 0); \
988       P1 p1 = getArgument<P1>(info, 1); \
989       P2 p2 = getArgument<P2>(info, 2); \
990       P3 p3 = getArgument<P3>(info, 3); \
991       P4 p4 = getArgument<P4>(info, 4); \
992       P5 p5 = getArgument<P5>(info, 5); \
993       P6 p6 = getArgument<P6>(info, 6); \
994       impl_##name(p0, p1, p2, p3, p4, p5, p6); \
995       return makeVoid(info); \
996   } \
997   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
998 
999 #define KOALA_INTEROP_V8(name, P0, P1, P2, P3, P4, P5, P6, P7) \
1000   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
1001       KOALA_MAYBE_LOG(name)                   \
1002       CallbackInfo info(env, cbinfo);              \
1003       P0 p0 = getArgument<P0>(info, 0); \
1004       P1 p1 = getArgument<P1>(info, 1); \
1005       P2 p2 = getArgument<P2>(info, 2); \
1006       P3 p3 = getArgument<P3>(info, 3); \
1007       P4 p4 = getArgument<P4>(info, 4); \
1008       P5 p5 = getArgument<P5>(info, 5); \
1009       P6 p6 = getArgument<P6>(info, 6); \
1010       P7 p7 = getArgument<P7>(info, 7); \
1011       impl_##name(p0, p1, p2, p3, p4, p5, p6, p7); \
1012       return makeVoid(info); \
1013   } \
1014   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
1015 
1016 #define KOALA_INTEROP_V9(name, P0, P1, P2, P3, P4, P5, P6, P7, P8) \
1017   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
1018       KOALA_MAYBE_LOG(impl_##name)                   \
1019       CallbackInfo info(env, cbinfo);              \
1020       P0 p0 = getArgument<P0>(info, 0); \
1021       P1 p1 = getArgument<P1>(info, 1); \
1022       P2 p2 = getArgument<P2>(info, 2); \
1023       P3 p3 = getArgument<P3>(info, 3); \
1024       P4 p4 = getArgument<P4>(info, 4); \
1025       P5 p5 = getArgument<P5>(info, 5); \
1026       P6 p6 = getArgument<P6>(info, 6); \
1027       P7 p7 = getArgument<P7>(info, 7); \
1028       P8 p8 = getArgument<P8>(info, 8); \
1029       impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8); \
1030       return makeVoid(info); \
1031   } \
1032   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
1033 
1034 #define KOALA_INTEROP_V10(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \
1035   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
1036       KOALA_MAYBE_LOG(name)                   \
1037       CallbackInfo info(env, cbinfo);              \
1038       P0 p0 = getArgument<P0>(info, 0); \
1039       P1 p1 = getArgument<P1>(info, 1); \
1040       P2 p2 = getArgument<P2>(info, 2); \
1041       P3 p3 = getArgument<P3>(info, 3); \
1042       P4 p4 = getArgument<P4>(info, 4); \
1043       P5 p5 = getArgument<P5>(info, 5); \
1044       P6 p6 = getArgument<P6>(info, 6); \
1045       P7 p7 = getArgument<P7>(info, 7); \
1046       P8 p8 = getArgument<P8>(info, 8); \
1047       P9 p9 = getArgument<P9>(info, 9); \
1048       impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); \
1049       return makeVoid(info); \
1050   } \
1051   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
1052 
1053 #define KOALA_INTEROP_V11(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \
1054   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
1055       KOALA_MAYBE_LOG(impl_##name)                   \
1056       CallbackInfo info(env, cbinfo);              \
1057       P0 p0 = getArgument<P0>(info, 0); \
1058       P1 p1 = getArgument<P1>(info, 1); \
1059       P2 p2 = getArgument<P2>(info, 2); \
1060       P3 p3 = getArgument<P3>(info, 3); \
1061       P4 p4 = getArgument<P4>(info, 4); \
1062       P5 p5 = getArgument<P5>(info, 5); \
1063       P6 p6 = getArgument<P6>(info, 6); \
1064       P7 p7 = getArgument<P7>(info, 7); \
1065       P8 p8 = getArgument<P8>(info, 8); \
1066       P9 p9 = getArgument<P9>(info, 9); \
1067       P10 p10 = getArgument<P10>(info, 10); \
1068       impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \
1069       return makeVoid(info); \
1070   } \
1071   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
1072 
1073 #define KOALA_INTEROP_V12(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) \
1074   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
1075       KOALA_MAYBE_LOG(impl_##name)                   \
1076       CallbackInfo info(env, cbinfo);              \
1077       P0 p0 = getArgument<P0>(info, 0); \
1078       P1 p1 = getArgument<P1>(info, 1); \
1079       P2 p2 = getArgument<P2>(info, 2); \
1080       P3 p3 = getArgument<P3>(info, 3); \
1081       P4 p4 = getArgument<P4>(info, 4); \
1082       P5 p5 = getArgument<P5>(info, 5); \
1083       P6 p6 = getArgument<P6>(info, 6); \
1084       P7 p7 = getArgument<P7>(info, 7); \
1085       P8 p8 = getArgument<P8>(info, 8); \
1086       P9 p9 = getArgument<P9>(info, 9); \
1087       P10 p10 = getArgument<P10>(info, 10); \
1088       P11 p11 = getArgument<P11>(info, 11); \
1089       impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \
1090       return makeVoid(info); \
1091   } \
1092   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
1093 
1094 #define KOALA_INTEROP_V13(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) \
1095   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
1096       KOALA_MAYBE_LOG(impl_##name)                   \
1097       CallbackInfo info(env, cbinfo);              \
1098       P0 p0 = getArgument<P0>(info, 0); \
1099       P1 p1 = getArgument<P1>(info, 1); \
1100       P2 p2 = getArgument<P2>(info, 2); \
1101       P3 p3 = getArgument<P3>(info, 3); \
1102       P4 p4 = getArgument<P4>(info, 4); \
1103       P5 p5 = getArgument<P5>(info, 5); \
1104       P6 p6 = getArgument<P6>(info, 6); \
1105       P7 p7 = getArgument<P7>(info, 7); \
1106       P8 p8 = getArgument<P8>(info, 8); \
1107       P9 p9 = getArgument<P9>(info, 9); \
1108       P10 p10 = getArgument<P10>(info, 10); \
1109       P11 p11 = getArgument<P11>(info, 11); \
1110       P12 p12 = getArgument<P12>(info, 12); \
1111       impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \
1112       return makeVoid(info); \
1113   } \
1114   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
1115 
1116 #define KOALA_INTEROP_V14(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) \
1117   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
1118       KOALA_MAYBE_LOG(name)                   \
1119       CallbackInfo info(env, cbinfo);              \
1120       P0 p0 = getArgument<P0>(info, 0); \
1121       P1 p1 = getArgument<P1>(info, 1); \
1122       P2 p2 = getArgument<P2>(info, 2); \
1123       P3 p3 = getArgument<P3>(info, 3); \
1124       P4 p4 = getArgument<P4>(info, 4); \
1125       P5 p5 = getArgument<P5>(info, 5); \
1126       P6 p6 = getArgument<P6>(info, 6); \
1127       P7 p7 = getArgument<P7>(info, 7); \
1128       P8 p8 = getArgument<P8>(info, 8); \
1129       P9 p9 = getArgument<P9>(info, 9); \
1130       P10 p10 = getArgument<P10>(info, 10); \
1131       P11 p11 = getArgument<P11>(info, 11); \
1132       P12 p12 = getArgument<P12>(info, 12); \
1133       P13 p13 = getArgument<P13>(info, 13); \
1134       impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \
1135       return makeVoid(info); \
1136   } \
1137   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
1138 
1139 #define KOALA_INTEROP_V15(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14) \
1140   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
1141       KOALA_MAYBE_LOG(name)                   \
1142       CallbackInfo info(env, cbinfo);              \
1143       P0 p0 = getArgument<P0>(info, 0); \
1144       P1 p1 = getArgument<P1>(info, 1); \
1145       P2 p2 = getArgument<P2>(info, 2); \
1146       P3 p3 = getArgument<P3>(info, 3); \
1147       P4 p4 = getArgument<P4>(info, 4); \
1148       P5 p5 = getArgument<P5>(info, 5); \
1149       P6 p6 = getArgument<P6>(info, 6); \
1150       P7 p7 = getArgument<P7>(info, 7); \
1151       P8 p8 = getArgument<P8>(info, 8); \
1152       P9 p9 = getArgument<P9>(info, 9); \
1153       P10 p10 = getArgument<P10>(info, 10); \
1154       P11 p11 = getArgument<P11>(info, 11); \
1155       P12 p12 = getArgument<P12>(info, 12); \
1156       P13 p13 = getArgument<P13>(info, 13); \
1157       P14 p14 = getArgument<P14>(info, 14); \
1158       impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \
1159       return makeVoid(info); \
1160   } \
1161   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
1162 
1163 #define KOALA_INTEROP_CTX_0(name, Ret) \
1164   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
1165       KOALA_MAYBE_LOG(impl_##name)                   \
1166       CallbackInfo info(env, cbinfo);              \
1167       KVMContext ctx = reinterpret_cast<KVMContext>((napi_env)info.Env()); \
1168       return makeResult<Ret>(info, impl_##name(ctx)); \
1169   } \
1170   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
1171 
1172 #define KOALA_INTEROP_CTX_1(name, Ret, P0) \
1173   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
1174       KOALA_MAYBE_LOG(impl_##name)                   \
1175       CallbackInfo info(env, cbinfo);              \
1176       KVMContext ctx = reinterpret_cast<KVMContext>((napi_env)info.Env()); \
1177       P0 p0 = getArgument<P0>(info, 0); \
1178       return makeResult<Ret>(info, impl_##name(ctx, p0)); \
1179   } \
1180   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
1181 
1182 #define KOALA_INTEROP_CTX_2(name, Ret, P0, P1) \
1183   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
1184       KOALA_MAYBE_LOG(name)                   \
1185       CallbackInfo info(env, cbinfo);              \
1186       KVMContext ctx = reinterpret_cast<KVMContext>((napi_env)info.Env()); \
1187       P0 p0 = getArgument<P0>(info, 0); \
1188       P1 p1 = getArgument<P1>(info, 1); \
1189       return makeResult<Ret>(info, impl_##name(ctx, p0, p1)); \
1190   } \
1191   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
1192 
1193 #define KOALA_INTEROP_CTX_3(name, Ret, P0, P1, P2) \
1194   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
1195       KOALA_MAYBE_LOG(name)                   \
1196       CallbackInfo info(env, cbinfo);              \
1197       KVMContext ctx = reinterpret_cast<KVMContext>((napi_env)info.Env()); \
1198       P0 p0 = getArgument<P0>(info, 0); \
1199       P1 p1 = getArgument<P1>(info, 1); \
1200       P2 p2 = getArgument<P2>(info, 2); \
1201       return makeResult<Ret>(info, impl_##name(ctx, p0, p1, p2)); \
1202   } \
1203   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
1204 
1205 #define KOALA_INTEROP_CTX_4(name, Ret, P0, P1, P2, P3) \
1206   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
1207       KOALA_MAYBE_LOG(name)                   \
1208       CallbackInfo info(env, cbinfo);              \
1209       KVMContext ctx = reinterpret_cast<KVMContext>((napi_env)info.Env()); \
1210       P0 p0 = getArgument<P0>(info, 0); \
1211       P1 p1 = getArgument<P1>(info, 1); \
1212       P2 p2 = getArgument<P2>(info, 2); \
1213       P3 p3 = getArgument<P3>(info, 3); \
1214       return makeResult<Ret>(info, impl_##name(ctx, p0, p1, p2, p3)); \
1215   } \
1216   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
1217 
1218 #define KOALA_INTEROP_CTX_V0(name) \
1219   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
1220       KOALA_MAYBE_LOG(name)                   \
1221       CallbackInfo info(env, cbinfo);              \
1222       KVMContext ctx = reinterpret_cast<KVMContext>((napi_env)info.Env()); \
1223       impl_##name(ctx); \
1224       return makeVoid(info); \
1225   } \
1226   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
1227 
1228 
1229 #define KOALA_INTEROP_CTX_V1(name, P0) \
1230   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
1231       KOALA_MAYBE_LOG(name)                   \
1232       CallbackInfo info(env, cbinfo);              \
1233       KVMContext ctx = reinterpret_cast<KVMContext>((napi_env)info.Env()); \
1234       P0 p0 = getArgument<P0>(info, 0); \
1235       impl_##name(ctx, p0); \
1236       return makeVoid(info); \
1237   } \
1238   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
1239 
1240 #define KOALA_INTEROP_CTX_V2(name, P0, P1) \
1241   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
1242       KOALA_MAYBE_LOG(name)                   \
1243       CallbackInfo info(env, cbinfo);              \
1244       KVMContext ctx = reinterpret_cast<KVMContext>((napi_env)info.Env()); \
1245       P0 p0 = getArgument<P0>(info, 0); \
1246       P1 p1 = getArgument<P1>(info, 1); \
1247       impl_##name(ctx, p0, p1); \
1248       return makeVoid(info); \
1249   } \
1250   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
1251 
1252 #define KOALA_INTEROP_CTX_V3(name, P0, P1, P2) \
1253   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
1254       KOALA_MAYBE_LOG(name)                   \
1255       CallbackInfo info(env, cbinfo);              \
1256       KVMContext ctx = reinterpret_cast<KVMContext>((napi_env)info.Env()); \
1257       P0 p0 = getArgument<P0>(info, 0); \
1258       P1 p1 = getArgument<P1>(info, 1); \
1259       P2 p2 = getArgument<P2>(info, 2); \
1260       impl_##name(ctx, p0, p1, p2); \
1261       return makeVoid(info); \
1262   } \
1263   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
1264 
1265 #define KOALA_INTEROP_CTX_V4(name, P0, P1, P2, P3) \
1266   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
1267       KOALA_MAYBE_LOG(name)                   \
1268       CallbackInfo info(env, cbinfo);              \
1269       KVMContext ctx = reinterpret_cast<KVMContext>((napi_env)info.Env()); \
1270       P0 p0 = getArgument<P0>(info, 0); \
1271       P1 p1 = getArgument<P1>(info, 1); \
1272       P2 p2 = getArgument<P2>(info, 2); \
1273       P3 p3 = getArgument<P3>(info, 3); \
1274       impl_##name(ctx, p0, p1, p2, p3); \
1275       return makeVoid(info); \
1276   } \
1277   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
1278 
1279 #define KOALA_INTEROP_CTX_V5(name, P0, P1, P2, P3, P4) \
1280   napi_value Node_##name(napi_env env, napi_callback_info cbinfo) { \
1281       KOALA_MAYBE_LOG(name)                   \
1282       CallbackInfo info(env, cbinfo);              \
1283       KVMContext ctx = reinterpret_cast<KVMContext>((napi_env)info.Env()); \
1284       P0 p0 = getArgument<P0>(info, 0); \
1285       P1 p1 = getArgument<P1>(info, 1); \
1286       P2 p2 = getArgument<P2>(info, 2); \
1287       P3 p3 = getArgument<P3>(info, 3); \
1288       P4 p4 = getArgument<P4>(info, 4); \
1289       impl_##name(ctx, p0, p1, p2, p3, p4); \
1290       return makeVoid(info); \
1291   } \
1292   MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name)
1293 
1294 #define NODEJS_GET_AND_THROW_LAST_ERROR(env)                                 \
1295     do {                                                                     \
1296         const napi_extended_error_info *error_info;                          \
1297         napi_get_last_error_info((env), &error_info);                        \
1298         bool is_pending;                                                     \
1299         napi_is_exception_pending((env), &is_pending);                       \
1300         /* If an exception is already pending, don't rethrow it */           \
1301         if (!is_pending) {                                                   \
1302             const char* error_message = error_info->error_message != NULL ?  \
1303             error_info->error_message :                                      \
1304             "empty error message";                                           \
1305             napi_throw_error((env), NULL, error_message);                    \
1306         }                                                                    \
1307     } while (0)
1308 
1309 napi_value getKoalaNapiCallbackDispatcher(napi_env env);
1310 // TODO: can/shall we cache bridge reference?
1311 
1312 #define KOALA_INTEROP_CALL_VOID(venv, id, length, args)                            \
1313 {                                                                                  \
1314   napi_env env = reinterpret_cast<napi_env>(venv);                                 \
1315   napi_value bridge = getKoalaNapiCallbackDispatcher(env),                         \
1316      global = nullptr, return_val = nullptr;                                       \
1317   napi_handle_scope scope = nullptr;                                               \
1318   napi_open_handle_scope(env, &scope);                                             \
1319   napi_status status = napi_get_global(env, &global);                              \
1320   napi_value node_args[3];                                                         \
1321   napi_create_int32(env, id, &node_args[0]);                                       \
1322   napi_value buffer = nullptr;                                                     \
1323   napi_create_external_arraybuffer(env,                                            \
1324     args, length,                                                                  \
1325     [](napi_env, void* data, void* hint) {}, nullptr, &buffer);                    \
1326   napi_create_typedarray(env, napi_uint8_array, length, buffer, 0, &node_args[1]); \
1327   napi_create_int32(env, length, &node_args[2]);                                   \
1328   status = napi_call_function(env, global, bridge, 3, node_args, &return_val);     \
1329   if (status != napi_ok) NODEJS_GET_AND_THROW_LAST_ERROR((env));                   \
1330   napi_close_handle_scope(env, scope);                                             \
1331 }
1332 
1333 #define KOALA_INTEROP_CALL_INT(venv, id, length, args)                             \
1334 {                                                                                  \
1335   napi_env env = reinterpret_cast<napi_env>(venv);                                 \
1336   napi_value bridge = getKoalaNapiCallbackDispatcher(env),                         \
1337      global = nullptr, return_val = nullptr;                                       \
1338   napi_handle_scope scope = nullptr;                                               \
1339   napi_open_handle_scope(env, &scope);                                             \
1340   napi_status status = napi_get_global(env, &global);                              \
1341   napi_value node_args[3];                                                         \
1342   napi_create_int32(env, id, &node_args[0]);                                       \
1343   napi_value buffer = nullptr;                                                     \
1344   napi_create_external_arraybuffer(env,                                            \
1345     args, length,                                                                  \
1346     [](napi_env, void* data, void* hint) {}, nullptr, &buffer);                    \
1347   napi_create_typedarray(env, napi_uint8_array, length, buffer, 0, &node_args[1]); \
1348   napi_create_int32(env, length, &node_args[2]);                                   \
1349   status = napi_call_function(env, global, bridge, 3, node_args, &return_val);     \
1350   if (status != napi_ok) NODEJS_GET_AND_THROW_LAST_ERROR((env));                   \
1351   int result;                                                                      \
1352   status = napi_get_value_int32(env, return_val, &result);                         \
1353   napi_close_handle_scope(env, scope);                                             \
1354   return result;                                                                   \
1355 }
1356 
1357 #define KOALA_INTEROP_CALL_VOID_INTS32(venv, id, argc, args) KOALA_INTEROP_CALL_VOID(venv, id, (argc) * sizeof(int32_t), args)
1358 #define KOALA_INTEROP_CALL_INT_INTS32(venv, id, argc, args) KOALA_INTEROP_CALL_INT(venv, id, (argc) * sizeof(int32_t), args)
1359 
1360 #endif // KOALA_NAPI
1361 
1362 #endif // _CONVERTORS_NAPI_H_