Skip to content
Merged
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
7 changes: 7 additions & 0 deletions examples/basic/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,13 @@ export declare function basic_function(left: number, right: number): number;
*/
export declare function create_function(): CallbackFunction;

/**
* Creates a native reference to the callback, reads it back, and calls it with (1, 2)
* @param cb - A callback function that takes two numbers and returns a number
* @returns The result of calling cb(1, 2)
*/
export declare function call_function_with_reference(cb: CallbackFunction): number;

// ============== Thread Safe Function ==============

/**
Expand Down
2 changes: 2 additions & 0 deletions examples/basic/src/hello.zig
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const buffer = @import("buffer.zig");
const arraybuffer = @import("arraybuffer.zig");
const typedarray = @import("typedarray.zig");
const dataview = @import("dataview.zig");
const reference = @import("reference.zig");

pub const test_i32 = number.test_i32;
pub const test_f32 = number.test_f32;
Expand All @@ -40,6 +41,7 @@ pub const return_nullable = object.return_nullable;
pub const call_function = function.call_function;
pub const basic_function = function.basic_function;
pub const create_function = function.create_function;
pub const call_function_with_reference = reference.call_function_with_reference;

pub const call_thread_safe_function = thread_safe_function.call_thread_safe_function;

Expand Down
11 changes: 11 additions & 0 deletions examples/basic/src/reference.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const napi = @import("napi");

const Args = struct { i32, i32 };

pub fn call_function_with_reference(env: napi.Env, cb: napi.Function(Args, i32)) !i32 {
var reference = try cb.CreateRef();
defer reference.Unref(env) catch @panic("Failed to unref reference");

const function = try reference.GetValue(env);
return try function.Call(.{ 1, 2 });
}
7 changes: 7 additions & 0 deletions harmony_example/entry/src/main/cpp/types/libhello/Index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,13 @@ export declare function basic_function(left: number, right: number): number;
*/
export declare function create_function(): CallbackFunction;

/**
* Creates a native reference to the callback, reads it back, and calls it with (1, 2)
* @param cb - A callback function that takes two numbers and returns a number
* @returns The result of calling cb(1, 2)
*/
export declare function call_function_with_reference(cb: CallbackFunction): number;

// ============== Thread Safe Function ==============

