diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/javascript/jsc/base.zig | 35 | ||||
-rw-r--r-- | src/javascript/jsc/bindings/bindings.zig | 11 | ||||
-rw-r--r-- | src/jsc.zig | 1 | ||||
-rw-r--r-- | src/napi/napi.zig | 122 |
4 files changed, 156 insertions, 13 deletions
diff --git a/src/javascript/jsc/base.zig b/src/javascript/jsc/base.zig index 2e0a723ea..ac2d05106 100644 --- a/src/javascript/jsc/base.zig +++ b/src/javascript/jsc/base.zig @@ -2511,6 +2511,41 @@ comptime { std.testing.refAllDecls(RefString); } +// TODO: remove this abstraction and make it work directly with +pub const ExternalBuffer = struct { + global: *JSC.JSGlobalObject, + ctx: ?*anyopaque = null, + function: JSC.napi.napi_finalize = null, + allocator: std.mem.Allocator, + buf: []u8 = &[_]u8{}, + + pub fn create(ctx: ?*anyopaque, buf: []u8, global: *JSC.JSGlobalObject, function: JSC.napi.napi_finalize, allocator: std.mem.Allocator) !*ExternalBuffer { + var container = try allocator.create(ExternalBuffer); + container.* = .{ + .ctx = ctx, + .global = global, + .allocator = allocator, + .function = function, + .buf = buf, + }; + return container; + } + + pub fn toJS(this: *ExternalBuffer, ctx: *JSC.JSGlobalObject) JSC.JSValue { + return JSC.JSValue.createBufferWithCtx(ctx, this.buf, this.ctx, ExternalBuffer_deallocator); + } + + pub fn toArrayBuffer(this: *ExternalBuffer, ctx: *JSC.JSGlobalObject) JSC.JSValue { + return JSValue.c(JSC.C.JSObjectMakeArrayBufferWithBytesNoCopy(ctx.ref(), this.buf.ptr, this.buf.len, ExternalBuffer_deallocator, this, null)); + } +}; +pub export fn ExternalBuffer_deallocator(bytes_: *anyopaque, ctx: *anyopaque) callconv(.C) void { + var external: *ExternalBuffer = bun.cast(*ExternalBuffer, ctx); + external.function.?(external.global, external.ctx, bytes_); + const allocator = external.allocator; + allocator.destroy(external); +} + pub export fn MarkedArrayBuffer_deallocator(bytes_: *anyopaque, _: *anyopaque) void { const mimalloc = @import("../../allocators/mimalloc.zig"); // zig's memory allocator interface won't work here diff --git a/src/javascript/jsc/bindings/bindings.zig b/src/javascript/jsc/bindings/bindings.zig index eb46837a1..7732a27e3 100644 --- a/src/javascript/jsc/bindings/bindings.zig +++ b/src/javascript/jsc/bindings/bindings.zig @@ -2324,6 +2324,11 @@ pub const JSValue = enum(u64) { return JSC.GetJSPrivateData(ZigType, value.asObjectRef()); } + extern fn JSBuffer__isBuffer(*JSGlobalObject, JSValue) bool; + pub fn isBuffer(value: JSValue, global: *JSGlobalObject) bool { + return JSBuffer__isBuffer(value, global); + } + pub fn asCheckLoaded(value: JSValue, comptime ZigType: type) ?*ZigType { if (!ZigType.Class.isLoaded() or value.isUndefinedOrNull()) return null; @@ -2355,6 +2360,12 @@ pub const JSValue = enum(u64) { } } + pub fn createBufferWithCtx(globalObject: *JSGlobalObject, slice: []u8, ptr: *anyopaque, func: JSC.C.JSTypedArrayBytesDeallocator) JSValue { + if (comptime JSC.is_bindgen) unreachable; + @setRuntimeSafety(false); + return JSBuffer__bufferFromPointerAndLengthAndDeinit(globalObject, slice.ptr, slice.len, ptr, func); + } + extern fn JSBuffer__bufferFromPointerAndLengthAndDeinit(*JSGlobalObject, [*]u8, usize, ?*anyopaque, JSC.C.JSTypedArrayBytesDeallocator) JSValue; pub fn jsNumberWithType(comptime Number: type, number: Number) JSValue { diff --git a/src/jsc.zig b/src/jsc.zig index cd31b206c..fa71683dd 100644 --- a/src/jsc.zig +++ b/src/jsc.zig @@ -1,6 +1,7 @@ // Top-level so it can access all files pub const is_bindgen = @import("std").meta.globalOption("bindgen", bool) orelse false; +pub const napi = @import("./napi/napi.zig"); pub usingnamespace @import("./javascript/jsc/bindings/exports.zig"); pub usingnamespace @import("./javascript/jsc/bindings/bindings.zig"); pub usingnamespace @import("./javascript/jsc/base.zig"); diff --git a/src/napi/napi.zig b/src/napi/napi.zig index f9b772c33..41b1ba225 100644 --- a/src/napi/napi.zig +++ b/src/napi/napi.zig @@ -9,7 +9,7 @@ pub const napi_env = *JSC.JSGlobalObject; pub const napi_ref = struct_napi_ref__; pub const napi_handle_scope = struct_napi_handle_scope__; pub const napi_escapable_handle_scope = struct_napi_escapable_handle_scope__; -pub const napi_callback_info = struct_napi_callback_info__; +pub const napi_callback_info = *JSC.CallFrame; pub const napi_deferred = struct_napi_deferred__; pub const napi_callback_scope = struct_napi_callback_scope__; pub const napi_async_context = struct_napi_async_context__; @@ -22,7 +22,6 @@ pub const napi_value = JSC.JSValue; pub const struct_napi_ref__ = opaque {}; pub const struct_napi_handle_scope__ = opaque {}; pub const struct_napi_escapable_handle_scope__ = opaque {}; -pub const struct_napi_callback_info__ = opaque {}; pub const struct_napi_deferred__ = opaque {}; const char16_t = u16; @@ -58,6 +57,26 @@ pub const napi_typedarray_type = enum(c_uint) { float64_array = 8, bigint64_array = 9, biguint64_array = 10, + + pub fn toJSType(this: napi_typedarray_type) JSC.JSValue.JSType { + return switch (this) { + .int8_array => .Int8Array, + .uint8_array => .Uint8Array, + .uint8_clamped_array => .Uint8ClampedArray, + .int16_array => .Int16Array, + .uint16_array => .Uint16Array, + .int32_array => .Int32Array, + .uint32_array => .Uint32Array, + .float32_array => .Float32Array, + .float64_array => .Float64Array, + .bigint64_array => .BigInt64Array, + .biguint64_array => .BigUint64Array, + }; + } + + pub fn toC(this: napi_typedarray_type) JSC.C.JSTypedArrayType { + return this.toJSType().toC(); + } }; pub const napi_status = enum(c_uint) { ok = 0, @@ -569,28 +588,83 @@ pub export fn napi_is_arraybuffer(_: napi_env, value: napi_value, result: *bool) result.* = value.jsTypeLoose() == .ArrayBuffer; return .ok; } -pub extern fn napi_create_arraybuffer(env: napi_env, byte_length: usize, data: [*]*anyopaque, result: *napi_value) napi_status; -pub extern fn napi_create_external_arraybuffer(env: napi_env, external_data: ?*anyopaque, byte_length: usize, finalize_cb: napi_finalize, finalize_hint: ?*anyopaque, result: *napi_value) napi_status; +pub export fn napi_create_arraybuffer(env: napi_env, byte_length: usize, data: [*]const u8, result: *napi_value) napi_status { + var typed_array = JSC.C.JSObjectMakeTypedArray(env.ref(), .kJSTypedArrayTypeArrayBuffer, byte_length, TODO_EXCEPTION); + var array_buffer = JSValue.c(typed_array).asArrayBuffer(env) orelse return .generic_failure; + @memcpy(array_buffer.ptr, data, @minimum(array_buffer.len, @truncate(u32, byte_length))); + result.* = JSValue.c(typed_array); + return .ok; +} + +pub export fn napi_create_external_arraybuffer(env: napi_env, external_data: ?*anyopaque, byte_length: usize, finalize_cb: napi_finalize, finalize_hint: ?*anyopaque, result: *napi_value) napi_status { + var external = JSC.ExternalBuffer.create( + finalize_hint, + @ptrCast([*]u8, external_data).?[0..byte_length], + finalize_cb, + JSC.VirtualMachine.vm.allocator, + ) catch { + return .generic_failure; + }; + result.* = external.toArrayBuffer(env); + return .ok; +} pub extern fn napi_get_arraybuffer_info(env: napi_env, arraybuffer: napi_value, data: [*]*anyopaque, byte_length: [*c]usize) napi_status; pub export fn napi_is_typedarray(_: napi_env, value: napi_value, result: *bool) napi_status { result.* = value.jsTypeLoose().isTypedArray(); return .ok; } -pub extern fn napi_create_typedarray(env: napi_env, @"type": napi_typedarray_type, length: usize, arraybuffer: napi_value, byte_offset: usize, result: *napi_value) napi_status; +pub export fn napi_create_typedarray(env: napi_env, @"type": napi_typedarray_type, length: usize, arraybuffer: napi_value, byte_offset: usize, result: *napi_value) napi_status { + result.* = JSValue.c( + JSC.C.JSObjectMakeTypedArrayWithArrayBufferAndOffset( + env.ref(), + @"type".toC(), + arraybuffer.asObjectRef(), + byte_offset, + length, + TODO_EXCEPTION, + ), + ); + return .ok; +} pub extern fn napi_get_typedarray_info(env: napi_env, typedarray: napi_value, @"type": [*c]napi_typedarray_type, length: [*c]usize, data: [*]*anyopaque, arraybuffer: *napi_value, byte_offset: [*c]usize) napi_status; pub extern fn napi_create_dataview(env: napi_env, length: usize, arraybuffer: napi_value, byte_offset: usize, result: *napi_value) napi_status; -pub extern fn napi_is_dataview(env: napi_env, value: napi_value, result: *bool) napi_status; +pub export fn napi_is_dataview(_: napi_env, value: napi_value, result: *bool) napi_status { + result.* = value.isEmptyOrUndefinedOrNull() and value.jsTypeLoose() == .DataView; + return .ok; +} pub extern fn napi_get_dataview_info(env: napi_env, dataview: napi_value, bytelength: [*c]usize, data: [*]*anyopaque, arraybuffer: *napi_value, byte_offset: [*c]usize) napi_status; pub extern fn napi_get_version(env: napi_env, result: [*c]u32) napi_status; pub extern fn napi_create_promise(env: napi_env, deferred: [*c]napi_deferred, promise: *napi_value) napi_status; pub extern fn napi_resolve_deferred(env: napi_env, deferred: napi_deferred, resolution: napi_value) napi_status; pub extern fn napi_reject_deferred(env: napi_env, deferred: napi_deferred, rejection: napi_value) napi_status; -pub extern fn napi_is_promise(env: napi_env, value: napi_value, is_promise: *bool) napi_status; +pub export fn napi_is_promise(_: napi_env, value: napi_value, is_promise: *bool) napi_status { + if (value.isEmptyOrUndefinedOrNull()) { + is_promise.* = false; + return .ok; + } + + is_promise.* = value.asPromise() != null or value.asInternalPromise() != null; + return .ok; +} pub extern fn napi_run_script(env: napi_env, script: napi_value, result: *napi_value) napi_status; pub extern fn napi_adjust_external_memory(env: napi_env, change_in_bytes: i64, adjusted_value: [*c]i64) napi_status; -pub extern fn napi_create_date(env: napi_env, time: f64, result: *napi_value) napi_status; -pub extern fn napi_is_date(env: napi_env, value: napi_value, is_date: *bool) napi_status; -pub extern fn napi_get_date_value(env: napi_env, value: napi_value, result: [*c]f64) napi_status; +pub export fn napi_create_date(env: napi_env, time: f64, result: *napi_value) napi_status { + var args = [_]JSC.C.JSValueRef{JSC.JSValue.jsNumber(time)}; + result.* = JSC.C.JSObjectMakeDate(env.ref(), 1, &args, TODO_EXCEPTION); + return .ok; +} +pub export fn napi_is_date(_: napi_env, value: napi_value, is_date: *bool) napi_status { + is_date.* = value.jsTypeLoose() == .JSDate; + return .ok; +} +pub export fn napi_get_date_value(env: napi_env, value: napi_value, result: *f64) napi_status { + const getTimeFunction = value.get(env, "getTime") orelse { + return .date_expected; + }; + + result.* = JSValue.c(JSC.C.JSObjectCallAsFunction(env.ref(), getTimeFunction.asObjectRef(), value.asObjectRef, 0, null, TODO_EXCEPTION)).asNumber(); + return .ok; +} pub extern fn napi_add_finalizer(env: napi_env, js_object: napi_value, native_object: ?*anyopaque, finalize_cb: napi_finalize, finalize_hint: ?*anyopaque, result: [*c]napi_ref) napi_status; pub extern fn napi_create_bigint_int64(env: napi_env, value: i64, result: *napi_value) napi_status; pub extern fn napi_create_bigint_uint64(env: napi_env, value: u64, result: *napi_value) napi_status; @@ -651,9 +725,31 @@ pub extern fn napi_async_init(env: napi_env, async_resource: napi_value, async_r pub extern fn napi_async_destroy(env: napi_env, async_context: napi_async_context) napi_status; pub extern fn napi_make_callback(env: napi_env, async_context: napi_async_context, recv: napi_value, func: napi_value, argc: usize, argv: [*c]const napi_value, result: *napi_value) napi_status; pub extern fn napi_create_buffer(env: napi_env, length: usize, data: [*]*anyopaque, result: *napi_value) napi_status; -pub extern fn napi_create_external_buffer(env: napi_env, length: usize, data: ?*anyopaque, finalize_cb: napi_finalize, finalize_hint: ?*anyopaque, result: *napi_value) napi_status; -pub extern fn napi_create_buffer_copy(env: napi_env, length: usize, data: ?*const anyopaque, result_data: [*]*anyopaque, result: *napi_value) napi_status; -pub extern fn napi_is_buffer(env: napi_env, value: napi_value, result: *bool) napi_status; +pub export fn napi_create_external_buffer(env: napi_env, length: usize, data: ?*anyopaque, finalize_cb: napi_finalize, finalize_hint: ?*anyopaque, result: *napi_value) napi_status { + var buf = JSC.ExternalBuffer.create(finalize_hint, @ptrCast([*]u8, data.?)[0..length], env, finalize_cb, JSC.VirtualMachine.vm.allocator) catch { + return .generic_failure; + }; + + result.* = buf.toJS(env); + return .ok; +} +pub export fn napi_create_buffer_copy(env: napi_env, length: usize, data: [*]u8, result_data: ?*?*anyopaque, result: *napi_value) napi_status { + var duped = JSC.VirtualMachine.vm.allocator.alloc(u8, data[0..length]) catch { + return .generic_failure; + }; + @memcpy(duped.ptr, data, length); + if (result_data) |res| { + res.* = duped.ptr; + } + + result.* = JSC.JSValue.createBuffer(env, duped, JSC.VirtualMachine.vm.allocator); + + return .ok; +} +pub export fn napi_is_buffer(env: napi_env, value: napi_value, result: *bool) napi_status { + result.* = value.isBuffer(env); + return .ok; +} pub extern fn napi_get_buffer_info(env: napi_env, value: napi_value, data: [*]*anyopaque, length: [*c]usize) napi_status; pub extern fn napi_create_async_work(env: napi_env, async_resource: napi_value, async_resource_name: napi_value, execute: napi_async_execute_callback, complete: napi_async_complete_callback, data: ?*anyopaque, result: [*c]napi_async_work) napi_status; pub extern fn napi_delete_async_work(env: napi_env, work: napi_async_work) napi_status; |