Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add File interface #181

Merged
merged 13 commits into from
Jan 10, 2025
90 changes: 58 additions & 32 deletions builtins/web/blob.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#include "blob.h"
#include "file.h"
#include "builtin.h"
#include "encode.h"
#include "extension-api.h"
#include "js/UniquePtr.h"
#include "rust-encoding.h"
#include "streams/native-stream-source.h"

#include "mozilla/UniquePtr.h"
#include "js/UniquePtr.h"
#include "js/ArrayBuffer.h"
#include "js/Conversions.h"
#include "js/experimental/TypedData.h"
Expand Down Expand Up @@ -152,6 +152,19 @@ namespace web {
namespace blob {

using js::Vector;
using file::File;

#define DEFINE_BLOB_METHOD(name) \
bool Blob::name(JSContext *cx, unsigned argc, JS::Value *vp) { \
METHOD_HEADER(0) \
return name(cx, self, args.rval()); \
}

#define DEFINE_BLOB_METHOD_W_ARGS(name) \
bool Blob::name(JSContext *cx, unsigned argc, JS::Value *vp) { \
METHOD_HEADER(0) \
return name(cx, self, args, args.rval()); \
}

const JSFunctionSpec Blob::static_methods[] = {
JS_FS_END,
Expand Down Expand Up @@ -267,15 +280,19 @@ JSObject *Blob::data_to_owned_array_buffer(JSContext *cx, HandleObject self, siz
return array_buffer;
}

bool Blob::arrayBuffer(JSContext *cx, unsigned argc, JS::Value *vp) {
METHOD_HEADER(0)
DEFINE_BLOB_METHOD(arrayBuffer)
DEFINE_BLOB_METHOD(bytes)
DEFINE_BLOB_METHOD(stream)
DEFINE_BLOB_METHOD(text)
DEFINE_BLOB_METHOD_W_ARGS(slice)
tschneidereit marked this conversation as resolved.
Show resolved Hide resolved

bool Blob::arrayBuffer(JSContext *cx, HandleObject self, MutableHandleValue rval) {
JS::RootedObject promise(cx, JS::NewPromiseObject(cx, nullptr));
if (!promise) {
return false;
}

args.rval().setObject(*promise);
rval.setObject(*promise);

auto buffer = data_to_owned_array_buffer(cx, self);
if (!buffer) {
Expand All @@ -289,15 +306,13 @@ bool Blob::arrayBuffer(JSContext *cx, unsigned argc, JS::Value *vp) {
return true;
}

bool Blob::bytes(JSContext *cx, unsigned argc, JS::Value *vp) {
METHOD_HEADER(0)

bool Blob::bytes(JSContext *cx, HandleObject self, MutableHandleValue rval) {
JS::RootedObject promise(cx, JS::NewPromiseObject(cx, nullptr));
if (!promise) {
return false;
}

args.rval().setObject(*promise);
rval.setObject(*promise);

JS::RootedObject buffer(cx, data_to_owned_array_buffer(cx, self));
if (!buffer) {
Expand All @@ -317,9 +332,7 @@ bool Blob::bytes(JSContext *cx, unsigned argc, JS::Value *vp) {
return true;
}

bool Blob::slice(JSContext *cx, unsigned argc, JS::Value *vp) {
METHOD_HEADER(0)

bool Blob::slice(JSContext *cx, HandleObject self, const CallArgs &args, MutableHandleValue rval) {
auto src = Blob::blob(self);
int64_t size = src->length();
int64_t start = 0;
Expand Down Expand Up @@ -364,13 +377,11 @@ bool Blob::slice(JSContext *cx, unsigned argc, JS::Value *vp) {
return false;
}

args.rval().setObject(*new_blob);
rval.setObject(*new_blob);
return true;
}

bool Blob::stream(JSContext *cx, unsigned argc, JS::Value *vp) {
METHOD_HEADER(0)

bool Blob::stream(JSContext *cx, HandleObject self, MutableHandleValue rval) {
auto native_stream = streams::NativeStreamSource::create(cx, self, JS::UndefinedHandleValue,
stream_pull, stream_cancel);

Expand All @@ -392,19 +403,17 @@ bool Blob::stream(JSContext *cx, unsigned argc, JS::Value *vp) {
return false;
}

args.rval().setObject(*stream);
rval.setObject(*stream);
return true;
}

bool Blob::text(JSContext *cx, unsigned argc, JS::Value *vp) {
METHOD_HEADER(0)

bool Blob::text(JSContext *cx, HandleObject self, MutableHandleValue rval) {
JS::RootedObject promise(cx, JS::NewPromiseObject(cx, nullptr));
if (!promise) {
return false;
}

args.rval().setObject(*promise);
rval.setObject(*promise);

auto src = Blob::blob(self);
auto encoding = const_cast<jsencoding::Encoding *>(jsencoding::encoding_for_label_no_replacement(
Expand Down Expand Up @@ -512,6 +521,15 @@ Blob::LineEndings Blob::line_endings(JSObject *self) {
JS::GetReservedSlot(self, static_cast<size_t>(Blob::Slots::Endings)).toInt32());
}

bool Blob::is_instance(const JSObject *obj) {
return obj != nullptr &&
(JS::GetClass(obj) == &Blob::class_ || JS::GetClass(obj) == &File::class_);
}

bool Blob::is_instance(const Value val) {
return val.isObject() && is_instance(&val.toObject());
}

bool Blob::append_value(JSContext *cx, HandleObject self, HandleValue val) {
auto blob = Blob::blob(self);

Expand Down Expand Up @@ -670,17 +688,7 @@ JSObject *Blob::create(JSContext *cx, UniqueChars data, size_t data_len, HandleS
return self;
}

bool Blob::constructor(JSContext *cx, unsigned argc, JS::Value *vp) {
CTOR_HEADER("Blob", 0);

RootedValue blobParts(cx, args.get(0));
RootedValue opts(cx, args.get(1));
RootedObject self(cx, JS_NewObjectForConstructor(cx, &class_, args));

if (!self) {
return false;
}

bool Blob::init(JSContext *cx, HandleObject self, HandleValue blobParts, HandleValue opts) {
SetReservedSlot(self, static_cast<uint32_t>(Slots::Type), JS_GetEmptyStringValue(cx));
SetReservedSlot(self, static_cast<uint32_t>(Slots::Endings), JS::Int32Value(LineEndings::Transparent));
SetReservedSlot(self, static_cast<uint32_t>(Slots::Data), JS::PrivateValue(new ByteBuffer));
Expand All @@ -699,6 +707,24 @@ bool Blob::constructor(JSContext *cx, unsigned argc, JS::Value *vp) {
return false;
}

return true;
}

bool Blob::constructor(JSContext *cx, unsigned argc, JS::Value *vp) {
CTOR_HEADER("Blob", 0);

RootedValue blobParts(cx, args.get(0));
RootedValue opts(cx, args.get(1));
RootedObject self(cx, JS_NewObjectForConstructor(cx, &class_, args));

if (!self) {
return false;
}

if (!init(cx, self, blobParts, opts)) {
return false;
}

args.rval().setObject(*self);
return true;
}
Expand Down
11 changes: 11 additions & 0 deletions builtins/web/blob.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,24 @@ class Blob : public TraceableBuiltinImpl<Blob> {
using ByteBuffer = js::Vector<uint8_t, 0, js::SystemAllocPolicy>;
using ReadersMap = JS::GCHashMap<HeapObj, BlobReader, js::StableCellHasher<HeapObj>, js::SystemAllocPolicy>;

static bool arrayBuffer(JSContext *cx, HandleObject self, MutableHandleValue rval);
static bool bytes(JSContext *cx, HandleObject self, MutableHandleValue rval);
static bool stream(JSContext *cx, HandleObject self, MutableHandleValue rval);
static bool text(JSContext *cx, HandleObject self, MutableHandleValue rval);
static bool slice(JSContext *cx, HandleObject self, const CallArgs &args, MutableHandleValue rval);

static ReadersMap *readers(JSObject *self);
static ByteBuffer *blob(JSObject *self);
static size_t blob_size(JSObject *self);
static JSString *type(JSObject *self);
static LineEndings line_endings(JSObject *self);

static bool is_instance(const JSObject *obj);
static bool is_instance(const Value val);
static bool append_value(JSContext *cx, HandleObject self, HandleValue val);
static bool init_blob_parts(JSContext *cx, HandleObject self, HandleValue iterable);
static bool init_options(JSContext *cx, HandleObject self, HandleValue opts);
static bool init(JSContext *cx, HandleObject self, HandleValue blobParts, HandleValue opts);

static bool stream_cancel(JSContext *cx, JS::CallArgs args, JS::HandleObject stream,
JS::HandleObject owner, JS::HandleValue reason);
Expand All @@ -75,6 +85,7 @@ class Blob : public TraceableBuiltinImpl<Blob> {
static JSObject *data_to_owned_array_buffer(JSContext *cx, HandleObject self);
static JSObject *data_to_owned_array_buffer(JSContext *cx, HandleObject self, size_t offset,
size_t size, size_t *bytes_read);

static JSObject *create(JSContext *cx, UniqueChars data, size_t data_len, HandleString type);

static bool init_class(JSContext *cx, HandleObject global);
Expand Down
2 changes: 1 addition & 1 deletion builtins/web/fetch/request-response.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ bool RequestOrResponse::extract_body(JSContext *cx, JS::HandleObject self,

if (Blob::is_instance(body_obj)) {
RootedValue stream(cx);
if (!Call(cx, body_obj, "stream", HandleValueArray::empty(), &stream)) {
if (!Blob::stream(cx, body_obj, &stream)) {
return false;
}

Expand Down
Loading
Loading