/**
Expand Down
7 changes: 7 additions & 0 deletions src/napi.zig
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const buffer = @import("./napi/wrapper/buffer.zig");
const arraybuffer = @import("./napi/wrapper/arraybuffer.zig");
const typedarray = @import("./napi/wrapper/typedarray.zig");
const dataview = @import("./napi/wrapper/dataview.zig");
const reference = @import("./napi/wrapper/reference.zig");

pub const napi_sys = @import("napi-sys");
pub const Env = env.Env;
Expand Down Expand Up @@ -50,6 +51,12 @@ pub const Float64Array = typedarray.Float64Array;
pub const BigInt64Array = typedarray.BigInt64Array;
pub const BigUint64Array = typedarray.BigUint64Array;
pub const DataView = dataview.DataView;
pub const Reference = reference.Reference;
pub const Ref = reference.Reference;
pub fn FunctionRef(comptime Args: type, comptime Return: type) type {
return reference.Reference(function.Function(Args, Return));
}
pub const ObjectRef = reference.Reference(value.Object);

pub const NODE_API_MODULE = module.NODE_API_MODULE;
pub const NODE_API_MODULE_WITH_INIT = module.NODE_API_MODULE_WITH_INIT;
4 changes: 4 additions & 0 deletions src/napi/util/helper.zig
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ pub fn isDataView(comptime T: type) bool {
return @hasDecl(T, "is_napi_dataview");
}

pub fn isReference(comptime T: type) bool {
return @hasDecl(T, "is_napi_reference");
}

pub fn isArrayList(comptime T: type) bool {
const info = @typeInfo(T);
if (info != .@"struct") {
Expand Down
6 changes: 6 additions & 0 deletions src/napi/util/napi.zig
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ pub const Napi = struct {
if (comptime helper.isDataView(T)) {
return T.from_raw(env, raw);
}
if (comptime helper.isReference(T)) {
return T.from_napi_value(env, raw);
}

if (comptime helper.isTuple(T)) {
return NapiValue.Array.from_napi_value(env, raw, T);
Expand Down Expand Up @@ -210,6 +213,9 @@ pub const Napi = struct {
if (comptime helper.isDataView(value_type)) {
return value.raw;
}
if (comptime helper.isReference(value_type)) {
return try value.to_napi_value(env);
}
if (comptime helper.isTuple(value_type)) {
const array = try NapiValue.Array.New(Env.from_raw(env), value);
return array.raw;
Expand Down
5 changes: 5 additions & 0 deletions src/napi/value/function.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const Napi = @import("../util/napi.zig").Napi;
const NapiError = @import("../wrapper/error.zig");
const Undefined = @import("./undefined.zig").Undefined;
const GlobalAllocator = @import("../util/allocator.zig");
const Reference = @import("../wrapper/reference.zig").Reference;

pub fn Function(comptime Args: type, comptime Return: type) type {
const ArgsInfos = @typeInfo(Args);
Expand Down Expand Up @@ -135,5 +136,9 @@ pub fn Function(comptime Args: type, comptime Return: type) type {

return Napi.from_napi_value(self.env, result, Return);
}

pub fn CreateRef(self: Self) !Reference(Self) {
return Reference(Self).New(Env.from_raw(self.env), self);
}
};
}
5 changes: 5 additions & 0 deletions src/napi/value/object.zig
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const String = @import("./string.zig").String;
const helper = @import("../util/helper.zig");
const Napi = @import("../util/napi.zig").Napi;
const NapiError = @import("../wrapper/error.zig");
const Reference = @import("../wrapper/reference.zig").Reference;

pub const Object = struct {
env: napi.napi_env,
Expand Down Expand Up @@ -158,4 +159,8 @@ pub const Object = struct {
}
return result;
}

pub fn CreateRef(self: Object) !Reference(Object) {
return Reference(Object).New(Env.from_raw(self.env), self);
}
};
12 changes: 0 additions & 12 deletions src/napi/wrapper/dataview.zig
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,6 @@ pub const DataView = struct {
return DataView.from_raw(env.raw, raw);
}

pub fn from_arraybuffer(env: Env, arraybuffer: ArrayBuffer, byte_offset: usize, byte_length: usize) !DataView {
return DataView.fromArrayBuffer(env, arraybuffer, byte_offset, byte_length);
}

pub fn New(env: Env, byte_length: usize) !DataView {
const arraybuffer = try ArrayBuffer.New(env, byte_length);
return DataView.fromArrayBuffer(env, arraybuffer, 0, byte_length);
Expand All @@ -75,19 +71,11 @@ pub const DataView = struct {
return DataView.fromArrayBuffer(env, arraybuffer, 0, data.len);
}

pub fn copy_from(env: Env, data: []const u8) !DataView {
return DataView.copy(env, data);
}

pub fn from(env: Env, data: []u8) !DataView {
const arraybuffer = try ArrayBuffer.from(env, data);
return DataView.fromArrayBuffer(env, arraybuffer, 0, data.len);
}

pub fn from_data(env: Env, data: []u8) !DataView {
return DataView.from(env, data);
}

pub fn asSlice(self: DataView) []u8 {
return self.data[0..self.byte_length];
}
Expand Down
113 changes: 113 additions & 0 deletions src/napi/wrapper/reference.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
const napi = @import("napi-sys").napi_sys;
const Env = @import("../env.zig").Env;
const NapiError = @import("./error.zig");
pub fn Reference(comptime T: type) type {
if (!@hasDecl(T, "from_raw")) {
@compileError("Reference(T) requires T.from_raw");
}
if (!@hasField(T, "raw")) {
@compileError("Reference(T) requires T.raw");
}

return struct {
pub const is_napi_reference = true;
pub const referenced_type = T;

raw_ref: napi.napi_ref,
taken: bool,

const Self = @This();

pub fn from_raw(env: napi.napi_env, raw: napi.napi_ref) Self {
_ = env;
return Self{
.raw_ref = raw,
.taken = false,
};
}

pub fn New(env: Env, value: T) !Self {
var raw_ref: napi.napi_ref = undefined;
const status = napi.napi_create_reference(env.raw, value.raw, 1, &raw_ref);
if (status != napi.napi_ok) {
return NapiError.Error.fromStatus(NapiError.Status.New(status));
}

return Self.from_raw(env.raw, raw_ref);
}

pub fn from_napi_value(env: napi.napi_env, raw_value: napi.napi_value) Self {
const value = T.from_raw(env, raw_value);
return Self.New(Env.from_raw(env), value) catch @panic("Failed to create reference");
}

pub fn to_napi_value(self: Self, env: napi.napi_env) !napi.napi_value {
return try self.get_raw_value(Env.from_raw(env));
}

fn get_raw_value(self: Self, env: Env) !napi.napi_value {
if (self.taken) {
return NapiError.Error.fromStatus(@as([]const u8, "Ref value has been deleted"));
}

var raw_value: napi.napi_value = undefined;
const status = napi.napi_get_reference_value(env.raw, self.raw_ref, &raw_value);
if (status != napi.napi_ok) {
return NapiError.Error.fromStatus(NapiError.Status.New(status));
}

if (raw_value == null) {
return NapiError.Error.fromStatus(NapiError.Status.InvalidArg);
}

return raw_value;
}

pub fn get_value(self: Self, env: Env) !T {
const raw_value = try self.get_raw_value(env);
return T.from_raw(env.raw, raw_value);
}

pub fn GetValue(self: Self, env: Env) !T {
const raw_value = try self.get_raw_value(env);
return T.from_raw(env.raw, raw_value);
}

pub fn Unref(self: *Self, env: Env) !void {
if (self.taken or self.raw_ref == null) {
return NapiError.Error.fromStatus(@as([]const u8, "Ref value has been deleted"));
}

var count: u32 = 0;
const unref_status = napi.napi_reference_unref(env.raw, self.raw_ref, &count);
if (unref_status != napi.napi_ok) {
return NapiError.Error.fromStatus(NapiError.Status.New(unref_status));
}

const delete_status = napi.napi_delete_reference(env.raw, self.raw_ref);
if (delete_status != napi.napi_ok) {
return NapiError.Error.fromStatus(NapiError.Status.New(delete_status));
}

self.taken = true;
self.raw_ref = null;
}

pub fn Ref(self: *Self, env: Env) !u32 {
if (self.taken or self.raw_ref == null) {
return NapiError.Error.fromStatus(@as([]const u8, "Ref value has been deleted"));
}

var count: u32 = 0;
const status = napi.napi_reference_ref(env.raw, self.raw_ref, &count);
if (status != napi.napi_ok) {
return NapiError.Error.fromStatus(NapiError.Status.New(status));
}
return count;
}

pub fn Delete(self: *Self, env: Env) !void {
return Self.Unref(self, env);
}
};
}
12 changes: 0 additions & 12 deletions src/napi/wrapper/typedarray.zig
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,6 @@ pub fn TypedArray(comptime T: type) type {
return Self.from_raw(env.raw, raw);
}

pub fn from_arraybuffer(env: Env, arraybuffer: ArrayBuffer, len: usize, byte_offset: usize) !Self {
return Self.fromArrayBuffer(env, arraybuffer, len, byte_offset);
}

pub fn New(env: Env, len: usize) !Self {
const arraybuffer = try ArrayBuffer.New(env, len * @sizeOf(T));
return Self.fromArrayBuffer(env, arraybuffer, len, 0);
Expand All @@ -120,19 +116,11 @@ pub fn TypedArray(comptime T: type) type {
return result;
}

pub fn copy_from(env: Env, data: []const T) !Self {
return Self.copy(env, data);
}

pub fn from(env: Env, data: []T) !Self {
const arraybuffer = try ArrayBuffer.from(env, std.mem.sliceAsBytes(data));
return Self.fromArrayBuffer(env, arraybuffer, data.len, 0);
}

pub fn from_data(env: Env, data: []T) !Self {
return Self.from(env, data);
}

pub fn asSlice(self: Self) []T {
return self.data[0..self.len];
}
Expand Down