Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/wapython
Path: blob/main/core/posix-node/src/node.zig
1067 views
1
// Copyright, SageMath, Inc., 2022
2
// I massively added to and changed this file.
3
//
4
// ORIGINAL Copyright
5
// SPDX-FileCopyrightText: 2021 Coil Technologies, Inc
6
// SPDX-License-Identifier: Apache-2.0
7
8
// I'm halfway through changing a lot of the function names, so there are some major
9
// inconsistencies right now, e.g., stringFromValue vs valueToString. For this,
10
// naming groups similar functions by the *start* of their name.
11
// Also, many of these could take a type as input and be a
12
// a single function instead of a bunch of them.
13
14
// Also, it seems like this should be a big struct with the env as a parameter
15
// to the constructor. Then instead of passing the env as the first param,
16
// you call methods on the struct.
17
18
const std = @import("std");
19
const assert = std.debug.assert;
20
const c = @import("c.zig");
21
const stdio = @cImport(@cInclude("stdio.h"));
22
const util = @import("util.zig");
23
24
const RegisterError = error{ CreateError, SetError };
25
26
pub fn registerFunction(
27
env: c.napi_env,
28
exports: c.napi_value,
29
comptime name: [:0]const u8,
30
comptime function: fn (env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value,
31
) RegisterError!void {
32
var napi_function: c.napi_value = undefined;
33
var status = c.napi_create_function(env, null, 0, function, null, &napi_function);
34
if (status != c.napi_ok) return RegisterError.CreateError;
35
status = c.napi_set_named_property(env, exports, @ptrCast([*c]const u8, name), napi_function);
36
if (status != c.napi_ok) return RegisterError.SetError;
37
}
38
39
pub fn throwError(env: c.napi_env, message: [*:0]const u8) void {
40
var result = c.napi_throw_error(env, null, message);
41
switch (result) {
42
c.napi_ok, c.napi_pending_exception => {},
43
else => unreachable,
44
}
45
}
46
47
// throw error with the Error(message).code specified
48
pub fn throwErrorCode(env: c.napi_env, message: [*:0]const u8, code: [*:0]const u8) void {
49
var result = c.napi_throw_error(env, code, message);
50
switch (result) {
51
c.napi_ok, c.napi_pending_exception => {},
52
else => unreachable,
53
}
54
}
55
56
// throw error with the Error(message).code the string version of a number
57
// char *itoa(int value, char *string, int radix);
58
// "buf is as long as 17 bytes"
59
pub fn throwErrorNumber(env: c.napi_env, message: [*:0]const u8, errcode: i32) void {
60
var buf: [17]u8 = undefined;
61
_ = stdio.sprintf(&buf, "%d", errcode);
62
const result = c.napi_throw_error(env, &buf, message);
63
switch (result) {
64
c.napi_ok, c.napi_pending_exception => {},
65
else => unreachable,
66
}
67
}
68
69
// Throw error but with code set the errno number.
70
pub fn throwErrno(env: c.napi_env, message: [*:0]const u8) void {
71
var buf: [17]u8 = undefined;
72
_ = stdio.sprintf(&buf, "%d", util.getErrno());
73
const result = c.napi_throw_error(env, &buf, message);
74
switch (result) {
75
c.napi_ok, c.napi_pending_exception => {},
76
else => unreachable,
77
}
78
}
79
80
pub fn getArgv(env: c.napi_env, info: c.napi_callback_info, comptime n: usize) ![n]c.napi_value {
81
var argv: [n]c.napi_value = undefined;
82
var argc: usize = n;
83
const status = c.napi_get_cb_info(env, info, &argc, &argv, null, null);
84
if (status != c.napi_ok) {
85
return throw(env, "failed to parse arguments to function");
86
}
87
return argv;
88
}
89
90
const NodeError = error{ ExceptionThrown, MemoryError, LoopError };
91
92
pub fn throw(env: c.napi_env, comptime message: [:0]const u8) NodeError {
93
var result = c.napi_throw_error(env, null, @ptrCast([*c]const u8, message));
94
switch (result) {
95
c.napi_ok, c.napi_pending_exception => {},
96
else => unreachable,
97
}
98
99
return NodeError.ExceptionThrown;
100
}
101
102
pub fn throwMemoryError(env: c.napi_env) NodeError {
103
var result = c.napi_throw_error(env, null, "out of memory");
104
switch (result) {
105
c.napi_ok, c.napi_pending_exception => {},
106
else => unreachable,
107
}
108
109
return NodeError.MemoryError;
110
}
111
112
pub fn captureUndefined(env: c.napi_env) !c.napi_value {
113
var result: c.napi_value = undefined;
114
if (c.napi_get_undefined(env, &result) != c.napi_ok) {
115
return throw(env, "Failed to capture the value of \"undefined\".");
116
}
117
return result;
118
}
119
120
pub fn set_instance_data(
121
env: c.napi_env,
122
data: *anyopaque,
123
finalize_callback: fn (env: c.napi_env, data: ?*anyopaque, hint: ?*anyopaque) callconv(.C) void,
124
) !void {
125
if (c.napi_set_instance_data(env, data, finalize_callback, null) != c.napi_ok) {
126
return throw(env, "Failed to initialize environment.");
127
}
128
}
129
130
pub fn create_external(env: c.napi_env, context: *anyopaque) !c.napi_value {
131
var result: c.napi_value = null;
132
if (c.napi_create_external(env, context, null, null, &result) != c.napi_ok) {
133
return throw(env, "Failed to create external for client context.");
134
}
135
return result;
136
}
137
138
pub fn value_external(
139
env: c.napi_env,
140
value: c.napi_value,
141
comptime error_message: [:0]const u8,
142
) !?*anyopaque {
143
var result: ?*anyopaque = undefined;
144
if (c.napi_get_value_external(env, value, &result) != c.napi_ok) {
145
return throw(env, error_message);
146
}
147
return result;
148
}
149
150
pub const UserData = packed struct {
151
env: c.napi_env,
152
callback_reference: c.napi_ref,
153
};
154
155
/// This will create a reference in V8 with a ref_count of 1.
156
/// This reference will be destroyed when we return the server response to JS.
157
pub fn user_data_from_value(env: c.napi_env, value: c.napi_value) !UserData {
158
var callback_type: c.napi_valuetype = undefined;
159
if (c.napi_typeof(env, value, &callback_type) != c.napi_ok) {
160
return throw(env, "Failed to check callback type.");
161
}
162
if (callback_type != .napi_function) return throw(env, "Callback must be a Function.");
163
164
var callback_reference: c.napi_ref = undefined;
165
if (c.napi_create_reference(env, value, 1, &callback_reference) != c.napi_ok) {
166
return throw(env, "Failed to create reference to callback.");
167
}
168
169
return UserData{
170
.env = env,
171
.callback_reference = callback_reference,
172
};
173
}
174
175
pub fn globals(env: c.napi_env) !?*anyopaque {
176
var data: ?*anyopaque = null;
177
if (c.napi_get_instance_data(env, &data) != c.napi_ok) {
178
return throw(env, "Failed to decode globals.");
179
}
180
181
return data;
182
}
183
184
pub fn slice_from_object(
185
env: c.napi_env,
186
object: c.napi_value,
187
comptime key: [:0]const u8,
188
) ![]const u8 {
189
var property: c.napi_value = undefined;
190
if (c.napi_get_named_property(env, object, key, &property) != c.napi_ok) {
191
return throw(env, key ++ " must be defined");
192
}
193
194
return slice_from_value(env, property, key);
195
}
196
197
pub fn slice_from_value(
198
env: c.napi_env,
199
value: c.napi_value,
200
comptime key: [:0]const u8,
201
) ![]u8 {
202
var is_buffer: bool = undefined;
203
assert(c.napi_is_buffer(env, value, &is_buffer) == .napi_ok);
204
205
if (!is_buffer) return throw(env, key ++ " must be a buffer");
206
207
var data: ?*anyopaque = null;
208
var data_length: usize = undefined;
209
assert(c.napi_get_buffer_info(env, value, &data, &data_length) == .napi_ok);
210
211
if (data_length < 1) return throw(env, key ++ " must not be empty");
212
213
return @ptrCast([*]u8, data.?)[0..data_length];
214
}
215
216
pub fn bytes_from_object(
217
env: c.napi_env,
218
object: c.napi_value,
219
comptime length: u8,
220
comptime key: [:0]const u8,
221
) ![length]u8 {
222
var property: c.napi_value = undefined;
223
if (c.napi_get_named_property(env, object, key, &property) != c.napi_ok) {
224
return throw(env, key ++ " must be defined");
225
}
226
227
const data = try slice_from_value(env, property, key);
228
if (data.len != length) {
229
return throw(env, key ++ " has incorrect length.");
230
}
231
232
// Copy this out of V8 as the underlying data lifetime is not guaranteed.
233
var result: [length]u8 = undefined;
234
std.mem.copy(u8, result[0..], data[0..]);
235
236
return result;
237
}
238
239
pub fn bytes_from_buffer(
240
env: c.napi_env,
241
buffer: c.napi_value,
242
output: []u8,
243
comptime key: [:0]const u8,
244
) !usize {
245
const data = try slice_from_value(env, buffer, key);
246
if (data.len < 1) {
247
return throw(env, key ++ " must not be empty.");
248
}
249
if (data.len > output.len) {
250
return throw(env, key ++ " exceeds max message size.");
251
}
252
253
// Copy this out of V8 as the underlying data lifetime is not guaranteed.
254
std.mem.copy(u8, output[0..], data[0..]);
255
256
return data.len;
257
}
258
259
pub fn u128_from_object(env: c.napi_env, object: c.napi_value, comptime key: [:0]const u8) !u128 {
260
var property: c.napi_value = undefined;
261
if (c.napi_get_named_property(env, object, key, &property) != c.napi_ok) {
262
return throw(env, key ++ " must be defined");
263
}
264
265
return u128_from_value(env, property, key);
266
}
267
268
pub fn u64_from_object(env: c.napi_env, object: c.napi_value, comptime key: [:0]const u8) !u64 {
269
var property: c.napi_value = undefined;
270
if (c.napi_get_named_property(env, object, key, &property) != c.napi_ok) {
271
return throw(env, key ++ " must be defined");
272
}
273
274
return u64_from_value(env, property, key);
275
}
276
277
pub fn u32_from_object(env: c.napi_env, object: c.napi_value, comptime key: [:0]const u8) !u32 {
278
var property: c.napi_value = undefined;
279
if (c.napi_get_named_property(env, object, @ptrCast([*c]const u8, key), &property) != c.napi_ok) {
280
return throw(env, key ++ " must be defined");
281
}
282
283
return u32FromValue(env, property, key);
284
}
285
286
pub fn i32_from_object(env: c.napi_env, object: c.napi_value, comptime key: [:0]const u8) !i32 {
287
var property: c.napi_value = undefined;
288
if (c.napi_get_named_property(env, object, @ptrCast([*c]const u8, key), &property) != c.napi_ok) {
289
return throw(env, key ++ " must be defined");
290
}
291
292
return i32FromValue(env, property, key);
293
}
294
295
pub fn u16_from_object(env: c.napi_env, object: c.napi_value, comptime key: [:0]const u8) !u16 {
296
const result = try u32_from_object(env, object, key);
297
if (result > std.math.maxInt(u16)) {
298
return throw(env, key ++ " must be a u16.");
299
}
300
301
return @intCast(u16, result);
302
}
303
304
pub fn i16_from_object(env: c.napi_env, object: c.napi_value, comptime key: [:0]const u8) !i16 {
305
const result = try i32_from_object(env, object, key);
306
if (result > std.math.maxInt(i16) or result < std.math.minInt(i16)) {
307
return throw(env, key ++ " must be a i16.");
308
}
309
310
return @intCast(i16, result);
311
}
312
313
pub fn u128_from_value(env: c.napi_env, value: c.napi_value, comptime name: [:0]const u8) !u128 {
314
// A BigInt's value (using ^ to mean exponent) is (words[0] * (2^64)^0 + words[1] * (2^64)^1 + ...)
315
316
// V8 says that the words are little endian. If we were on a big endian machine
317
// we would need to convert, but big endian is not supported by tigerbeetle.
318
var result: u128 = 0;
319
var sign_bit: c_int = undefined;
320
const words = @ptrCast(*[2]u64, &result);
321
var word_count: usize = 2;
322
switch (c.napi_get_value_bigint_words(env, value, &sign_bit, &word_count, words)) {
323
.napi_ok => {},
324
.napi_bigint_expected => return throw(env, name ++ " must be a BigInt"),
325
else => unreachable,
326
}
327
if (sign_bit != 0) return throw(env, name ++ " must be positive");
328
if (word_count > 2) return throw(env, name ++ " must fit in 128 bits");
329
330
return result;
331
}
332
333
pub fn u64_from_value(env: c.napi_env, value: c.napi_value, comptime name: [:0]const u8) !u64 {
334
var result: u64 = undefined;
335
var lossless: bool = undefined;
336
switch (c.napi_get_value_bigint_uint64(env, value, &result, &lossless)) {
337
.napi_ok => {},
338
.napi_bigint_expected => return throw(env, name ++ " must be an unsigned 64-bit BigInt"),
339
else => unreachable,
340
}
341
if (!lossless) return throw(env, name ++ " conversion was lossy");
342
343
return result;
344
}
345
346
pub fn u32FromValue(env: c.napi_env, value: c.napi_value, comptime name: [:0]const u8) !u32 {
347
var result: u32 = undefined;
348
// TODO Check whether this will coerce signed numbers to a u32:
349
// In that case we need to use the appropriate napi method to do more type checking here.
350
// We want to make sure this is: unsigned, and an integer.
351
switch (c.napi_get_value_uint32(env, value, &result)) {
352
c.napi_ok => {},
353
c.napi_number_expected => return throw(env, name ++ " must be a number"),
354
else => unreachable,
355
}
356
return result;
357
}
358
359
pub fn i32FromValue(env: c.napi_env, value: c.napi_value, comptime name: [:0]const u8) !i32 {
360
var result: i32 = undefined;
361
switch (c.napi_get_value_int32(env, value, &result)) {
362
c.napi_ok => {},
363
c.napi_number_expected => return throw(env, name ++ " must be a number"),
364
else => unreachable,
365
}
366
return result;
367
}
368
369
pub fn valueToBool(env: c.napi_env, value: c.napi_value, comptime name: [:0]const u8) !bool {
370
var result: bool = undefined;
371
switch (c.napi_get_value_bool(env, value, &result)) {
372
c.napi_ok => {},
373
c.napi_boolean_expected => return throw(env, name ++ " must be bool"),
374
else => unreachable,
375
}
376
return result;
377
}
378
379
pub fn i64FromBigIntValue(env: c.napi_env, value: c.napi_value, comptime name: [:0]const u8) !i64 {
380
var result: i64 = undefined;
381
var lossless: bool = undefined;
382
switch (c.napi_get_value_bigint_int64(env, value, &result, &lossless)) {
383
c.napi_ok => {},
384
c.napi_number_expected => return throw(env, name ++ " must be a BigInt"),
385
else => unreachable,
386
}
387
return result;
388
}
389
390
pub fn stringFromValue(env: c.napi_env, value: c.napi_value, comptime name: [:0]const u8, comptime bufsize: usize, buf: *[bufsize]u8) !void {
391
var result: usize = undefined;
392
if (c.napi_get_value_string_utf8(env, value, buf, bufsize, &result) != c.napi_ok) {
393
return throw(env, name ++ " must be a string");
394
}
395
}
396
397
// node value --> C char *
398
// convert a node value to a null terminated C string. caller must free this using std.c.free.
399
pub fn valueToString(env: c.napi_env, value: c.napi_value, comptime name: [:0]const u8) ![*:0]u8 {
400
var len: usize = undefined;
401
if (c.napi_get_value_string_utf8(env, value, null, 0, &len) != c.napi_ok) {
402
return throw(env, name ++ " must be a string");
403
}
404
var memory = std.c.malloc(len + 1) orelse {
405
return throwMemoryError(env);
406
};
407
var buf = @ptrCast([*:0]u8, memory);
408
var result: usize = undefined;
409
if (c.napi_get_value_string_utf8(env, value, buf, len + 1, &result) != c.napi_ok) {
410
return throw(env, name ++ " must be a string");
411
}
412
return buf;
413
}
414
415
// node value --> C char *const argv[]
416
// convert a node value to a null terminated array of null terminated C strings.
417
// caller must free this using std.c.free; there is a function freeArrayOfStrings
418
// in util.zig that does this:
419
pub fn valueToArrayOfStrings(env: c.napi_env, value: c.napi_value, comptime name: [:0]const u8) ![*](?[*:0]u8) {
420
var len: u32 = undefined;
421
if (c.napi_get_array_length(env, value, &len) != c.napi_ok) {
422
return throw(env, name ++ " must be array of strings (failed to get length)");
423
}
424
var memory = std.c.malloc(@sizeOf(?[*:0]u8) * (len + 1)) orelse {
425
return throwMemoryError(env);
426
};
427
var aligned = @alignCast(std.meta.alignment([*](?[*:0]u8)), memory);
428
var s: [*](?[*:0]u8) = @ptrCast([*](?[*:0]u8), aligned);
429
s[len] = null;
430
var i: u32 = 0;
431
while (i < len) : (i += 1) {
432
var result: c.napi_value = undefined;
433
if (c.napi_get_element(env, value, i, &result) != c.napi_ok) {
434
return throw(env, name ++ " must be array of strings (failed to get element)");
435
}
436
s[i] = try valueToString(env, result, name);
437
}
438
return s;
439
}
440
441
pub fn valueToArrayOfI32(env: c.napi_env, value: c.napi_value, comptime name: [:0]const u8, lenPtr: *u32) ![*]i32 {
442
if (c.napi_get_array_length(env, value, lenPtr) != c.napi_ok) {
443
return throw(env, name ++ " must be array of ints (failed to get length)");
444
}
445
var memory = std.c.malloc(@sizeOf(i32) * lenPtr.*) orelse {
446
return throwMemoryError(env);
447
};
448
var aligned = @alignCast(std.meta.alignment([*]i32), memory);
449
var s: [*]i32 = @ptrCast([*]i32, aligned);
450
var i: u32 = 0;
451
while (i < lenPtr.*) : (i += 1) {
452
var result: c.napi_value = undefined;
453
if (c.napi_get_element(env, value, i, &result) != c.napi_ok) {
454
return throw(env, name ++ " must be array of ints (failed to get element)");
455
}
456
s[i] = try i32FromValue(env, result, "element of array of ints");
457
}
458
return s;
459
}
460
461
pub fn set_named_property_to_byte_slice(
462
env: c.napi_env,
463
object: c.napi_value,
464
comptime key: [:0]const u8,
465
value: []const u8,
466
comptime error_message: [:0]const u8,
467
) !void {
468
var result: c.napi_value = undefined;
469
// create a copy that is managed by V8.
470
if (c.napi_create_buffer_copy(env, value.len, value.ptr, null, &result) != c.napi_ok) {
471
return throw(env, error_message ++ " Failed to allocate Buffer in V8.");
472
}
473
474
if (c.napi_set_named_property(env, object, key, result) != c.napi_ok) {
475
return throw(env, error_message);
476
}
477
}
478
479
pub fn set_named_property_to_u128(
480
env: c.napi_env,
481
object: c.napi_value,
482
comptime key: [:0]const u8,
483
value: u128,
484
comptime error_message: [:0]const u8,
485
) !void {
486
// A BigInt's value (using ^ to mean exponent) is (words[0] * (2^64)^0 + words[1] * (2^64)^1 + ...)
487
488
// V8 says that the words are little endian. If we were on a big endian machine
489
// we would need to convert, but big endian is not supported by tigerbeetle.
490
var bigint: c.napi_value = undefined;
491
if (c.napi_create_bigint_words(
492
env,
493
0,
494
2,
495
@ptrCast(*const [2]u64, &value),
496
&bigint,
497
) != c.napi_ok) {
498
return throw(env, error_message);
499
}
500
501
if (c.napi_set_named_property(env, object, key, bigint) != c.napi_ok) {
502
return throw(env, error_message);
503
}
504
}
505
506
pub fn set_named_property_to_u64(
507
env: c.napi_env,
508
object: c.napi_value,
509
comptime key: [:0]const u8,
510
value: u64,
511
comptime error_message: [:0]const u8,
512
) !void {
513
var result: c.napi_value = undefined;
514
if (c.napi_create_bigint_uint64(env, value, &result) != c.napi_ok) {
515
return throw(env, error_message);
516
}
517
518
if (c.napi_set_named_property(env, object, key, result) != c.napi_ok) {
519
return throw(env, error_message);
520
}
521
}
522
523
pub fn set_named_property_to_u32(
524
env: c.napi_env,
525
object: c.napi_value,
526
comptime key: [:0]const u8,
527
value: u32,
528
comptime error_message: [:0]const u8,
529
) !void {
530
var result: c.napi_value = undefined;
531
if (c.napi_create_uint32(env, value, &result) != c.napi_ok) {
532
return throw(env, error_message);
533
}
534
535
if (c.napi_set_named_property(env, object, @ptrCast([*c]const u8, key), result) != c.napi_ok) {
536
return throw(env, error_message);
537
}
538
}
539
540
pub fn set_named_property_to_i64(
541
env: c.napi_env,
542
object: c.napi_value,
543
comptime key: [:0]const u8,
544
value: i64,
545
comptime error_message: [:0]const u8,
546
) !void {
547
var result: c.napi_value = undefined;
548
if (c.napi_create_int64(env, value, &result) != c.napi_ok) {
549
return throw(env, error_message);
550
}
551
552
if (c.napi_set_named_property(env, object, @ptrCast([*c]const u8, key), result) != c.napi_ok) {
553
return throw(env, error_message);
554
}
555
}
556
557
pub fn setNamedProperty(env: c.napi_env, object: c.napi_value, comptime key: [:0]const u8, value: c.napi_value, comptime error_message: [:0]const u8) !void {
558
if (c.napi_set_named_property(env, object, @ptrCast([*c]const u8, key), value) != c.napi_ok) {
559
return throw(env, "error setting " ++ key ++ " " ++ error_message);
560
}
561
}
562
563
pub fn createObject(env: c.napi_env, comptime error_message: [:0]const u8) !c.napi_value {
564
var result: c.napi_value = undefined;
565
if (c.napi_create_object(env, &result) != c.napi_ok) {
566
return throw(env, error_message);
567
}
568
return result;
569
}
570
571
pub fn create_string(env: c.napi_env, value: [:0]const u8) !c.napi_value {
572
var result: c.napi_value = undefined;
573
if (c.napi_create_string_utf8(env, value, value.len, &result) != c.napi_ok) {
574
return throw(env, "error creating string from pointer");
575
}
576
return result;
577
}
578
579
pub fn strlen(s: [*:0]const u8) usize {
580
var i: usize = 0;
581
while (s[i] != 0) : (i += 1) {}
582
return i;
583
}
584
585
// create nodejs string from null-terminated pointer
586
pub fn createStringFromPtr(env: c.napi_env, value: ?[*:0]const u8, comptime error_message: [:0]const u8) !c.napi_value {
587
const value1 = value orelse {
588
return throw(env, "can't create string from null pointer " ++ error_message);
589
};
590
var result: c.napi_value = undefined;
591
if (c.napi_create_string_utf8(env, value1, strlen(value1), &result) != c.napi_ok) {
592
return throw(env, "error creating string from pointer " ++ error_message);
593
}
594
return result;
595
}
596
597
pub fn create_u32(env: c.napi_env, value: u32, comptime error_message: [:0]const u8) !c.napi_value {
598
var result: c.napi_value = undefined;
599
if (c.napi_create_uint32(env, value, &result) != c.napi_ok) {
600
return throw(env, "error creating u32 " ++ error_message);
601
}
602
return result;
603
}
604
605
pub fn create_i32(env: c.napi_env, value: i32, comptime error_message: [:0]const u8) !c.napi_value {
606
var result: c.napi_value = undefined;
607
if (c.napi_create_int32(env, value, &result) != c.napi_ok) {
608
return throw(env, "error creating i32 " ++ error_message);
609
}
610
return result;
611
}
612
613
pub fn create_bool(env: c.napi_env, value: bool, comptime error_message: [:0]const u8) !c.napi_value {
614
var result: c.napi_value = undefined;
615
if (c.napi_get_boolean(env, value, &result) != c.napi_ok) {
616
return throw(env, "error creating boolean " ++ error_message);
617
}
618
return result;
619
}
620
621
pub fn createBuffer(
622
env: c.napi_env,
623
value: []const u8,
624
comptime error_message: [:0]const u8,
625
) !c.napi_value {
626
var data: ?*anyopaque = undefined;
627
var result: c.napi_value = undefined;
628
if (c.napi_create_buffer(env, value.len, &data, &result) != c.napi_ok) {
629
return throw(env, "error creating buffer " ++ error_message);
630
}
631
632
std.mem.copy(u8, @ptrCast([*]u8, data.?)[0..value.len], value[0..value.len]);
633
634
return result;
635
}
636
637
pub fn createBufferCopy(
638
env: c.napi_env,
639
data: *anyopaque,
640
len: usize,
641
comptime error_message: [:0]const u8,
642
) !c.napi_value {
643
var result: c.napi_value = undefined;
644
if (c.napi_create_buffer_copy(env, len, data, null, &result) != c.napi_ok) {
645
return throw(env, "error creating buffer " ++ error_message);
646
}
647
return result;
648
}
649
650
pub fn createArray(
651
env: c.napi_env,
652
length: u32,
653
comptime error_message: [:0]const u8,
654
) !c.napi_value {
655
var result: c.napi_value = undefined;
656
if (c.napi_create_array_with_length(env, length, &result) != c.napi_ok) {
657
return throw(env, "error creating array " ++ error_message);
658
}
659
660
return result;
661
}
662
663
pub fn setElement(
664
env: c.napi_env,
665
array: c.napi_value,
666
index: u32,
667
value: c.napi_value,
668
comptime error_message: [:0]const u8,
669
) !void {
670
if (c.napi_set_element(env, array, index, value) != c.napi_ok) {
671
return throw(env, error_message);
672
}
673
}
674
675
pub fn getArrayElement(env: c.napi_env, array: c.napi_value, index: u32, comptime message: [:0]const u8) !c.napi_value {
676
var element: c.napi_value = undefined;
677
if (c.napi_get_element(env, array, index, &element) != c.napi_ok) {
678
return throw(env, "failed to get array element " ++ message);
679
}
680
681
return element;
682
}
683
684
pub fn arrayLength(env: c.napi_env, array: c.napi_value, comptime message: [:0]const u8) !u32 {
685
var is_array: bool = undefined;
686
if (c.napi_is_array(env, array, &is_array) != c.napi_ok) {
687
return throw(env, "error determining if it is an array " ++ message);
688
}
689
if (!is_array) {
690
return throw(env, "must be an array " ++ message);
691
}
692
693
var length: u32 = undefined;
694
if (c.napi_get_array_length(env, array, &length) != c.napi_ok) {
695
return throw(env, "failed to get array length " ++ message);
696
}
697
698
return length;
699
}
700
701
pub fn delete_reference(env: c.napi_env, reference: c.napi_ref) !void {
702
if (c.napi_delete_reference(env, reference) != c.napi_ok) {
703
return throw(env, "Failed to delete callback reference.");
704
}
705
}
706
707
pub fn create_error(
708
env: c.napi_env,
709
comptime message: [:0]const u8,
710
) NodeError!c.napi_value {
711
var napi_string: c.napi_value = undefined;
712
if (c.napi_create_string_utf8(env, message, std.mem.len(message), &napi_string) != c.napi_ok) {
713
return NodeError.ExceptionThrown;
714
}
715
716
var napi_error: c.napi_value = undefined;
717
if (c.napi_create_error(env, null, napi_string, &napi_error) != c.napi_ok) {
718
return NodeError.ExceptionThrown;
719
}
720
721
return napi_error;
722
}
723
724
pub fn call_function(
725
env: c.napi_env,
726
this: c.napi_value,
727
callback: c.napi_value,
728
argc: usize,
729
argv: [*]c.napi_value,
730
) !void {
731
const result = c.napi_call_function(env, this, callback, argc, argv, null);
732
switch (result) {
733
.napi_ok => {},
734
// the user's callback may throw a JS exception or call other functions that do so. We
735
// therefore don't throw another error.
736
.napi_pending_exception => {},
737
else => return throw(env, "Failed to invoke results callback."),
738
}
739
}
740
741
pub fn scope(env: c.napi_env, comptime error_message: [:0]const u8) !c.napi_value {
742
var result: c.napi_value = undefined;
743
if (c.napi_get_global(env, &result) != c.napi_ok) {
744
return throw(env, error_message);
745
}
746
747
return result;
748
}
749
750
pub fn reference_value(
751
env: c.napi_env,
752
callback_reference: c.napi_ref,
753
comptime error_message: [:0]const u8,
754
) !c.napi_value {
755
var result: c.napi_value = undefined;
756
if (c.napi_get_reference_value(env, callback_reference, &result) != c.napi_ok) {
757
return throw(env, error_message);
758
}
759
760
return result;
761
}
762
763
// get file descriptors of the streams
764
// process.stdin._handle.fd
765
pub fn getStreamFd(env: c.napi_env, comptime name: [:0]const u8) !c_int {
766
var global: c.napi_value = undefined;
767
if (c.napi_get_global(env, &global) != c.napi_ok) {
768
return throw(env, "failed to get global");
769
}
770
var process: c.napi_value = undefined;
771
if (c.napi_get_named_property(env, global, "process", &process) != c.napi_ok) {
772
return throw(env, name ++ " - failed to get process");
773
}
774
var stream: c.napi_value = undefined;
775
if (c.napi_get_named_property(env, process, @ptrCast([*c]const u8, name), &stream) != c.napi_ok) {
776
return throw(env, name ++ " - failed to get stream");
777
}
778
var _handle: c.napi_value = undefined;
779
if (c.napi_get_named_property(env, stream, "_handle", &_handle) != c.napi_ok) {
780
return throw(env, name ++ " - failed to get _handle");
781
}
782
var fd: c.napi_value = undefined;
783
if (c.napi_get_named_property(env, _handle, "fd", &fd) != c.napi_ok) {
784
return throw(env, name ++ " - failed to get fd");
785
}
786
return try i32FromValue(env, fd, "process." ++ name ++ "._handle.fd");
787
}
788
789
pub fn getNamedProperty(env: c.napi_env, object: c.napi_value, comptime key: [:0]const u8, comptime message: [:0]const u8) !c.napi_value {
790
var result: c.napi_value = undefined;
791
if (c.napi_get_named_property(env, object, @ptrCast([*c]const u8, key), &result) != c.napi_ok) {
792
return throw(env, "getNamedProperty " ++ key ++ " failed -- " ++ message);
793
}
794
return result;
795
}
796
797
pub fn hasNamedProperty(env: c.napi_env, object: c.napi_value, comptime key: [:0]const u8, comptime message: [:0]const u8) !bool {
798
var result: bool = undefined;
799
if (c.napi_has_named_property(env, object, @ptrCast([*c]const u8, key), &result) != c.napi_ok) {
800
return throw(env, "hasOwnProperty " ++ key ++ " failed -- " ++ message);
801
}
802
return result;
803
}
804
805
extern fn uv_loop_close(loop: *c.uv_loop_s) void;
806
pub fn closeEventLoop(env: c.napi_env) !void {
807
//std.debug.print("closeEventLoop\n", .{});
808
var loop: *c.uv_loop_s = undefined;
809
if (c.napi_get_uv_event_loop(env, @ptrCast([*c]?*c.uv_loop_s, &loop)) != c.napi_ok) {
810
std.debug.print("failed to close event loop\n", .{});
811
return throw(env, "failed to close event loop");
812
}
813
uv_loop_close(loop);
814
//c.free(loop);
815
}
816
817