Skip to content
This repository was archived by the owner on Feb 17, 2019. It is now read-only.

n-api: add inheritance example #20

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions inheritance/node-api/binding.gyp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
'targets': [
{
'target_name': 'inheritance',
'sources': [ 'inheritance.c' ]
}
]
}
93 changes: 93 additions & 0 deletions inheritance/node-api/example.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
const addon = require('./build/Release/inheritance.node');

// -----------------------------------------------------------------------------

console.log('Subclass');

let x = new addon.Subclass();

console.log('Construction');

console.log(JSON.stringify(x, null, 4));

x.subclassMethod();

console.log('Subclass method');

console.log(JSON.stringify(x, null, 4));

addon.Subclass.subclassStaticMethod(x);

console.log('Subclass static method');

console.log(JSON.stringify(x, null, 4));

x.superclassOverriddenMethod();

console.log('Superclass overridden method');

console.log(JSON.stringify(x, null, 4));

addon.Subclass.superclassOverriddenStaticMethod(x);

console.log('Superclass overridden static method');

console.log(JSON.stringify(x, null, 4));

x.superclassChainedMethod();

console.log('Superclass chained method');

console.log(JSON.stringify(x, null, 4));

addon.Subclass.superclassChainedStaticMethod(x);

console.log('Superclass chained static method');

console.log(JSON.stringify(x, null, 4));

// -----------------------------------------------------------------------------

console.log('Superclass');

x = new addon.Superclass();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same goes for the above.

I also think some comments on what is being achieved, possibly with the equivalent JavaScript code would also be very useful to help make it obvious what the example is try to show in each case.


console.log('Construction');

console.log(JSON.stringify(x, null, 4));

x.superclassMethod();

console.log('Superclass method');

console.log(JSON.stringify(x, null, 4));

addon.Superclass.superclassStaticMethod(x);

console.log('Superclass static method');

console.log(JSON.stringify(x, null, 4));

x.superclassOverriddenMethod();

console.log('Superclass overridden method');

console.log(JSON.stringify(x, null, 4));

addon.Superclass.superclassOverriddenStaticMethod(x);

console.log('Superclass overridden static method');

console.log(JSON.stringify(x, null, 4));

x.superclassChainedMethod();

console.log('Superclass chained method');

console.log(JSON.stringify(x, null, 4));

addon.Superclass.superclassChainedStaticMethod(x);

console.log('Superclass chained static method');

console.log(JSON.stringify(x, null, 4));
226 changes: 226 additions & 0 deletions inheritance/node-api/inheritance.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
#include "node_api.h"

// Throw an error with a specified message if the N-API call fails.
#define NAPI_CALL_BASE(env, call, message, return_value) \
{ \
napi_status status = call; \
if (status != napi_ok) { \
napi_throw_error((env), NULL, (message)); \
return return_value; \
} \
}

#define NAPI_CALL(env, call, message) \
NAPI_CALL_BASE((env), (call), (message), NULL)

// The last parameter is intentionally empty.
#define NAPI_CALL_VOID(env, call, message) \
NAPI_CALL_BASE((env), (call), (message),)

// Add a property whose name is stored in prefix to the value stored either in
// this, or in the first argument. The value of the property will be `true`.
#define SET_TARGET_PROPERTY(env, use_this, info, prefix) \
{ \
napi_value target, js_true; \
if (use_this) { \
NAPI_CALL((env), \
napi_get_cb_info((env), (info), NULL, NULL, &target, NULL), \
prefix ": Failed to retrieve target via callback info"); \
} else { \
size_t argc = 1; \
NAPI_CALL((env), \
napi_get_cb_info((env), (info), &argc, &target, NULL, NULL), \
prefix ": Failed to retrieve target via callback info"); \
} \
NAPI_CALL(env, napi_get_boolean((env), true, &js_true), \
prefix ": Failed to create boolean value"); \
NAPI_CALL(env, napi_set_named_property((env), target, (prefix), js_true), \
prefix ": Failed to set property"); \
}

// Set super_ctor as the superclass of ctor.
static void napi_inherits(napi_env env, napi_value ctor,
napi_value super_ctor) {
napi_value global, global_object, set_proto, ctor_proto_prop,
super_ctor_proto_prop;
napi_value args[2];

NAPI_CALL_VOID(env, napi_get_global(env, &global),
"napi_inherits: Failed to retrieve global object");
NAPI_CALL_VOID(env, napi_get_named_property(env, global, "Object",
&global_object),
"napi_inherits: Failed to retrieve 'Object' from global");
NAPI_CALL_VOID(env, napi_get_named_property(env, global_object,
"setPrototypeOf", &set_proto),
"napi_inherits: Failed to retrieve 'setPrototypeOf' from 'Object'");
NAPI_CALL_VOID(env,
napi_get_named_property(env, ctor, "prototype",
&ctor_proto_prop),
"napi_inherits: Failed to retrieve 'prototype' from subclass");
NAPI_CALL_VOID(env, napi_get_named_property(env, super_ctor, "prototype",
&super_ctor_proto_prop),
"napi_inherits: Failed to retrieve 'prototype' from superclass");

args[0] = ctor_proto_prop;
args[1] = super_ctor_proto_prop;
NAPI_CALL_VOID(env, napi_call_function(env, global, set_proto, 2, args, NULL),
"napi_inherits: Failed to call 'setPrototypeOf' for prototypes");

args[0] = ctor;
args[1] = super_ctor;
NAPI_CALL_VOID(env, napi_call_function(env, global, set_proto, 2, args, NULL),
"napi_inherits: Failed to call 'setPrototypeOf' for constructors");
}

