pmed / v8pp

Bind C++ functions and classes into V8 JavaScript engine
http://pmed.github.io/v8pp/
Other
901 stars 121 forks source link

Proposal: Get properties as tuple #112

Closed linwe2012 closed 4 years ago

linwe2012 commented 5 years ago

Hi, I hope there is an simple way to get properties of objects.

What I am looking for is something like that:

auto [x, y, z] = get_properties<int, double, string>(isolate, object, "x", "y", "z")

I tried implement this myself:

#include "v8pp/convert.hpp"
#include <tuple>

namespace detail {
    template<typename Args>
    Args GetPropertiesPass(v8::Isolate* isolate, v8::Local<v8::Object> object, const char* c) {
        using namespace v8;
        return
            v8pp::from_v8<Args>(isolate, object->Get(String::NewFromUtf8(isolate, c, NewStringType::kNormal).ToLocalChecked()));

    }

    template<typename... Args, std::size_t... Is>
    std::tuple<Args...> GetProperties(v8::Isolate* isolate, v8::Local<v8::Object> object, const char* arr[sizeof...(Args)], std::index_sequence<Is...>) {
        return {
            GetPropertiesPass<Args>(isolate, object, arr[Is])...
        };
    }

}

template<typename... Args>
std::tuple<Args...> GetProperties(v8::Isolate* isolate, v8::Local<v8::Object> object, const char* arr[sizeof...(Args)]) {
    using t = const char* [sizeof...(Args)];

    return detail::GetProperties<Args...>(isolate, object, arr, std::index_sequence_for<Args...>{});
}

Not sure if correct. It would be nice if v8pp could provide apis like that

pmed commented 5 years ago

Hi @linwe2012

In C++17 you could try to use std::apply() with a lambda that calls v8pp::get_option() for each tuple component. Like this:

template<typename ...Types, typename ...Names>
auto get_options(v8::Isolate* isolate, v8::Local<v8::Object> obj, Names... names)
{
    std::tuple<Types...> result;
    std::apply([&](auto& ...x) { (..., v8pp::get_option(isolate, obj, names, x)); }, result);
    return result;
}

void test_object()
{
    v8pp::context context;
    v8::Isolate* isolate = context.isolate();

    v8::HandleScope scope(isolate);

    v8::Local<v8::Object> obj = v8::Object::New(isolate);

    v8pp::set_option(isolate, obj, "a", 10);
    v8pp::set_option(isolate, obj, "b", true);
    v8pp::set_option(isolate, obj, "sub", v8::Object::New(isolate));
    v8pp::set_option(isolate, obj, "sub.x", "zzz");
    v8pp::set_const(isolate, obj, "pi", 3.1415926);

    auto [a, b, x, pi] = get_options<int, bool, std::string, double>(isolate, obj, "a", "b", "sub.x", "pi");
    check_eq("obj.a", a, 10);
    check_eq("obj.b", b, true);
    check_eq("obj.sub.x", x, "zzz");
    check("obj.pi", fabs(pi - 3.1415926) < 10e-6);
}