#ifndef SUPPORT_H_ #define SUPPORT_H_ #include #include #include #include #include #include #include #include "v8/include/v8.h" // Work around a bug in the V8 headers. // // The following template is defined in v8-internal.h. It has a subtle bug that // indirectly makes it impossible to convert `v8::Data` handles to themselves. // Some methods do that impliclity so they don't compile without this hack; one // example is `Local MaybeLocal::FromMaybe(Local default_value)`. // // Spot the bug :) // // ``` // template // V8_INLINE void PerformCastCheck(T* data) { // CastCheck::value && // !std::is_same>::value>::Perform(data); // } // ``` template <> template <> inline void v8::internal::CastCheck::Perform(v8::Data* data) {} // Check assumptions made in binding code. static_assert(sizeof(bool) == sizeof(uint8_t), ""); static_assert(sizeof(std::unique_ptr) == sizeof(void*), ""); namespace support { template using uninit_t = typename std::aligned_storage::type; template class construct_in_place_helper { public: construct_in_place_helper(uninit_t* buf, Args... args) : inner_(std::forward(args)...) {} private: T inner_; }; template void construct_in_place(uninit_t* buf, Args... args) { new (buf) construct_in_place_helper(buf, std::forward(args)...); } // Rust's FFI only supports returning normal C data structures (AKA plain old // data). There are some situations in the V8 API where functions return non-POD // data. We use make_pod to carefully adjust the return values so they can be // passed into Rust. // // The destructor of V is never called. // P is not allowed to have a destructor. template struct make_pod { template inline make_pod(V&& value) : pod_(helper(std::move(value))) {} template inline make_pod(const V& value) : pod_(helper(value)) {} inline operator P() { return pod_; } private: P pod_; // This helper exists to avoid calling the destructor. // Using a union is a C++ trick to achieve this. template union helper { static_assert(std::is_pod

::value, "type P must a pod type"); static_assert(sizeof(V) == sizeof(P), "type P must be same size as type V"); static_assert(alignof(V) == alignof(P), "alignment of type P must be compatible with that of type V"); inline helper(V&& value) : value_(std::move(value)) {} inline helper(const V& value) : value_(value) {} inline ~helper() {} inline operator P() { // Do a memcpy here avoid undefined behavior. P result; memcpy(&result, this, sizeof result); return result; } private: V value_; }; }; // The C-ABI compatible equivalent of V8's Maybe. enum class MaybeBool { JustFalse = 0, JustTrue = 1, Nothing = 2 }; inline static MaybeBool maybe_to_maybe_bool(v8::Maybe maybe) { if (maybe.IsNothing()) { return MaybeBool::Nothing; } else if (maybe.FromJust()) { return MaybeBool::JustTrue; } else { return MaybeBool::JustFalse; } } inline static v8::Maybe maybe_bool_to_maybe(MaybeBool maybe) { switch (maybe) { case MaybeBool::JustTrue: case MaybeBool::JustFalse: return v8::Just(maybe == MaybeBool::JustTrue); default: return v8::Nothing(); } } template inline static T* local_to_ptr(v8::Local local) { return *local; } template inline static const v8::Local ptr_to_local(const T* ptr) { static_assert(sizeof(v8::Local) == sizeof(T*), ""); auto local = *reinterpret_cast*>(&ptr); assert(*local == ptr); return local; } template inline static v8::Local* const_ptr_array_to_local_array( const T* const ptr_array[]) { static_assert(sizeof(v8::Local[42]) == sizeof(T* [42]), ""); auto mut_ptr_array = const_cast(ptr_array); auto mut_local_array = reinterpret_cast*>(mut_ptr_array); return mut_local_array; } template inline static T* maybe_local_to_ptr(v8::MaybeLocal local) { return *local.FromMaybe(v8::Local()); } template inline static const v8::MaybeLocal ptr_to_maybe_local(const T* ptr) { static_assert(sizeof(v8::MaybeLocal) == sizeof(T*), ""); return *reinterpret_cast*>(&ptr); } template inline static v8::Global ptr_to_global(const T* ptr) { v8::Global global; std::swap(ptr, *reinterpret_cast(&global)); return global; } // Because, for some reason, Clang complains that `std::array` is an // incomplete type, incompatible with C linkage. struct two_pointers_t { void* a; void* b; }; struct three_pointers_t { void* a; void* b; void* c; }; } // namespace support #endif // SUPPORT_H_