Skip to content

Commit

Permalink
Generated JSI integration compiles successfully
Browse files Browse the repository at this point in the history
  • Loading branch information
RedBeard0531 committed Nov 23, 2022
1 parent beeeae8 commit f057939
Show file tree
Hide file tree
Showing 5 changed files with 1,109 additions and 21 deletions.
12 changes: 12 additions & 0 deletions packages/bindgen/src/cpp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ export class CppVar {
const staticTok = this.isStatic ? "static" : "";
return `${staticTok} ${this.arg_declaration()};`;
}

static_definition(on: CppClass) {
return `${this.type} ${on.name}::${this.name};`;
}
}

type CppFuncProp = "static" | "const" | "noexcept" | "override";
Expand Down Expand Up @@ -174,6 +178,13 @@ export class CppClass {
};`;
}

staticMemberDefs() {
return this.members
.filter((m) => m.isStatic)
.map((m) => m.static_definition(this))
.join("\n");
}

methodDefs() {
return this.methods.map((m) => m.definition()).join("\n");
}
Expand All @@ -198,6 +209,7 @@ export class CppDecls {
out(c.definition());
}
for (const c of this.classes) {
out(c.staticMemberDefs());
out(c.methodDefs());
}
for (const f of this.free_funcs) {
Expand Down
170 changes: 170 additions & 0 deletions packages/bindgen/src/realm_js_jsi_helpers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
#pragma once

#include <concepts>
#include <jsi/jsi.h>
#include <realm_js_helpers.h>
#include <type_traits>

namespace realm::js::JSI {
namespace {
namespace jsi = facebook::jsi;
template <typename Ref>
struct HostRefWrapper : jsi::HostObject {
static_assert(std::is_reference_v<Ref>);
HostRefWrapper(Ref ref)
: ref(ref)
{
}

static std::shared_ptr<HostRefWrapper> create(Ref val)
{
return std::make_shared<HostRefWrapper>(val);
}

static jsi::Object create(jsi::Runtime& rt, Ref val)
{
return jsi::Object::createFromHostObject(rt, create(val));
}

static Ref& extract(jsi::Runtime& rt, jsi::Object&& obj)
{
return FWD(obj).getHostObject<HostRefWrapper>(rt)->ref;
}
static Ref& extract(jsi::Runtime& rt, jsi::Value&& val)
{
return extract(rt, FWD(val).getObject(rt));
}
static Ref& extract(jsi::Runtime& rt, const jsi::Value& val)
{
return extract(rt, val.getObject(rt));
}

Ref ref;
};

template <typename T, typename Base = T>
struct HostObjClassWrapper : HostRefWrapper<Base&> {
HostObjClassWrapper(T&& val)
: HostRefWrapper<Base&>(this->value)
, value(std::move(val))
{
}

static std::shared_ptr<HostObjClassWrapper> create(T&& val)
{
return std::make_shared<HostObjClassWrapper>(FWD(val));
}

static jsi::Object create(jsi::Runtime& rt, T&& val)
{
return jsi::Object::createFromHostObject(rt, create(FWD(val)));
}

T value;
};

template <typename T>
std::remove_cvref_t<T> copyIfNeeded(jsi::Runtime& rt, const T& val)
{
return T(rt, val);
}

template <typename T>
std::remove_cvref_t<T> copyIfNeeded(jsi::Runtime&, T&& val)
{
return FWD(val);
}

#define FWD_OR_COPY(x) copyIfNeeded(_env, FWD(x))

REALM_NOINLINE inline jsi::Value toJsiErrorCode(jsi::Runtime& env, const std::error_code& e) noexcept
{
REALM_ASSERT_RELEASE(e);
auto out = jsi::JSError(env, e.message()).value().getObject(env);
out.setProperty(env, "code", e.value());
out.setProperty(env, "category", e.category().name());
return jsi::Value(std::move(out));
}

REALM_NOINLINE inline jsi::Value toJsiException(jsi::Runtime& env, const std::exception_ptr& e) noexcept
{
auto jsError = [&] {
try {
std::rethrow_exception(e);
}
catch (const jsi::JSError& e) {
return e;
}
catch (const std::exception& e) {
return jsi::JSError(env, e.what());
}
catch (...) {
return jsi::JSError(env, "Unknown Error");
}
}();
return jsi::Value(env, jsError.value());
}

[[noreturn]] REALM_NOINLINE inline void throwJsiException(jsi::Runtime& env, const std::exception& e)
{
if (dynamic_cast<const jsi::JSError*>(&e))
throw; // Just allow exception propagation to continue
// TODO consider throwing more specific errors in some cases.
// TODO consider using ThrowAsJavaScriptException instead here.
throw jsi::JSError(env, e.what());
}

[[noreturn]] REALM_NOINLINE inline void throwNullSharedPtrError(jsi::Runtime& env, const char* clsName)
{
throw jsi::JSError(env, util::format("Attempting to use an instanace of $1 holding a null shared_ptr. "
"Did you call $resetSharedPtr on it already?",
clsName));
}

/**
* Stores Func in a std::shared_ptr if it isn't copyable.
*/
template <typename Func>
class MakeCopyable {
public:
explicit MakeCopyable(Func&& func)
: m_func(std::make_shared<Func>(FWD(func)))
{
}

auto operator()(auto&&... args) const
requires std::invocable<Func, decltype(FWD(args))...>
{
return (*m_func)(FWD(args)...);
}

private:
static_assert(!std::copyable<Func>);
static_assert(!std::is_reference_v<Func>);
std::shared_ptr<Func> m_func;
};

/**
* Specialization if Func is already copyable stores Func inline.
*/
template <std::copyable Func>
class MakeCopyable<Func> {
public:
explicit MakeCopyable(Func&& func)
: m_func(FWD(func))
{
}

auto operator()(auto&&... args) const
requires std::invocable<Func, decltype(FWD(args))...>
{
return m_func(FWD(args)...);
}

private:
static_assert(!std::is_reference_v<Func>);
Func m_func;
};

} // namespace
} // namespace realm::js::JSI

0 comments on commit f057939

Please sign in to comment.