static napi_value construct_superclass(napi_env env, napi_callback_info info) {
SET_TARGET_PROPERTY(env, true, info, "construct_superclass");
return NULL;
}

static napi_value superclass_method(napi_env env, napi_callback_info info) {
SET_TARGET_PROPERTY(env, true, info, "superclass_method");
return NULL;
}

static napi_value superclass_static_method(napi_env env,
napi_callback_info info) {
SET_TARGET_PROPERTY(env, false, info, "superclass_static_method");
return NULL;
}

static napi_value superclass_overridden_method(napi_env env,
napi_callback_info info) {
SET_TARGET_PROPERTY(env, true, info, "superclass_overridden_method");
return NULL;
}

static napi_value superclass_overridden_static_method(napi_env env,
napi_callback_info info) {
SET_TARGET_PROPERTY(env, false, info,
"superclass_overridden_static_method");
return NULL;
}

static napi_value superclass_chained_method(napi_env env,
napi_callback_info info) {
SET_TARGET_PROPERTY(env, true, info, "superclass_chained_method");
return NULL;
}

static napi_value superclass_chained_static_method(napi_env env,
napi_callback_info info) {
SET_TARGET_PROPERTY(env, false, info, "superclass_chained_static_method");
return NULL;
}

static napi_value construct_subclass(napi_env env, napi_callback_info info) {
construct_superclass(env, info);
SET_TARGET_PROPERTY(env, true, info, "construct_subclass");
return NULL;
}

static napi_value subclass_method(napi_env env, napi_callback_info info) {
SET_TARGET_PROPERTY(env, true, info, "subclass_method");
return NULL;
}

static napi_value subclass_static_method(napi_env env,
napi_callback_info info) {
SET_TARGET_PROPERTY(env, false, info, "subclass_static_method");
return NULL;
}

static napi_value
subclass_superclass_overridden_method(napi_env env, napi_callback_info info) {
SET_TARGET_PROPERTY(env, true, info,
"subclass_superclass_overridden_method");
return NULL;
}

static napi_value
subclass_superclass_overridden_static_method(napi_env env,
napi_callback_info info) {
SET_TARGET_PROPERTY(env, false, info,
"subclass_superclass_overridden_static_method");
return NULL;
}

static napi_value subclass_superclass_chained_method(napi_env env,
napi_callback_info info) {
superclass_chained_method(env, info);
SET_TARGET_PROPERTY(env, true, info,
"subclass_superclass_chained_method");
return NULL;
}

static napi_value
subclass_superclass_chained_static_method(napi_env env,
napi_callback_info info) {
superclass_chained_static_method(env, info);
SET_TARGET_PROPERTY(env, false, info,
"subclass_superclass_chained_static_method");
return NULL;
}

static napi_value Init(napi_env env, napi_value exports) {
napi_value superclass, subclass;

napi_property_descriptor superclass_properties[] = {
{"superclassMethod", NULL, superclass_method, NULL, NULL, NULL,
napi_enumerable, NULL},
{"superclassStaticMethod", NULL, superclass_static_method, NULL, NULL,
NULL, napi_enumerable | napi_static, NULL},
{"superclassOverriddenMethod", NULL, superclass_overridden_method, NULL,
NULL, NULL, napi_enumerable, NULL},
{"superclassOverriddenStaticMethod", NULL,
superclass_overridden_static_method, NULL, NULL, NULL,
napi_enumerable | napi_static, NULL},
{"superclassChainedMethod", NULL, superclass_chained_method, NULL, NULL,
NULL, napi_enumerable, NULL},
{"superclassChainedStaticMethod", NULL, superclass_chained_static_method,
NULL, NULL, NULL, napi_enumerable | napi_static, NULL}};

napi_property_descriptor subclass_properties[] = {
{"subclassMethod", NULL, subclass_method, NULL, NULL, NULL,
napi_enumerable, NULL},
{"subclassStaticMethod", NULL, subclass_static_method, NULL, NULL, NULL,
napi_enumerable | napi_static, NULL},
{"superclassOverriddenMethod", NULL,
subclass_superclass_overridden_method, NULL, NULL, NULL, napi_enumerable,
NULL},
{"superclassOverriddenStaticMethod", NULL,
subclass_superclass_overridden_static_method, NULL, NULL, NULL,
napi_enumerable | napi_static, NULL},
{"superclassChainedMethod", NULL, subclass_superclass_chained_method,
NULL, NULL, NULL, napi_enumerable, NULL},
{"superclassChainedStaticMethod", NULL,
subclass_superclass_chained_static_method, NULL, NULL, NULL,
napi_enumerable | napi_static, NULL}};

NAPI_CALL(env, napi_define_class(env, "Superclass", NAPI_AUTO_LENGTH,
construct_superclass, NULL,
sizeof(superclass_properties) /
sizeof(superclass_properties[0]),
superclass_properties, &superclass),
"Failed to define superclass");

NAPI_CALL(env,
napi_define_class(
env, "Subclass", NAPI_AUTO_LENGTH, construct_subclass, NULL,
sizeof(subclass_properties) / sizeof(subclass_properties[0]),
subclass_properties, &subclass),
"Failed to define subclass");

napi_inherits(env, subclass, superclass);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think using napi_inherits is confusing as it might make people think it is part of the N-API. I suggest. setup_inheritance(


NAPI_CALL(env,
napi_set_named_property(env, exports, "Superclass", superclass),
"Failed to assign superclass to exports");

NAPI_CALL(env, napi_set_named_property(env, exports, "Subclass", subclass),
"Failed to assign subclass to exports");

return exports;
}

NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)