diff options
author | 2022-03-23 04:26:49 -0700 | |
---|---|---|
committer | 2022-03-23 04:26:49 -0700 | |
commit | 07d77c1e00a3c74774ab4ea8c79d5bdeb0d9be4a (patch) | |
tree | 52b4a5c69ac1f0a5433166a92004a3134ba935f2 | |
parent | 5e5f0bd2930a0e1a2f897ba6e857be05e8ca04f2 (diff) | |
download | bun-07d77c1e00a3c74774ab4ea8c79d5bdeb0d9be4a.tar.gz bun-07d77c1e00a3c74774ab4ea8c79d5bdeb0d9be4a.tar.zst bun-07d77c1e00a3c74774ab4ea8c79d5bdeb0d9be4a.zip |
[bun.js] Bun.write for macOS
-rw-r--r-- | integration/bunjs-only-snippets/html-rewriter.test.js | 13 | ||||
-rw-r--r-- | integration/bunjs-only-snippets/response.file.test.js | 50 | ||||
-rw-r--r-- | src/fallback.version | 2 | ||||
-rw-r--r-- | src/javascript/jsc/api/html_rewriter.zig | 18 | ||||
-rw-r--r-- | src/javascript/jsc/api/server.zig | 8 | ||||
-rw-r--r-- | src/javascript/jsc/base.zig | 4 | ||||
-rw-r--r-- | src/javascript/jsc/bindings/bindings.cpp | 16 | ||||
-rw-r--r-- | src/javascript/jsc/bindings/bindings.zig | 11 | ||||
-rw-r--r-- | src/javascript/jsc/bindings/headers-cpp.h | 2 | ||||
-rw-r--r-- | src/javascript/jsc/bindings/headers.h | 4 | ||||
-rw-r--r-- | src/javascript/jsc/bindings/headers.zig | 1 | ||||
-rw-r--r-- | src/javascript/jsc/node/syscall.zig | 2 | ||||
-rw-r--r-- | src/javascript/jsc/webcore/response.zig | 175 | ||||
-rw-r--r-- | src/runtime.version | 2 |
14 files changed, 232 insertions, 76 deletions
diff --git a/integration/bunjs-only-snippets/html-rewriter.test.js b/integration/bunjs-only-snippets/html-rewriter.test.js index bb63d8d25..a4ca965aa 100644 --- a/integration/bunjs-only-snippets/html-rewriter.test.js +++ b/integration/bunjs-only-snippets/html-rewriter.test.js @@ -42,6 +42,19 @@ describe("HTMLRewriter", () => { expect(await output.text()).toBe("<div><blink>it worked!</blink></div>"); }); + it("(from file) supports element handlers", async () => { + var rewriter = new HTMLRewriter(); + rewriter.on("div", { + element(element) { + element.setInnerContent("<blink>it worked!</blink>", { html: true }); + }, + }); + await Bun.write("/tmp/html-rewriter.txt.js", "<div>hello</div>"); + var input = new Response(Bun.file("/tmp/html-rewriter.txt.js")); + var output = rewriter.transform(input); + expect(await output.text()).toBe("<div><blink>it worked!</blink></div>"); + }); + it("supports attribute iterator", async () => { var rewriter = new HTMLRewriter(); var expected = [ diff --git a/integration/bunjs-only-snippets/response.file.test.js b/integration/bunjs-only-snippets/response.file.test.js index f9cb886a2..6e1191433 100644 --- a/integration/bunjs-only-snippets/response.file.test.js +++ b/integration/bunjs-only-snippets/response.file.test.js @@ -10,12 +10,32 @@ it("Bun.write('out.txt', 'string')", async () => { } catch (e) {} } - const out = await Bun.write("/tmp/out.txt", "string"); + await Bun.write("/tmp/out.txt", "string"); + const out = Bun.file("/tmp/out.txt"); expect(await out.text()).toBe("string"); expect(await out.text()).toBe(fs.readFileSync("/tmp/out.txt", "utf8")); } }); +it("Bun.write blob", async () => { + await Bun.write( + Bun.file("/tmp/response-file.test.txt"), + Bun.file(path.join(import.meta.dir, "fetch.js.txt")) + ); + await Bun.write(Bun.file("/tmp/response-file.test.txt"), "blah blah blha"); + await Bun.write( + Bun.file("/tmp/response-file.test.txt"), + new Uint32Array(1024) + ); + await Bun.write("/tmp/response-file.test.txt", new Uint32Array(1024)); + expect( + await Bun.write( + new TextEncoder().encode("/tmp/response-file.test.txt"), + new Uint32Array(1024) + ) + ).toBe(new Uint32Array(1024).byteLength); +}); + it("Bun.file -> Bun.file", async () => { try { fs.unlinkSync(path.join("/tmp", "fetch.js.in")); @@ -33,23 +53,22 @@ it("Bun.file -> Bun.file", async () => { Bun.file("/tmp/fetch.js.out"), Bun.file("/tmp/fetch.js.in") ); - expect(await result.text()).toBe(text); + expect(await Bun.file("/tmp/fetch.js.out").text()).toBe(text); } { - const result = await Bun.write( + await Bun.write( Bun.file("/tmp/fetch.js.in").slice(0, (text.length / 2) | 0), Bun.file("/tmp/fetch.js.out") ); - expect(await result.text()).toBe(text.substring(0, (text.length / 2) | 0)); + expect(await Bun.file("/tmp/fetch.js.in").text()).toBe( + text.substring(0, (text.length / 2) | 0) + ); } { - const result = await Bun.write( - "/tmp/fetch.js.in", - Bun.file("/tmp/fetch.js.out") - ); - expect(await result.text()).toBe(text); + await Bun.write("/tmp/fetch.js.in", Bun.file("/tmp/fetch.js.out")); + expect(await Bun.file("/tmp/fetch.js.in").text()).toBe(text); } }); @@ -99,6 +118,19 @@ it("Response -> Bun.file", async () => { expect(await response.text()).toBe(text); }); +it("Bun.file -> Response", async () => { + // ensure the file doesn't already exist + try { + fs.unlinkSync("/tmp/fetch.js.out"); + } catch {} + + const file = path.join(import.meta.dir, "fetch.js.txt"); + const text = fs.readFileSync(file, "utf8"); + const resp = await fetch("https://example.com"); + expect(await Bun.write("/tmp/fetch.js.out", resp)).toBe(text.length); + expect(await Bun.file("/tmp/fetch.js.out").text()).toBe(text); +}); + it("Response -> Bun.file -> Response -> text", async () => { const file = path.join(import.meta.dir, "fetch.js.txt"); const text = fs.readFileSync(file, "utf8"); diff --git a/src/fallback.version b/src/fallback.version index b07ec851e..36b21d826 100644 --- a/src/fallback.version +++ b/src/fallback.version @@ -1 +1 @@ -3c32b2da4ba87f18
\ No newline at end of file +871e1d1d6a2e7805
\ No newline at end of file diff --git a/src/javascript/jsc/api/html_rewriter.zig b/src/javascript/jsc/api/html_rewriter.zig index a85a62ac8..a9f5f5d48 100644 --- a/src/javascript/jsc/api/html_rewriter.zig +++ b/src/javascript/jsc/api/html_rewriter.zig @@ -303,7 +303,7 @@ pub const HTMLRewriter = struct { const is_pending = input.needsToReadFile(); defer if (!is_pending) input.detach(); - if (input.needsToReadFile()) { + if (is_pending) { input.doReadFileInternal(*BufferOutputSink, sink, onFinishedLoadingWrap, global); } else if (sink.runOutputSink(input.sharedView(), false)) |error_value| { return error_value; @@ -321,8 +321,6 @@ pub const HTMLRewriter = struct { } pub fn onFinishedLoading(sink: *BufferOutputSink, bytes: anyerror![]u8) void { - var input = sink.input; - defer input.detach(); const data = bytes catch |err| { if (sink.response.body.value == .Locked and @ptrToInt(sink.response.body.value.Locked.task) == @ptrToInt(sink)) { sink.response.body.value = .{ .Empty = .{} }; @@ -378,16 +376,10 @@ pub const HTMLRewriter = struct { this.response.body.value = .{ .Blob = JSC.WebCore.Blob.init(bytes, this.bytes.allocator, this.global), }; - - if (prev_value.Locked.promise) |promise| { - prev_value.Locked.promise = null; - promise.asInternalPromise().?.resolve(this.global, JSC.JSValue.fromRef( - Response.makeMaybePooled( - this.global.ref(), - this.response, - ), - )); - } + prev_value.resolve( + &this.response.body.value, + this.global, + ); } pub fn write(this: *BufferOutputSink, bytes: []const u8) void { diff --git a/src/javascript/jsc/api/server.zig b/src/javascript/jsc/api/server.zig index cd769c616..1360f4d52 100644 --- a/src/javascript/jsc/api/server.zig +++ b/src/javascript/jsc/api/server.zig @@ -298,7 +298,7 @@ pub fn NewServer(comptime ssl_enabled: bool) type { } } else { var sbytes: std.os.off_t = adjusted_count; - const signed_offset = @bitCast(i64, this.sendfile.offset); + const signed_offset = @bitCast(i64, @as(u64, this.sendfile.offset)); // var sf_hdr_trailer: std.os.darwin.sf_hdtr = .{ // .headers = &separator_iovec, @@ -320,9 +320,9 @@ pub fn NewServer(comptime ssl_enabled: bool) type { null, 0, )); - - this.sendfile.offset += sbytes; - this.sendfile.remain -= @intCast(JSC.WebCore.Blob.SizeType, sbytes); + const wrote = @intCast(Blob.SizeType, sbytes); + this.sendfile.offset += wrote; + this.sendfile.remain -= wrote; if (errcode != .AGAIN or this.aborted or this.sendfile.remain == 0 or sbytes == 0) { if (errcode != .AGAIN and errcode != .SUCCESS) { Output.prettyErrorln("Error: {s}", .{@tagName(errcode)}); diff --git a/src/javascript/jsc/base.zig b/src/javascript/jsc/base.zig index 0763b5b6d..13de8770d 100644 --- a/src/javascript/jsc/base.zig +++ b/src/javascript/jsc/base.zig @@ -1868,6 +1868,10 @@ pub const ArrayBuffer = extern struct { return this.ptr[this.offset .. this.offset + this.len]; } + pub inline fn byteSlice(this: *const @This()) []u8 { + return this.ptr[this.offset .. this.offset + this.byte_len]; + } + pub inline fn asU16(this: *const @This()) []u16 { return std.mem.bytesAsSlice(u16, @alignCast(@alignOf([*]u16), this.ptr[this.offset..this.byte_len])); } diff --git a/src/javascript/jsc/bindings/bindings.cpp b/src/javascript/jsc/bindings/bindings.cpp index 7036508c4..e4dbdc949 100644 --- a/src/javascript/jsc/bindings/bindings.cpp +++ b/src/javascript/jsc/bindings/bindings.cpp @@ -221,6 +221,12 @@ JSC__JSInternalPromise* JSC__JSValue__asInternalPromise(JSC__JSValue JSValue0) JSC::JSValue value = JSC::JSValue::decode(JSValue0); return JSC::jsCast<JSC::JSInternalPromise*>(value); } + +JSC__JSPromise* JSC__JSValue__asPromise(JSC__JSValue JSValue0) +{ + JSC::JSValue value = JSC::JSValue::decode(JSValue0); + return JSC::jsCast<JSC::JSPromise*>(value); +} JSC__JSValue JSC__JSValue__createInternalPromise(JSC__JSGlobalObject* globalObject) { JSC::VM& vm = globalObject->vm(); @@ -1616,19 +1622,15 @@ int64_t JSC__JSValue__toInt64(JSC__JSValue val) return result; } - if (auto* heapBigInt = _val.asHeapBigInt()) { - if (heapBigInt != nullptr) { + if (_val.isHeapBigInt()) { + + if (auto* heapBigInt = _val.asHeapBigInt()) { return heapBigInt->toBigInt64(heapBigInt); } - } - - - return _val.asAnyInt(); } - JSC__JSValue JSC__JSValue__createObject2(JSC__JSGlobalObject* globalObject, const ZigString* arg1, const ZigString* arg2, JSC__JSValue JSValue3, JSC__JSValue JSValue4) diff --git a/src/javascript/jsc/bindings/bindings.zig b/src/javascript/jsc/bindings/bindings.zig index 0c9449037..0ddd11862 100644 --- a/src/javascript/jsc/bindings/bindings.zig +++ b/src/javascript/jsc/bindings/bindings.zig @@ -1836,6 +1836,7 @@ pub const JSValue = enum(u64) { c_uint => @intCast(c_uint, toU32(this)), c_int => @intCast(c_int, toInt32(this)), ?*JSInternalPromise => asInternalPromise(this), + ?*JSPromise => asPromise(this), // TODO: BigUint64? u64 => @as(u64, toU32(this)), @@ -1935,6 +1936,14 @@ pub const JSValue = enum(u64) { }); } + pub fn asPromise( + value: JSValue, + ) ?*JSPromise { + return cppFn("asPromise", .{ + value, + }); + } + pub fn jsNumber(number: anytype) JSValue { return jsNumberWithType(@TypeOf(number), number); } @@ -2371,7 +2380,7 @@ pub const JSValue = enum(u64) { return @intToPtr(*anyopaque, @enumToInt(this)); } - pub const Extern = [_][]const u8{ "toInt64", "_then", "put", "makeWithNameAndPrototype", "parseJSON", "symbolKeyFor", "symbolFor", "getSymbolDescription", "createInternalPromise", "asInternalPromise", "asArrayBuffer_", "getReadableStreamState", "getWritableStreamState", "fromEntries", "createTypeError", "createRangeError", "createObject2", "getIfPropertyExistsImpl", "jsType", "jsonStringify", "kind_", "isTerminationException", "isSameValue", "getLengthOfArray", "toZigString", "createStringArray", "createEmptyObject", "putRecord", "asPromise", "isClass", "getNameProperty", "getClassName", "getErrorsProperty", "toInt32", "toBoolean", "isInt32", "isIterable", "forEach", "isAggregateError", "toZigException", "isException", "toWTFString", "hasProperty", "getPropertyNames", "getDirect", "putDirect", "getIfExists", "asString", "asObject", "asNumber", "isError", "jsNull", "jsUndefined", "jsTDZValue", "jsBoolean", "jsDoubleNumber", "jsNumberFromDouble", "jsNumberFromChar", "jsNumberFromU16", "jsNumberFromInt32", "jsNumberFromInt64", "jsNumberFromUint64", "isBoolean", "isAnyInt", "isUInt32AsAnyInt", "isInt32AsAnyInt", "isNumber", "isString", "isBigInt", "isHeapBigInt", "isBigInt32", "isSymbol", "isPrimitive", "isGetterSetter", "isCustomGetterSetter", "isObject", "isCell", "asCell", "toString", "toStringOrNull", "toPropertyKey", "toPropertyKeyValue", "toObject", "toString", "getPrototype", "getPropertyByPropertyName", "eqlValue", "eqlCell", "isCallable" }; + pub const Extern = [_][]const u8{ "asPromise", "toInt64", "_then", "put", "makeWithNameAndPrototype", "parseJSON", "symbolKeyFor", "symbolFor", "getSymbolDescription", "createInternalPromise", "asInternalPromise", "asArrayBuffer_", "getReadableStreamState", "getWritableStreamState", "fromEntries", "createTypeError", "createRangeError", "createObject2", "getIfPropertyExistsImpl", "jsType", "jsonStringify", "kind_", "isTerminationException", "isSameValue", "getLengthOfArray", "toZigString", "createStringArray", "createEmptyObject", "putRecord", "asPromise", "isClass", "getNameProperty", "getClassName", "getErrorsProperty", "toInt32", "toBoolean", "isInt32", "isIterable", "forEach", "isAggregateError", "toZigException", "isException", "toWTFString", "hasProperty", "getPropertyNames", "getDirect", "putDirect", "getIfExists", "asString", "asObject", "asNumber", "isError", "jsNull", "jsUndefined", "jsTDZValue", "jsBoolean", "jsDoubleNumber", "jsNumberFromDouble", "jsNumberFromChar", "jsNumberFromU16", "jsNumberFromInt32", "jsNumberFromInt64", "jsNumberFromUint64", "isBoolean", "isAnyInt", "isUInt32AsAnyInt", "isInt32AsAnyInt", "isNumber", "isString", "isBigInt", "isHeapBigInt", "isBigInt32", "isSymbol", "isPrimitive", "isGetterSetter", "isCustomGetterSetter", "isObject", "isCell", "asCell", "toString", "toStringOrNull", "toPropertyKey", "toPropertyKeyValue", "toObject", "toString", "getPrototype", "getPropertyByPropertyName", "eqlValue", "eqlCell", "isCallable" }; }; extern "c" fn Microtask__run(*Microtask, *JSGlobalObject) void; diff --git a/src/javascript/jsc/bindings/headers-cpp.h b/src/javascript/jsc/bindings/headers-cpp.h index bac4b0abf..421914228 100644 --- a/src/javascript/jsc/bindings/headers-cpp.h +++ b/src/javascript/jsc/bindings/headers-cpp.h @@ -1,4 +1,4 @@ -//-- AUTOGENERATED FILE -- 1647946969 +//-- AUTOGENERATED FILE -- 1648033260 // clang-format off #pragma once diff --git a/src/javascript/jsc/bindings/headers.h b/src/javascript/jsc/bindings/headers.h index 4580be974..d04a3dc67 100644 --- a/src/javascript/jsc/bindings/headers.h +++ b/src/javascript/jsc/bindings/headers.h @@ -1,5 +1,5 @@ // clang-format: off -//-- AUTOGENERATED FILE -- 1647946969 +//-- AUTOGENERATED FILE -- 1648033260 #pragma once #include <stddef.h> @@ -434,6 +434,8 @@ CPP_DECL JSC__JSCell* JSC__JSValue__asCell(JSC__JSValue JSValue0); CPP_DECL JSC__JSInternalPromise* JSC__JSValue__asInternalPromise(JSC__JSValue JSValue0); CPP_DECL double JSC__JSValue__asNumber(JSC__JSValue JSValue0); CPP_DECL bJSC__JSObject JSC__JSValue__asObject(JSC__JSValue JSValue0); +CPP_DECL JSC__JSPromise* JSC__JSValue__asPromise(JSC__JSValue JSValue0); +CPP_DECL JSC__JSPromise* JSC__JSValue__asPromise(JSC__JSValue JSValue0); CPP_DECL JSC__JSString* JSC__JSValue__asString(JSC__JSValue JSValue0); CPP_DECL JSC__JSValue JSC__JSValue__createEmptyObject(JSC__JSGlobalObject* arg0, size_t arg1); CPP_DECL JSC__JSValue JSC__JSValue__createInternalPromise(JSC__JSGlobalObject* arg0); diff --git a/src/javascript/jsc/bindings/headers.zig b/src/javascript/jsc/bindings/headers.zig index a82822ed9..8298b8caa 100644 --- a/src/javascript/jsc/bindings/headers.zig +++ b/src/javascript/jsc/bindings/headers.zig @@ -273,6 +273,7 @@ pub extern fn JSC__JSValue__asCell(JSValue0: JSC__JSValue) [*c]JSC__JSCell; pub extern fn JSC__JSValue__asInternalPromise(JSValue0: JSC__JSValue) [*c]JSC__JSInternalPromise; pub extern fn JSC__JSValue__asNumber(JSValue0: JSC__JSValue) f64; pub extern fn JSC__JSValue__asObject(JSValue0: JSC__JSValue) bJSC__JSObject; +pub extern fn JSC__JSValue__asPromise(JSValue0: JSC__JSValue) [*c]JSC__JSPromise; pub extern fn JSC__JSValue__asString(JSValue0: JSC__JSValue) [*c]JSC__JSString; pub extern fn JSC__JSValue__createEmptyObject(arg0: [*c]JSC__JSGlobalObject, arg1: usize) JSC__JSValue; pub extern fn JSC__JSValue__createInternalPromise(arg0: [*c]JSC__JSGlobalObject) JSC__JSValue; diff --git a/src/javascript/jsc/node/syscall.zig b/src/javascript/jsc/node/syscall.zig index 3bd6a8cf7..bac85cce4 100644 --- a/src/javascript/jsc/node/syscall.zig +++ b/src/javascript/jsc/node/syscall.zig @@ -328,7 +328,7 @@ pub fn copyfile(from: [:0]const u8, to: [:0]const u8, flags: c_int) Maybe(void) unreachable; } -pub fn fcopyfile(fd_in: std.os.fd_t, fd_out: std.os.fd_t, flags: c_int) Maybe(void) { +pub fn fcopyfile(fd_in: std.os.fd_t, fd_out: std.os.fd_t, flags: u32) Maybe(void) { if (comptime !Environment.isMac) @compileError("macOS only"); while (true) { diff --git a/src/javascript/jsc/webcore/response.zig b/src/javascript/jsc/webcore/response.zig index 23885a0ea..0c9e71a85 100644 --- a/src/javascript/jsc/webcore/response.zig +++ b/src/javascript/jsc/webcore/response.zig @@ -157,6 +157,12 @@ pub const Response = struct { status_text: string = "", redirected: bool = false, + pub fn getBodyValue( + this: *Response, + ) *Body.Value { + return &this.body.value; + } + pub inline fn statusCode(this: *const Response) u16 { return this.body.init.status_code; } @@ -1995,13 +2001,19 @@ pub const Blob = struct { pub fn getFdMac(this: *This) AsyncIO.OpenError!JSC.Node.FileDescriptor { var buf: [bun.MAX_PATH_BYTES]u8 = undefined; - this.opened_fd = AsyncIO.openSync( - this.file_store.pathlike.path.sliceZ(&buf), - open_flags_, - ) catch |err| { - this.errno = err; - return err; + var path = if (@hasField(This, "file_store")) + this.file_store.pathlike.path.sliceZ(&buf) + else + this.file_blob.store.?.data.file.pathlike.path.sliceZ(&buf); + + this.opened_fd = switch (JSC.Node.Syscall.open(path, open_flags_, JSC.Node.default_permission)) { + .result => |fd| fd, + .err => |err| { + this.errno = AsyncIO.asError(err.errno); + return @errSetCast(AsyncIO.OpenError, this.errno.?); + }, }; + return this.opened_fd; } @@ -2437,8 +2449,8 @@ pub const Blob = struct { onCompleteCallback: OnWriteFileCallback = undefined, wrote: usize = 0, - pub const ResultType = anyerror!Blob; - pub const OnWriteFileCallback = fn (ctx: *anyopaque, blob: ResultType) void; + pub const ResultType = anyerror!SizeType; + pub const OnWriteFileCallback = fn (ctx: *anyopaque, count: ResultType) void; pub usingnamespace FileOpenerMixin(WriteFile); pub usingnamespace FileCloserMixin(WriteFile); @@ -2522,6 +2534,7 @@ pub const Blob = struct { var cb_ctx = this.onCompleteCtx; this.bytes_blob.store.?.deref(); + this.file_blob.store.?.deref(); if (this.errno) |err| { bun.default_allocator.destroy(this); @@ -2529,10 +2542,8 @@ pub const Blob = struct { return; } - var blob = this.file_blob; - bun.default_allocator.destroy(this); - cb(cb_ctx, blob); + cb(cb_ctx, @truncate(SizeType, this.wrote)); } pub fn run(this: *WriteFile, task: *WriteFileTask) void { this.runAsyncFrame = async this.runAsync(task); @@ -2580,7 +2591,7 @@ pub const Blob = struct { if (wrote_len == 0) break; } - this.file_blob.size = @truncate(SizeType, total_written); + this.wrote = @truncate(SizeType, total_written); if (needs_close) { this.doClose() catch {}; @@ -2613,7 +2624,7 @@ pub const Blob = struct { globalThis: *JSGlobalObject, - pub const ResultType = anyerror!Blob; + pub const ResultType = anyerror!SizeType; pub const Callback = fn (ctx: *anyopaque, len: ResultType) void; pub const CopyFilePromiseTask = JSC.ConcurrentPromiseTask(CopyFile); @@ -2651,6 +2662,7 @@ pub const Blob = struct { bun.default_allocator.free(bun.constStrToU8(this.source_file_store.pathlike.path.slice())); } } + this.store.?.deref(); bun.default_allocator.destroy(this); } @@ -2673,21 +2685,14 @@ pub const Blob = struct { } pub fn then(this: *CopyFile, promise: *JSC.JSInternalPromise) void { - defer this.source_store.?.deref(); + this.source_store.?.deref(); if (this.errno != null) { this.reject(promise); return; } - var blob = Blob{ - .offset = this.read_off, - .size = this.read_len, - .store = this.store, - }; - blob.allocator = bun.default_allocator; - var ptr = bun.default_allocator.create(Blob) catch unreachable; - ptr.* = blob; - promise.resolve(this.globalThis, JSC.JSValue.fromRef(Blob.Class.make(this.globalThis.ref(), ptr))); + + promise.resolve(this.globalThis, JSC.JSValue.jsNumberFromUint64(this.read_len)); } pub fn run(this: *CopyFile) void { this.runAsync(); @@ -2802,14 +2807,23 @@ pub const Blob = struct { pub fn doFCopyFile(this: *CopyFile) anyerror!void { switch (JSC.Node.Syscall.fcopyfile(this.source_fd, this.destination_fd, os.system.COPYFILE_DATA)) { - else => |errno| { - this.errno = AsyncIO.asError(errno); + .err => |errno| { + this.errno = AsyncIO.asError(errno.errno); return this.errno.?; }, .result => {}, } } + pub fn doClonefile(this: *CopyFile) anyerror!void { + switch (JSC.Node.Syscall.clonefile(this.destination_file_store.pathlike.path.sliceZAssume(), this.source_file_store.pathlike.path.sliceZAssume())) { + .err => |errno| { + return AsyncIO.asError(errno.errno); + }, + .result => {}, + } + } + pub fn runAsync(this: *CopyFile) void { // defer task.onFinish(); @@ -2829,7 +2843,7 @@ pub const Blob = struct { // First, we attempt to clonefile() on macOS // This is the fastest way to copy a file. if (comptime Environment.isMac) { - if (this.offset == 0) { + if (this.offset == 0 and this.source_file_store.pathlike == .path and this.destination_file_store.pathlike == .path) { do_clonefile: { // stat the output file, make sure it: @@ -2848,12 +2862,12 @@ pub const Blob = struct { }, .err => |err| { // If we can't stat it, we also can't copy it. - this.errno = err; + this.errno = AsyncIO.asError(err.errno); return; }, } - if (this.doCloneFile()) { + if (this.doClonefile()) { if (this.max_length != Blob.max_size and this.max_length < @intCast(SizeType, stat_.?.size)) { // If this fails...well, there's not much we can do about it. _ = bun.C.truncate( @@ -3448,11 +3462,11 @@ pub const Blob = struct { pub const WriteFilePromise = struct { promise: *JSPromise, globalThis: *JSGlobalObject, - pub fn run(handler: *@This(), blob_: Blob.Store.WriteFile.ResultType) void { + pub fn run(handler: *@This(), count: Blob.Store.WriteFile.ResultType) void { var promise = handler.promise; var globalThis = handler.globalThis; bun.default_allocator.destroy(handler); - var blob = blob_ catch |err| { + var wrote = count catch |err| { var error_string = ZigString.init( std.fmt.allocPrint(bun.default_allocator, "Failed to write file \"{s}\"", .{std.mem.span(@errorName(err))}) catch unreachable, ); @@ -3461,10 +3475,7 @@ pub const Blob = struct { return; }; - var ptr = bun.default_allocator.create(Blob) catch unreachable; - ptr.* = blob; - - promise.resolve(globalThis, JSC.JSValue.fromRef(Blob.Class.make(globalThis.ref(), ptr))); + promise.resolve(globalThis, JSC.JSValue.jsNumberFromUint64(wrote)); } }; @@ -3775,7 +3786,7 @@ pub const Blob = struct { JSC.JSValue.JSType.BigUint64Array, JSC.JSValue.JSType.DataView, => { - var buf = try bun.default_allocator.dupe(u8, top_value.asArrayBuffer(global).?.slice()); + var buf = try bun.default_allocator.dupe(u8, top_value.asArrayBuffer(global).?.byteSlice()); return Blob.init(buf, bun.default_allocator, global); }, @@ -3866,7 +3877,7 @@ pub const Blob = struct { JSC.JSValue.JSType.DataView, => { var buf = item.asArrayBuffer(global).?; - joiner.append(buf.slice(), 0, null); + joiner.append(buf.byteSlice(), 0, null); continue; }, .Array, .DerivedArray => { @@ -4073,6 +4084,15 @@ pub const Body = struct { task: ?*anyopaque = null, callback: ?fn (ctx: *anyopaque, value: *Value) void = null, deinit: bool = false, + action: Action = Action.none, + + pub const Action = enum { + none, + getText, + getJSON, + getArrayBuffer, + getBlob, + }; }; pub const Value = union(Tag) { @@ -4091,6 +4111,47 @@ pub const Body = struct { }; pub const empty = Value{ .Empty = .{} }; + + pub fn resolve(this: *Value, new: *Value, global: *JSGlobalObject) void { + if (this.* == .Locked) { + var locked = this.Locked; + if (locked.callback) |callback| { + locked.callback = null; + callback(locked.task.?, new); + } + + if (locked.promise) |promise| { + var blob = new.use(); + + switch (locked.action) { + .getText => { + promise.asPromise().?.resolve(global, JSValue.fromRef(blob.getTextTransfer(global.ref()))); + }, + .getJSON => { + promise.asPromise().?.resolve(global, blob.toJSON(global)); + blob.detach(); + }, + .getArrayBuffer => { + promise.asPromise().?.resolve(global, JSValue.fromRef(blob.getArrayBufferTransfer(global.ref()))); + }, + .getBlob => { + var ptr = bun.default_allocator.create(Blob) catch unreachable; + ptr.* = blob; + ptr.allocator = bun.default_allocator; + promise.asPromise().?.resolve(global, JSC.JSValue.fromRef(Blob.Class.make(global.ref(), ptr))); + }, + else => { + var ptr = bun.default_allocator.create(Blob) catch unreachable; + ptr.* = blob; + ptr.allocator = bun.default_allocator; + promise.asInternalPromise().?.resolve(global, JSC.JSValue.fromRef(Blob.Class.make(global.ref(), ptr))); + }, + } + JSC.C.JSValueUnprotect(global.ref(), promise.asObjectRef()); + locked.promise = null; + } + } + } pub fn slice(this: Value) []const u8 { return switch (this) { .Blob => this.Blob.sharedView(), @@ -4118,8 +4179,9 @@ pub const Body = struct { if (locked.promise) |promise| { if (promise.asInternalPromise()) |internal| { internal.reject(global, error_instance); + } else if (promise.asPromise()) |internal| { + internal.reject(global, error_instance); } - JSC.C.JSValueUnprotect(global.ref(), promise.asObjectRef()); locked.promise = null; } @@ -4535,6 +4597,12 @@ pub const Request = struct { ); } + pub fn getBodyValue( + this: *Request, + ) *Body.Value { + return &this.body; + } + pub fn getBodyUsed( this: *Request, _: js.JSContextRef, @@ -4602,6 +4670,14 @@ fn BlobInterface(comptime Type: type) type { _: []const js.JSValueRef, _: js.ExceptionRef, ) js.JSValueRef { + var value = this.getBodyValue(); + if (value.* == .Locked) { + value.Locked.action = .getText; + var promise = JSC.JSPromise.create(ctx.ptr()); + value.Locked.promise = promise.asValue(ctx.ptr()); + return value.Locked.promise.?.asObjectRef(); + } + var blob = this.body.use(); return blob.getTextTransfer(ctx); } @@ -4614,6 +4690,14 @@ fn BlobInterface(comptime Type: type) type { _: []const js.JSValueRef, exception: js.ExceptionRef, ) js.JSValueRef { + var value = this.getBodyValue(); + if (value.* == .Locked) { + value.Locked.action = .getJSON; + var promise = JSC.JSPromise.create(ctx.ptr()); + value.Locked.promise = promise.asValue(ctx.ptr()); + return value.Locked.promise.?.asObjectRef(); + } + var blob = this.body.use(); return blob.getJSON(ctx, null, null, &.{}, exception); } @@ -4625,6 +4709,15 @@ fn BlobInterface(comptime Type: type) type { _: []const js.JSValueRef, _: js.ExceptionRef, ) js.JSValueRef { + var value = this.getBodyValue(); + + if (value.* == .Locked) { + value.Locked.action = .getArrayBuffer; + var promise = JSC.JSPromise.create(ctx.ptr()); + value.Locked.promise = promise.asValue(ctx.ptr()); + return value.Locked.promise.?.asObjectRef(); + } + var blob = this.body.use(); return blob.getArrayBufferTransfer(ctx); } @@ -4637,6 +4730,14 @@ fn BlobInterface(comptime Type: type) type { _: []const js.JSValueRef, _: js.ExceptionRef, ) js.JSValueRef { + var value = this.getBodyValue(); + if (value.* == .Locked) { + value.Locked.action = .getBlob; + var promise = JSC.JSPromise.create(ctx.ptr()); + value.Locked.promise = promise.asValue(ctx.ptr()); + return value.Locked.promise.?.asObjectRef(); + } + var blob = this.body.use(); var ptr = getAllocator(ctx).create(Blob) catch unreachable; ptr.* = blob; diff --git a/src/runtime.version b/src/runtime.version index fd95ea0a3..0bbf538da 100644 --- a/src/runtime.version +++ b/src/runtime.version @@ -1 +1 @@ -118e8e9b568841b0
\ No newline at end of file +139d399765744be7
\ No newline at end of file |