pmed / v8pp

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

Any idea for using `SetHandler` on class? #47

Open Yangff opened 7 years ago

Yangff commented 7 years ago

To achieve this, I added some code to class.hpp, so I can call klass.index<Type>() to make this class array-like. However I don't think it's an elegant way (my code)...

#define METHOD_CHECKER_ANY(fn, args) \
template<class C, typename=void> struct has_member_##fn : std::false_type {}; \
template<class C> struct has_member_##fn<C, typename std::enable_if< \
  !std::is_same<decltype(std::declval<C>().fn args)*, void>::value>::type> : std::true_type {};

METHOD_CHECKER_ANY(index_query, (0));
METHOD_CHECKER_ANY(index_set, (0, T1()));
METHOD_CHECKER_ANY(index_delete, (0));
METHOD_CHECKER_ANY(index_enum, ());

    template<class T1>
    static auto set_index_set(v8::IndexedPropertySetterCallback &indexset) -> typename std::enable_if_t<has_member_index_set<T>::value> {
        indexset = [](uint32_t index, v8::Local<v8::Value> value, v8::PropertyCallbackInfo <v8::Value> &info) -> void {
            auto klass = v8pp::from_v8<T&>(info.GetIsolate(), info.This());

            info.GetReturnValue().Set(v8pp::to_v8<T1>(info.GetIsolate(), klass.index_set(index, v8pp::to_local<T1>(value))));
        };
    }

    template<class T1>
    static auto set_index_set(v8::IndexedPropertySetterCallback &indexset) -> typename std::enable_if_t<!has_member_index_set<T>::value> {

    }
    template<class T1>
    static auto set_index_query(v8::IndexedPropertyQueryCallback &indexquery) -> typename std::enable_if_t<has_member_index_query<T>::value> {
        indexquery = [](uint32_t index, v8::PropertyCallbackInfo <v8::Integer> &info) -> void {
            auto klass = v8pp::from_v8<T&>(info.GetIsolate(), info.This());
            info.GetReturnValue().Set(v8pp::to_v8<int>(info.GetIsolate(), klass.index_query(index)));
        };
    }
    template<class T1>
    static auto set_index_query(v8::IndexedPropertyQueryCallback &indexquery) -> typename std::enable_if_t<!has_member_index_query<T>::value> {

    }
    template<class T1>
    static auto set_index_delete(v8::IndexedPropertyDeleterCallback &indexdelete) -> typename std::enable_if_t<has_member_index_delete<T>::value> {
        indexdelete = [](uint32_t index, v8::PropertyCallbackInfo <v8::Boolean> &info) -> void {
            auto klass = v8pp::from_v8<T&>(info.GetIsolate(), info.This());
            info.GetReturnValue().Set(v8pp::to_v8<bool>(info.GetIsolate(), klass.index_delete(index)));
        };
    }
    template<class T1>
    static auto set_index_delete(v8::IndexedPropertyDeleterCallback &indexdelete) -> typename std::enable_if_t<!has_member_index_delete<T>::value> {

    }
    template<class T1>
    static auto set_index_enum(v8::IndexedPropertyEnumeratorCallback &indexenum) -> typename std::enable_if_t<has_member_index_enum<T>::value> {
        indexenum = [](v8::PropertyCallbackInfo <v8::Array> &info) -> void {
            auto klass = v8pp::from_v8<T&>(info.GetIsolate(), info.This());
            info.GetReturnValue().Set(v8pp::to_v8<v8::Array>(info.GetIsolate(), klass.index_enum()));
        };
    }
    template<class T1>
    static auto set_index_enum(v8::IndexedPropertyEnumeratorCallback &indexenum) -> typename std::enable_if_t<!has_member_index_enum<T>::value> {

    }

    template<class T1> // element type
    void index() {
        v8::IndexedPropertyGetterCallback IndexGet = [](uint32_t index, const v8::PropertyCallbackInfo<v8::Value> &info) -> void {
            auto klass = v8pp::from_v8<T&>(info.GetIsolate(), info.This());
            info.GetReturnValue().Set(v8pp::to_v8<T1>(info.GetIsolate(), klass.index_get(index)));
        };

        v8::IndexedPropertySetterCallback IndexSet = NULL;
        set_index_set<T1>(IndexSet);

        v8::IndexedPropertyQueryCallback IndexQuery = NULL;
        set_index_query<T1>(IndexQuery);

        v8::IndexedPropertyDeleterCallback IndexDelete = NULL;
        set_index_delete<T1>(IndexDelete);

        v8::IndexedPropertyEnumeratorCallback IndexEnum = NULL;
        set_index_enum<T1>(IndexEnum);

        class_function_template()->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(IndexGet, IndexSet, IndexQuery, IndexDelete,IndexEnum));
    }

Is there any better method to do this?

mhalenza commented 6 years ago

I can't help you with your code, @Yangff, but I'd like to +1 this proposal and take it a step further: I'd like a way to intercept all property accesses that aren't handled by other v8pp properties. Use case is simple: I want all other properties to return null to JS and throw a JS exception on set.

pmed commented 6 years ago

Some time ago I started working on generalized indexed/named property accessor handler in v8pp::class_. Both of these handlers have 5 functions to get/set/query/delete/enumerate items or properties. Unfortunately, currently I have no spare time to complete that implementation.

At the present moment the only way is to set accessor handler with v8pp::class_::class_function_template()->InstanceTemplate()->SetHandler(your_accessor_handler_configuration). The accessor handler configuration could be created similar to example above by @Yangff