Skip to content

Instantly share code, notes, and snippets.

@jorendorff
Last active October 7, 2023 23:13
Show Gist options
  • Save jorendorff/74fc6833997bd83b226c507616dc588b to your computer and use it in GitHub Desktop.
Save jorendorff/74fc6833997bd83b226c507616dc588b to your computer and use it in GitHub Desktop.
// Template-based argument conversion in jsapi.h?
// First, to show what we're shooting for here...
namespace JS {
// The main entry point for getting object properties. Everything goes through here.
extern JS_PUBLIC_API(bool)
GetProperty(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp);
// The helper template for automatically converting/rooting arguments of random types
// to the HandleObject and HandleId required for the above signature.
inline template <typename ObjectArg, typename IdArg>
bool
GetProperty(JSContext* cx, ObjectArg objArg, IdArg idArg, MutableHandleValue vp)
{
// ArgumentHandler objects are fairly lightweight;
// they root and convert arguments as needed.
ArgumentHandler<ObjArg, JSObject*> obj(cx, objArg);
if (!obj.ok())
return false;
ArgumentHandlerId<IdArg, jsid> id(cx, idArg);
if (!id.ok())
return false;
return GetProperty(cx, obj.handle(), id.handle(), vp);
}
}
namespace JS {
// Implicit argument conversions **************************************************************
// Template for implicitly converting a variety of argument types
// to various Handle<Target> types.
template <typename Arg, typename Target> struct ArgumentHandler;
// Handle<T> -> Handle<T>, a trivial conversion.
template <typename T>
struct ArgumentHandler<Handle<T>, T>
{
Handle<T> h;
ArgumentHandler(JSContext*, Handle<T> arg) : h(arg) {}
bool ok() const { return true; }
Handle<T> handle() const { return h; }
};
// Heap<T> -> Handle<T>, with automatic rooting.
template <typename T>
struct ArgumentHandler<Heap<T>, T>
{
Rooted<T> root;
ArgumentHandlerObject(JSContext* cx, Heap<T> ptr) : root(cx, ptr) {}
bool ok() { return true; }
HandleObject handle() const { return robj; }
};
extern JS_PUBLIC_API(bool)
CStringToId(JSContext* cx, const char* s, MutableHandleId out);
// const char* -> HandleId, a conversion that can fail with OOM.
template <>
struct ArgumentHandler<const char*, jsid>
{
bool ok;
RootedId idroot;
ArgumentHandlerId(JSContext* cx, const char* s) : idroot(cx) {
ok = CStringToId(cx, s, &idroot);
}
bool ok() const { return ok; }
HandleId handle() const { return idroot; }
};
// uint32_t -> HandleId, same deal.
template <>
struct ArgumentHandler<uint32_t, jsid>
{
bool ok;
RootedId idroot;
ArgumentHandlerId(JSContext* cx, uint32_t index) : idroot(cx) {
ok = JS_IndexToId(cx, index, &idroot);
}
bool ok() const { return ok; }
HandleId handle() const { return idroot; }
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment