v8pp icon indicating copy to clipboard operation
v8pp copied to clipboard

Any idea for using `SetHandler` on class?

Open Yangff opened this issue 7 years ago • 2 comments

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?

Yangff avatar Jan 30 '17 14:01 Yangff

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.

imMute avatar Mar 14 '18 13:03 imMute

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

pmed avatar Mar 16 '18 06:03 pmed