Fix failing tests for ReadableStream -> {text, arrayBuffer, blob}

This commit is contained in:
Jarred Sumner
2022-07-01 03:24:16 -07:00
parent e105cfcca8
commit 4812fb8faf
6 changed files with 1893 additions and 1474 deletions

View File

@@ -1,5 +1,16 @@
# JavaScript Builtins
TLDR:
```bash
# Delete the built files
make clean-bindings generate-bindings && \
# Compile all the C++ files which live in ../bindings
make jsc-bindings-mac -j10 && \
# Re-link the binary without compiling zig (so it's faster)
make bun-link-lld-debug
```
JavaScript files in [./js](./js) use JavaScriptCore's builtins syntax
```js

View File

@@ -35,9 +35,9 @@
#include "ByteLengthQueuingStrategyBuiltins.cpp"
#include "CountQueuingStrategyBuiltins.cpp"
#include "ImportMetaObjectBuiltins.cpp"
#include "JSBufferConstructorBuiltins.cpp"
#include "JSBufferPrototypeBuiltins.cpp"
#include "JSZigGlobalObjectBuiltins.cpp"
#include "ReadableByteStreamControllerBuiltins.cpp"
#include "ReadableByteStreamInternalsBuiltins.cpp"
#include "ReadableStreamBYOBReaderBuiltins.cpp"

View File

@@ -104,53 +104,11 @@ function readableStreamToArray(stream) {
// this is a direct stream
var underlyingSource = @getByIdDirectPrivate(stream, "underlyingSource");
if (underlyingSource !== @undefined) {
const promise = @initializeArrayStream.@call(stream, underlyingSource, @undefined);
var reader = stream.getReader();
return (async function() {
while (@getByIdDirectPrivate(stream, "state") === @streamReadable) {
var thisResult = await reader.read();
if (thisResult.done) {
break;
}
}
try {
reader.releaseLock();
} catch(e) {
}
return await promise;
})();
if (underlyingSource !== @undefined) {
return @readableStreamToArrayDirect(stream, underlyingSource);
}
var reader = stream.getReader();
var manyResult = reader.readMany();
async function processManyResult(result) {
if (result.done) {
return [];
}
var chunks = result.value || [];
while (true) {
var thisResult = await reader.read();
if (thisResult.done) {
break;
}
chunks = chunks.concat(thisResult.value);
}
return chunks;
}
if (manyResult && @isPromise(manyResult)) {
return manyResult.@then(processManyResult);
}
return processManyResult(manyResult);
return @readableStreamIntoArray(stream);
}
@globalPrivate
@@ -160,73 +118,37 @@ function readableStreamToText(stream) {
// this is a direct stream
var underlyingSource = @getByIdDirectPrivate(stream, "underlyingSource");
if (underlyingSource !== @undefined) {
const promise = @initializeTextStream.@call(stream, underlyingSource, @undefined);
var reader = stream.getReader();
return (async function() {
while (@getByIdDirectPrivate(stream, "state") === @streamReadable) {
var thisResult = await reader.read();
if (thisResult.done) {
break;
}
}
try {
reader.releaseLock();
} catch(e) {
}
return await promise;
})();
return @readableStreamToTextDirect(stream, underlyingSource);
}
// TODO: optimize this to skip the extra ArrayBuffer
var toArrayBuffer = globalThis.Bun.readableStreamToArrayBuffer(stream);
if (toArrayBuffer && @isPromise(toArrayBuffer)) {
return toArrayBuffer.@then(function(arrayBuffer) {
return new globalThis.TextDecoder().decode(arrayBuffer);
});
return @readableStreamIntoText(stream);
}
@globalPrivate
function readableStreamToArrayBuffer(stream) {
"use strict";
// this is a direct stream
var underlyingSource = @getByIdDirectPrivate(stream, "underlyingSource");
if (underlyingSource !== @undefined) {
return @readableStreamToArrayBufferDirect(stream, underlyingSource);
}
return new globalThis.TextDecoder().decode(arrayBuffer);
return globalThis.Bun.readableStreamToArray(stream).@then(globalThis.Bun.concatArrayBuffers);
}
@globalPrivate
function readableStreamToJSON(stream) {
"use strict";
return @readableStreamToText(stream).@then(globalThis.JSON.parse);
return globalThis.Bun.readableStreamToText(stream).@then(globalThis.JSON.parse);
}
@globalPrivate
function readableStreamToBlob(stream) {
"use strict";
var underlyingSource = @getByIdDirectPrivate(stream, "underlyingSource");
if (underlyingSource != @undefined) {
var toArrayBuffer = globalThis.Bun.readableStreamToArrayBuffer(stream);
if (toArrayBuffer && @isPromise(toArrayBuffer)) {
return toArrayBuffer.@then(function(arrayBuffer) {
return new globalThis.Blob([arrayBuffer]);
});
}
return new globalThis.Blob([toArrayBuffer]);
}
const array = @readableStreamToArray(stream);
if (array === null) {
return new globalThis.Blob();
}
return array.@then(function(chunks) {
if (chunks === null || chunks.length === 0) {
return new globalThis.Blob();
}
return new globalThis.Blob(chunks);
});
return @Promise.resolve(globalThis.Bun.readableStreamToArray(stream)).@then(array => new Blob(array));
}
@globalPrivate
@@ -459,7 +381,7 @@ function pipeTo(destination)
// FIXME: https://bugs.webkit.org/show_bug.cgi?id=159869.
// Built-in generator should be able to parse function signature to compute the function length correctly.
let options = arguments[1];
let options = @argument(1);
let preventClose = false;
let preventAbort = false;

File diff suppressed because it is too large Load Diff

View File

@@ -56,6 +56,7 @@ pub const TextEncoder = struct {
// unless it's huge
// JSC will GC Uint8Array that occupy less than 512 bytes
// so it's extra good for that case
// this also means there won't be reallocations for small strings
var buf: [2048]u8 = undefined;
var ctx = globalThis.ref();

View File

@@ -1749,6 +1749,7 @@ pub fn HTTPServerWritable(comptime ssl: bool) type {
return .{ .owned = @truncate(Blob.SizeType, written) };
}
// In this case, it's always an error
pub fn end(this: *@This(), err: ?JSC.Node.Syscall.Error) JSC.Node.Maybe(void) {
log("end({s})", .{err});
@@ -1770,7 +1771,8 @@ pub fn HTTPServerWritable(comptime ssl: bool) type {
if (readable.len == 0) {
this.signal.close(err);
this.done = true;
this.res.endStream(false);
// we do not close the stream here
// this.res.endStream(false);
this.finalize();
return .{ .result = {} };
}
@@ -1778,6 +1780,10 @@ pub fn HTTPServerWritable(comptime ssl: bool) type {
if (!this.hasBackpressure()) {
if (this.send(readable)) {
this.handleWrote(readable.len);
this.signal.close(err);
this.done = true;
this.res.endStream(false);
this.finalize();
return .{ .result = {} };
}
@@ -1852,6 +1858,8 @@ pub fn HTTPServerWritable(comptime ssl: bool) type {
this.finalize();
}
// This can be called _many_ times for the same instance
// so it must zero out state instead of make it
pub fn finalize(this: *@This()) void {
log("finalize()", .{});
@@ -1866,7 +1874,7 @@ pub fn HTTPServerWritable(comptime ssl: bool) type {
this.buffer = bun.ByteList.init("");
this.pooled_buffer = null;
pooled.release();
} else if (!ByteListPool.full()) {
} else if (this.buffer.cap == 0) {} else if (!ByteListPool.full()) {
var entry = ByteListPool.get(this.allocator);
entry.data = this.buffer;
this.buffer = bun.ByteList.init("");