Skip to content

Commit 3bf4ad7

Browse files
authored
Add a template to avoid the cpp for initializing js classes (#178)
1 parent bd255b1 commit 3bf4ad7

File tree

4 files changed

+87
-28
lines changed

4 files changed

+87
-28
lines changed

c-dependencies/js-compute-runtime/builtin.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,63 @@
123123
return false; \
124124
}
125125

126+
namespace builtins {
127+
128+
template <typename Impl> class BuiltinImpl {
129+
private:
130+
static constexpr const JSClassOps class_ops{};
131+
static constexpr const uint32_t class_flags = 0;
132+
133+
public:
134+
static constexpr JSClass class_{
135+
Impl::class_name,
136+
JSCLASS_HAS_RESERVED_SLOTS(Impl::Slots::Count) | class_flags,
137+
&class_ops,
138+
};
139+
140+
static JS::PersistentRooted<JSObject *> proto_obj;
141+
142+
static bool is_instance(JSObject *obj) { return obj != nullptr && JS::GetClass(obj) == &class_; }
143+
144+
static bool is_instance(JS::Value val) { return val.isObject() && is_instance(&val.toObject()); }
145+
146+
static bool check_receiver(JSContext *cx, JS::HandleValue receiver, const char *method_name) {
147+
if (!Impl::is_instance(receiver)) {
148+
JS_ReportErrorUTF8(cx, "Method %s called on receiver that's not an instance of %s\n",
149+
method_name, Impl::class_.name);
150+
return false;
151+
}
152+
153+
return true;
154+
}
155+
156+
static bool init_class_impl(JSContext *cx, JS::HandleObject global,
157+
JS::HandleObject parent_proto = nullptr) {
158+
proto_obj.init(cx, JS_InitClass(cx, global, parent_proto, &class_, Impl::constructor,
159+
Impl::ctor_length, Impl::properties, Impl::methods, nullptr,
160+
nullptr));
161+
162+
return proto_obj != nullptr;
163+
}
164+
};
165+
166+
template <typename Impl> JS::PersistentRooted<JSObject *> BuiltinImpl<Impl>::proto_obj{};
167+
168+
template <typename Impl> class BuiltinNoConstructor : public BuiltinImpl<Impl> {
169+
public:
170+
static const int ctor_length = 1;
171+
172+
static bool constructor(JSContext *cx, unsigned argc, JS::Value *vp) {
173+
JS_ReportErrorUTF8(cx, "%s can't be instantiated directly", Impl::class_name);
174+
return false;
175+
}
176+
177+
static bool init_class(JSContext *cx, JS::HandleObject global) {
178+
return BuiltinImpl<Impl>::init_class_impl(cx, global) &&
179+
JS_DeleteProperty(cx, global, BuiltinImpl<Impl>::class_.name);
180+
}
181+
};
182+
183+
} // namespace builtins
184+
126185
#endif
Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,13 @@
11
#include "logger.h"
22
#include "host_call.h"
33

4-
namespace Logger {
5-
namespace Slots {
6-
enum { Endpoint, Count };
7-
};
4+
namespace builtins {
85

9-
bool check_receiver(JSContext *cx, JS::HandleValue receiver, const char *method_name);
10-
11-
namespace {
12-
13-
const unsigned ctor_length = 1;
14-
15-
static bool log(JSContext *cx, unsigned argc, JS::Value *vp) {
6+
bool Logger::log(JSContext *cx, unsigned argc, JS::Value *vp) {
167
METHOD_HEADER(1)
178

18-
auto endpoint = LogEndpointHandle{(uint32_t)JS::GetReservedSlot(self, Slots::Endpoint).toInt32()};
9+
auto endpoint =
10+
LogEndpointHandle{(uint32_t)JS::GetReservedSlot(self, Logger::Slots::Endpoint).toInt32()};
1911

2012
size_t msg_len;
2113
JS::UniqueChars msg = encode(cx, args.get(0), &msg_len);
@@ -30,15 +22,11 @@ static bool log(JSContext *cx, unsigned argc, JS::Value *vp) {
3022
return true;
3123
}
3224

33-
const JSFunctionSpec methods[] = {JS_FN("log", log, 1, JSPROP_ENUMERATE), JS_FS_END};
25+
const JSFunctionSpec Logger::methods[] = {JS_FN("log", log, 1, JSPROP_ENUMERATE), JS_FS_END};
3426

35-
const JSPropertySpec properties[] = {JS_PS_END};
27+
const JSPropertySpec Logger::properties[] = {JS_PS_END};
3628

37-
} // namespace
38-
39-
CLASS_BOILERPLATE_NO_CTOR(Logger)
40-
41-
JSObject *create(JSContext *cx, const char *name) {
29+
JSObject *Logger::create(JSContext *cx, const char *name) {
4230
JS::RootedObject logger(cx, JS_NewObjectWithGivenProto(cx, &class_, proto_obj));
4331
if (!logger)
4432
return nullptr;
@@ -52,4 +40,5 @@ JSObject *create(JSContext *cx, const char *name) {
5240

5341
return logger;
5442
}
55-
} // namespace Logger
43+
44+
} // namespace builtins

c-dependencies/js-compute-runtime/builtins/logger.h

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,23 @@
33

44
#include "builtin.h"
55

6-
namespace Logger {
7-
// Register the Logger class.
8-
bool init_class(JSContext *cx, JS::HandleObject global);
6+
namespace builtins {
97

10-
// Create an instance of the logger class.
11-
JSObject *create(JSContext *cx, const char *name);
12-
} // namespace Logger
8+
class Logger : public BuiltinNoConstructor<Logger> {
9+
private:
10+
static bool log(JSContext *cx, unsigned argc, JS::Value *vp);
11+
12+
public:
13+
static constexpr const char *class_name = "Logger";
14+
15+
enum Slots { Endpoint, Count };
16+
17+
static const JSFunctionSpec methods[];
18+
static const JSPropertySpec properties[];
19+
20+
static JSObject *create(JSContext *cx, const char *name);
21+
};
22+
23+
} // namespace builtins
1324

1425
#endif

c-dependencies/js-compute-runtime/js-compute-builtins.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,7 @@ bool getLogger(JSContext *cx, unsigned argc, Value *vp) {
483483
if (!name)
484484
return false;
485485

486-
RootedObject logger(cx, Logger::create(cx, name.get()));
486+
RootedObject logger(cx, builtins::Logger::create(cx, name.get()));
487487
if (!logger)
488488
return false;
489489

@@ -6271,7 +6271,7 @@ bool define_fastly_sys(JSContext *cx, HandleObject global) {
62716271
return false;
62726272
if (!TextDecoder::init_class(cx, global))
62736273
return false;
6274-
if (!Logger::init_class(cx, global))
6274+
if (!builtins::Logger::init_class(cx, global))
62756275
return false;
62766276
if (!URL::init_class(cx, global))
62776277
return false;

0 commit comments

Comments
 (0)