aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-01-29 22:33:37 -0800
committerGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-01-29 22:33:37 -0800
commit703bee976b9961a3cccc96c371c833546f3505d9 (patch)
treece531762755f626837c593310e4264be1b1f9325 /src/bun.js
parenteb5105aa09767da7d015299f956ed0fdfdffb386 (diff)
downloadbun-703bee976b9961a3cccc96c371c833546f3505d9.tar.gz
bun-703bee976b9961a3cccc96c371c833546f3505d9.tar.zst
bun-703bee976b9961a3cccc96c371c833546f3505d9.zip
[breaking] Add `binaryType` option to Bun.connect & Bun.listen
This is a breaking change because the default is `Buffer`, but previously the default was `Uint8Array`. While `Buffer` is a subclass of `Uint8Array`, it still technically is a breaking change because `slice` in `Uint8Array` is not semantically identical to `slice` in `Buffer` cc @colinhacks, the .d.ts changes I made here aren't great.
Diffstat (limited to 'src/bun.js')
-rw-r--r--src/bun.js/api/bun/socket.zig22
-rw-r--r--src/bun.js/base.zig99
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.cpp7
-rw-r--r--src/bun.js/bindings/bindings.zig1
-rw-r--r--src/bun.js/bindings/generated_classes.zig4
-rw-r--r--src/bun.js/net.exports.js11
6 files changed, 129 insertions, 15 deletions
diff --git a/src/bun.js/api/bun/socket.zig b/src/bun.js/api/bun/socket.zig
index 925db901d..cf482e242 100644
--- a/src/bun.js/api/bun/socket.zig
+++ b/src/bun.js/api/bun/socket.zig
@@ -65,6 +65,9 @@ fn normalizeHost(input: anytype) @TypeOf(input) {
return input;
}
+
+const BinaryType = JSC.BinaryType;
+
const Handlers = struct {
onOpen: JSC.JSValue = .zero,
onClose: JSC.JSValue = .zero,
@@ -75,7 +78,7 @@ const Handlers = struct {
onEnd: JSC.JSValue = .zero,
onError: JSC.JSValue = .zero,
- encoding: JSC.Node.Encoding = .utf8,
+ binary_type: BinaryType = .Buffer,
vm: *JSC.VirtualMachine,
globalObject: *JSC.JSGlobalObject,
@@ -150,7 +153,6 @@ const Handlers = struct {
.{ "onWritable", "drain" },
.{ "onOpen", "open" },
.{ "onClose", "close" },
- .{ "onData", "data" },
.{ "onTimeout", "timeout" },
.{ "onConnectError", "connectError" },
.{ "onEnd", "end" },
@@ -172,6 +174,18 @@ const Handlers = struct {
return null;
}
+ if (opts.getTruthy(globalObject, "binaryType")) |binary_type_value| {
+ if (!binary_type_value.isString()) {
+ exception.* = JSC.toInvalidArguments("Expected \"binaryType\" to be a string", .{}, globalObject).asObjectRef();
+ return null;
+ }
+
+ handlers.binary_type = BinaryType.fromJSValue(globalObject, binary_type_value) orelse {
+ exception.* = JSC.toInvalidArguments("Expected 'binaryType' to be 'arraybuffer', 'uint8array', 'buffer'", .{}, globalObject).asObjectRef();
+ return null;
+ };
+ }
+
return handlers;
}
@@ -1144,7 +1158,7 @@ fn NewSocket(comptime ssl: bool) type {
const globalObject = handlers.globalObject;
const this_value = this.getThisValue(globalObject);
- const output_value = JSC.ArrayBuffer.create(globalObject, data, .Uint8Array);
+ const output_value = handlers.binary_type.toJS(data, globalObject);
// const encoding = handlers.encoding;
const result = callback.callWithThis(globalObject, this_value, &[_]JSValue{
this_value,
@@ -1288,7 +1302,7 @@ fn NewSocket(comptime ssl: bool) type {
}
// we don't cork yet but we might later
const res = this.socket.write(buffer, is_end);
- log("write({d}, {any})", .{ buffer.len, is_end });
+ log("write({d}, {any}) = {d}", .{ buffer.len, is_end, res });
return res;
}
diff --git a/src/bun.js/base.zig b/src/bun.js/base.zig
index f2a305564..10a182c60 100644
--- a/src/bun.js/base.zig
+++ b/src/bun.js/base.zig
@@ -1715,13 +1715,18 @@ pub const ArrayBuffer = extern struct {
pub fn create(globalThis: *JSC.JSGlobalObject, bytes: []const u8, comptime kind: JSC.JSValue.JSType) JSValue {
JSC.markBinding(@src());
return switch (comptime kind) {
- .Uint8Array => Bun__createUint8ArrayForCopy(globalThis, bytes.ptr, bytes.len),
+ .Uint8Array => Bun__createUint8ArrayForCopy(globalThis, bytes.ptr, bytes.len, false),
.ArrayBuffer => Bun__createArrayBufferForCopy(globalThis, bytes.ptr, bytes.len),
else => @compileError("Not implemented yet"),
};
}
- extern "C" fn Bun__createUint8ArrayForCopy(*JSC.JSGlobalObject, ptr: ?*const anyopaque, len: usize) JSValue;
+ pub fn createBuffer(globalThis: *JSC.JSGlobalObject, bytes: []const u8) JSValue {
+ JSC.markBinding(@src());
+ return Bun__createUint8ArrayForCopy(globalThis, bytes.ptr, bytes.len, true);
+ }
+
+ extern "C" fn Bun__createUint8ArrayForCopy(*JSC.JSGlobalObject, ptr: ?*const anyopaque, len: usize, buffer: bool) JSValue;
extern "C" fn Bun__createArrayBufferForCopy(*JSC.JSGlobalObject, ptr: ?*const anyopaque, len: usize) JSValue;
pub fn fromTypedArray(ctx: JSC.C.JSContextRef, value: JSC.JSValue, _: JSC.C.ExceptionRef) ArrayBuffer {
@@ -3994,3 +3999,93 @@ pub const Strong = extern struct {
ref.destroy();
}
};
+
+pub const BinaryType = enum {
+ Buffer,
+ ArrayBuffer,
+ Uint8Array,
+ Uint16Array,
+ Uint32Array,
+ Int8Array,
+ Int16Array,
+ Int32Array,
+ Float32Array,
+ Float64Array,
+ // DataView,
+
+ pub fn toJSType(this: BinaryType) JSC.JSValue.JSType {
+ return switch (this) {
+ .ArrayBuffer => .ArrayBuffer,
+ .Buffer => .Uint8Array,
+ // .DataView => .DataView,
+ .Float32Array => .Float32Array,
+ .Float64Array => .Float64Array,
+ .Int16Array => .Int16Array,
+ .Int32Array => .Int32Array,
+ .Int8Array => .Int8Array,
+ .Uint16Array => .Uint16Array,
+ .Uint32Array => .Uint32Array,
+ .Uint8Array => .Uint8Array,
+ };
+ }
+
+ pub fn toTypedArrayType(this: BinaryType) JSC.C.JSTypedArrayType {
+ return this.toJSType().toC();
+ }
+
+ const Map = bun.ComptimeStringMap(
+ BinaryType,
+ .{
+ .{ "ArrayBuffer", .ArrayBuffer },
+ .{ "Buffer", .Buffer },
+ // .{ "DataView", .DataView },
+ .{ "Float32Array", .Float32Array },
+ .{ "Float64Array", .Float64Array },
+ .{ "Int16Array", .Int16Array },
+ .{ "Int32Array", .Int32Array },
+ .{ "Int8Array", .Int8Array },
+ .{ "Uint16Array", .Uint16Array },
+ .{ "Uint32Array", .Uint32Array },
+ .{ "Uint8Array", .Uint8Array },
+ .{ "arraybuffer", .ArrayBuffer },
+ .{ "buffer", .Buffer },
+ // .{ "dataview", .DataView },
+ .{ "float32array", .Float32Array },
+ .{ "float64array", .Float64Array },
+ .{ "int16array", .Int16Array },
+ .{ "int32array", .Int32Array },
+ .{ "int8array", .Int8Array },
+ .{ "nodebuffer", .Buffer },
+ .{ "uint16array", .Uint16Array },
+ .{ "uint32array", .Uint32Array },
+ .{ "uint8array", .Uint8Array },
+ },
+ );
+
+ pub fn fromString(input: []const u8) ?BinaryType {
+ return Map.get(input);
+ }
+
+ pub fn fromJSValue(globalThis: *JSC.JSGlobalObject, input: JSValue) ?BinaryType {
+ if (input.isString()) {
+ return Map.getWithEql(input.getZigString(globalThis), ZigString.eqlComptime);
+ }
+
+ return null;
+ }
+
+ /// This clones bytes
+ pub fn toJS(this: BinaryType, bytes: []const u8, globalThis: *JSC.JSGlobalObject) JSValue {
+ switch (this) {
+ .Buffer => return JSC.ArrayBuffer.createBuffer(globalThis, bytes),
+ .ArrayBuffer => return JSC.ArrayBuffer.create(globalThis, bytes, .ArrayBuffer),
+ .Uint8Array => return JSC.ArrayBuffer.create(globalThis, bytes, .Uint8Array),
+
+ // These aren't documented, but they are supported
+ .Uint16Array, .Uint32Array, .Int8Array, .Int16Array, .Int32Array, .Float32Array, .Float64Array => {
+ const buffer = JSC.ArrayBuffer.create(globalThis, bytes, .ArrayBuffer);
+ return JSC.JSValue.c(JSC.C.JSObjectMakeTypedArrayWithArrayBuffer(globalThis, this.toTypedArrayType(), buffer.asObjectRef(), null));
+ },
+ }
+ }
+};
diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp
index 9f6a13b40..bfd775cde 100644
--- a/src/bun.js/bindings/ZigGlobalObject.cpp
+++ b/src/bun.js/bindings/ZigGlobalObject.cpp
@@ -970,10 +970,13 @@ extern "C" JSC__JSValue Bun__createArrayBufferForCopy(JSC::JSGlobalObject* globa
RELEASE_AND_RETURN(scope, JSValue::encode(JSC::JSArrayBuffer::create(globalObject->vm(), globalObject->arrayBufferStructure(JSC::ArrayBufferSharingMode::Default), WTFMove(arrayBuffer))));
}
-extern "C" JSC__JSValue Bun__createUint8ArrayForCopy(JSC::JSGlobalObject* globalObject, const void* ptr, size_t len)
+extern "C" JSC__JSValue Bun__createUint8ArrayForCopy(JSC::JSGlobalObject* globalObject, const void* ptr, size_t len, bool isBuffer)
{
auto scope = DECLARE_THROW_SCOPE(globalObject->vm());
- JSC::JSUint8Array* array = JSC::JSUint8Array::createUninitialized(globalObject, globalObject->m_typedArrayUint8.get(globalObject), len);
+ JSC::JSUint8Array* array = JSC::JSUint8Array::createUninitialized(
+ globalObject,
+ isBuffer ? reinterpret_cast<Zig::GlobalObject*>(globalObject)->JSBufferSubclassStructure() : globalObject->m_typedArrayUint8.get(globalObject),
+ len);
if (UNLIKELY(!array)) {
JSC::throwOutOfMemoryError(globalObject, scope);
diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig
index 23dd6188f..447c6c043 100644
--- a/src/bun.js/bindings/bindings.zig
+++ b/src/bun.js/bindings/bindings.zig
@@ -2582,6 +2582,7 @@ pub const JSValue = enum(JSValueReprInt) {
.Float32Array => .kJSTypedArrayTypeFloat32Array,
.Float64Array => .kJSTypedArrayTypeFloat64Array,
.ArrayBuffer => .kJSTypedArrayTypeArrayBuffer,
+ // .DataView => .kJSTypedArrayTypeDataView,
else => .kJSTypedArrayTypeNone,
};
}
diff --git a/src/bun.js/bindings/generated_classes.zig b/src/bun.js/bindings/generated_classes.zig
index 9962ec7f5..18bf91b99 100644
--- a/src/bun.js/bindings/generated_classes.zig
+++ b/src/bun.js/bindings/generated_classes.zig
@@ -6,8 +6,8 @@
/// 1. `bun src/bun.js/scripts/generate-classes.ts`
/// 2. Scan for **/*.classes.ts files in src/bun.js/src
/// 3. Generate a JS wrapper for each class in:
-/// Zig: generated_classes.zig
-/// C++: ZigGeneratedClasses.h, ZigGeneratedClasses.cpp
+/// - Zig: generated_classes.zig
+/// - C++: ZigGeneratedClasses.h, ZigGeneratedClasses.cpp
/// 4. For the Zig code to successfully compile:
/// - Add it to generated_classes_list.zig
/// - pub usingnamespace JSC.Codegen.JSMyClassName;
diff --git a/src/bun.js/net.exports.js b/src/bun.js/net.exports.js
index 928189dd3..b4229a271 100644
--- a/src/bun.js/net.exports.js
+++ b/src/bun.js/net.exports.js
@@ -86,14 +86,14 @@ export const Socket = (function (InternalSocket) {
self.emit("error", error);
},
- data({ data: self }, { length, buffer }) {
- self.bytesRead += length;
+ data({ data: self }, buffer) {
+ self.bytesRead += buffer.length;
const queue = self.#readQueue;
- const ret = new Buffer(buffer);
+
if (queue.isEmpty()) {
- if (self.push(ret)) return;
+ if (self.push(buffer)) return;
}
- queue.push(ret);
+ queue.push(buffer);
},
drain: Socket.#Drain,
end: Socket.#Close,
@@ -120,6 +120,7 @@ export const Socket = (function (InternalSocket) {
const self = socket.data;
self.emit("timeout");
},
+ binaryType: "buffer",
};
static #Close(socket) {