v8toolkit  0.0.1
Utility library for embedding V8 Javascript engine in a c++ program
bidirectional.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <string>
4 
5 #define V8TOOLKIT_BIDIRECTIONAL_ENABLED
6 
7 #include "v8toolkit.h"
8 
9 
10 
11 
12 
13 
14 /**
15 * This file contains things needed to create "types" and objects in both C++ and javascript
16 * and use them in either environment regardless of where they were created. Since C++
17 * types must exist at compile time, types created with these tools cannot create
18 * actual C++ types, but instead allow behavior to be overridden on virtual functions
19 *
20 * See samples/bidirectional_sample.cpp for examples on how to use this library.
21 */
22 
23 
24 namespace v8toolkit {
25 
26 class BidirectionalException : public std::exception {
27  std::string reason;
28 public:
29  BidirectionalException(const std::string &reason) : reason(reason) { }
30 
31  virtual const char *what() const noexcept { return reason.c_str(); }
32 };
33 
34 
35 // Inheriting from this gives hints to the system that you are a bidirectional type
37 protected:
38  v8::Isolate *isolate;
39  v8::Global<v8::Context> global_context;
40  v8::Global<v8::Object> global_js_object;
41  v8::Global<v8::FunctionTemplate> global_created_by;
42 
43  /**
44  * It's easy to end up in infinite recursion where the JSWrapper object looks for a javascript implementation
45  * to call instead of calling the native C++ implementation, but finds its own JS_ACCESS function that its already in
46  * an proceeds to call itself. This flag stops that from happening - at least in naive situations. Marked as
47  * mutable because it needs to be changed even from within const methods
48  */
49  mutable bool called_from_javascript = false;
50 
51 protected:
53  v8::Local<v8::Object> object,
55  isolate(context->GetIsolate()),
56  global_context(v8::Global<v8::Context>(isolate, context)),
57  global_js_object(v8::Global<v8::Object>(isolate, object)),
58  global_created_by(v8::Global<v8::FunctionTemplate>(isolate, created_by)) { }
59 
60 public:
61  v8::Local<v8::Object> get_javascript_object() const { return global_js_object.Get(isolate); }
62 
63 };
64 
65 
66 /**
67 * C++ types to be extended in javascript must inherit from this class.
68 * Example: class MyClass{}; class JSMyClass : public MyClass, public JSWrapper {};
69 * Now, JSMyClass can be used as a MyClass, but will intercept calls to its methods
70 * and attempt to use the javascript object to fulfill them, falling back to the
71 * C++ class methods of MyClass when necessary
72 * Any class inheriting from this (e.g. JSMyClass) must have the first two parameters of its constructor
73 * be a v8::Local<v8::Context>, v8::Local<v8::Object>
74 */
75 template<class Base>
76 class JSWrapper : public JSWrapperBase {
77 protected:
78  using BASE_TYPE = Base;
79 
80 public:
82  v8::Local<v8::Object> object,
84  JSWrapperBase(context, object, created_by)
85  {}
86 };
87 
88 template<class T>
89 std::enable_if_t<std::is_base_of<JSWrapperBase, T>::value, v8::Local<v8::Object>> safe_get_javascript_object(T * object) {
90  return object->get_javascript_object();
91 }
92 
93 template<class T>
94 std::enable_if_t<!std::is_base_of<JSWrapperBase, T>::value, v8::Local<v8::Object>> safe_get_javascript_object(T * object) {
95  return v8::Local<v8::Object>();
96 }
97 
98 
99 
100 
101 /* template<class... Ts> */
102 /* struct CastToJS<JSWrapper<Ts...>> { */
103 /* v8::Local<v8::Value> operator()(v8::Isolate *isolate, JSWrapper<Ts...> &js_wrapper) { */
104 /* // printf("Using custom JSWrapper CastToJS method"); */
105 /* return js_wrapper.get_javascript_object(); */
106 /* } */
107 /* }; */
108 template<class T>
109 struct CastToJS<JSWrapper<T>> {
110  v8::Local<v8::Value> operator()(v8::Isolate *isolate, const JSWrapper<T> &js_wrapper) {
111 // printf("Using custom JSWrapper CastToJS method");
112  return js_wrapper.get_javascript_object();
113  }
114 };
115 } // end v8toolkit namespace
116 
117 #include "v8_class_wrapper.h"
118 
119 #ifndef V8_CLASS_WRAPPER_HAS_BIDIRECTIONAL_SUPPORT
120 #error bidirectional.h must be included before v8_class_wrapper.h
121 #endif
122 
123 namespace v8toolkit {
124 
125  /**
126  * Class for Factory to inherit from when no other parent is specified
127  * Must be empty
128  */
129  class EmptyFactoryBase {};
130 
131 
132 
133 
134 /**
135  * Common Factory Inheritance goes:
136  * v8toolkit::CppFactory => custom user-defined Factory type for additional data/functions =>
137  * v8toolkit::Factory => v8toolkit::Factory<BaseType> => Common base type for all factories
138  *
139  */
140 
141 /**
142  * Internal constructor parameters are parameters only on the Base type constructor that are not specified to
143  * each instance of the derived type. The value is fixed across all isntances of the specific derived type.
144  *
145  * External constructor parameters are parameers are all the parameters to the derived type (except an optional
146  * first parameter of the factory object which will be automatically populated)
147  */
148 
149 
150 /**
151 * Base class for a Factory that creates a bidirectional "type" by name. The object
152 * returned can be used as a class T regardless of whether it is a pure C++ type
153 * or if it has been extended in javascript
154 */
155 template<class Base, // The common base class type of object to be returned
156  class = TypeList<>, // List of parameters that may change per-instance created
157  class FactoryBase = EmptyFactoryBase, // base class of this factory class
158  class Deleter = std::default_delete<Base>>
159 class Factory;
160 
161 
162  template<class Base, class... ConstructorArgs, class FactoryBase, class Deleter>
163  class Factory<Base, TypeList<ConstructorArgs...>, FactoryBase, Deleter> : public virtual FactoryBase {
164 public:
165 // Factory(ParentTs&&... parent_ts) : ParentType(std::forward<ParentTs>(parent_ts)...)
166 // {}
167  Factory() = default;
168  Factory(const Factory &) = delete;
169  Factory(Factory &&) = default;
170  Factory & operator=(const Factory &) = delete;
171  Factory & operator=(Factory &&) = default;
172 
173 
174  /**
175  * Returns a pointer to a new object inheriting from type Base
176  */
177  virtual Base * operator()(ConstructorArgs&&... constructor_args) const = 0;
178 
179  Base * create(ConstructorArgs&&... constructor_args) const {
180  return this->operator()(std::forward<ConstructorArgs>(constructor_args)...);
181  }
182 
183  /**
184  * Returns a unique_ptr to a new object inheriting from type Base
185  */
186  template <class U = Base>
187  std::unique_ptr<U> get_unique(ConstructorArgs&&... args) const {
188 
189  // call operator() on the factory and put the results in a unique pointer
190  return std::unique_ptr<U>((*this)(std::forward<ConstructorArgs>(args)...));
191  }
192 
193  /**
194  * Helper to quickly turn a Base type into another type if allowed
195  */
196  template<class U, class... Args>
197  U * as(Args&&... args) const {
198  // printf("Trying to cast a %s to a %s\n", typeid(Base).name(), typeid(U).name());
199  auto result = this->operator()(std::forward<Args>(args)...);
200  if (dynamic_cast<U*>(result)) {
201  return static_cast<U*>(result);
202  } else {
203  throw BidirectionalException("Could not convert between types");
204  }
205  }
206 };
207 
208 
209 /**
210 * Returns a pure-C++ object of type Child which inherits from type Base. It's Base type and ConstructorArgs...
211 * must match with the Factory it is associated with. You can have it inherit from a type that inherits from v8toolkit::Factory
212 * but v8toolkit::Factory must be in the inheritance chain somewhere
213 */
214 template<
215  class Base,
216  class Child,
217  class FixedParamsTypeList, // parameters to be sent to the constructor that are known at factory creation time
218  class ExternalTypeList,
220  class Deleter = std::default_delete<Child> >
221 class CppFactory;
222 
223 
224 // if the constructor wants a reference to the factory, automatically pass it in
225  template<class Base, class Child, class... ExternalConstructorParams, class... FixedParams, class FactoryBase, class Deleter>
226  class CppFactory<Base,
227  Child,
228  TypeList<FixedParams...>,
229  TypeList<ExternalConstructorParams...>,
230  FactoryBase,
231  Deleter> : public virtual FactoryBase {
232 
233  private:
234  using TupleType = std::tuple<FixedParams...>;
235  TupleType fixed_param_tuple;
236 
237  public:
238 
239 
240  CppFactory(FixedParams &&... fixed_param_values) :
241  fixed_param_tuple(fixed_param_values...) {}
242 
243  CppFactory(const CppFactory &) = delete;
244 
245  CppFactory(CppFactory &&) = default;
246 
247  CppFactory &operator=(const CppFactory &) = delete;
248 
249  CppFactory &operator=(CppFactory &&) = default;
250 
251 
252  template<std::size_t... Is>
253  Base *call_operator_helper(ExternalConstructorParams &&... constructor_args, std::index_sequence<Is...>) const {
254 
255  // must const cast it since this method is const, so the tuple becomes const
256  return new Child(std::forward<FixedParams>(std::get<Is>(const_cast<TupleType &>(fixed_param_tuple)))...,
257  std::forward<ExternalConstructorParams>(constructor_args)...);
258  }
259 
260  virtual Base *operator()(ExternalConstructorParams &&... constructor_args) const override {
261  return call_operator_helper(std::forward<ExternalConstructorParams>(constructor_args)...,
262  std::index_sequence_for<FixedParams...>());
263  }
264  };
265 
266 
267 /**
268 * Returns a JavaScript-extended object inheriting from Base. It's Base type and
269 * *ConstructorParams must match up with the Factory class it is associated
270 *
271 * InternalConstructorParams are ones that will be specified in the javascript code declaring the new type
272 *
273 * ExternalConstructorParams will be potentially change for each instance of that type
274 *
275 * Example of internal vs external parameters: if the base type is "animal" and it takes two parameters
276 * "is_mammal" and "name". Whether or not the derived type is a mammal is known when making the derived type
277 * so it would be an internal parameter, while the name isn't known until the object is constructed so it would
278 * be an external parameter.
279 *
280 * Perhaps the order should be swapped to take external first, since that is maybe more common?
281 */
282  template<
283  class Base,
284  class JSWrapperClass,
285 
286  class Internal,
287  class External,
288  class FactoryBase = Factory<Base, External, EmptyFactoryBase>,
289  class Deleter = std::default_delete<JSWrapperClass>>
290 class JSFactory; // instance of undefined template means your inheritance is wrong and failing sfinae check
291  // sfinae check is almost certainly good
292 
293 // Begin real specialization
294 template<
295  class Base,
296  class JSWrapperClass,
297 
298  class... InternalConstructorParams,
299  class... ExternalConstructorParams,
300  class FactoryBase,
301  class Deleter>
302 class JSFactory<
303  Base,
304  JSWrapperClass,
305 
306  TypeList<InternalConstructorParams...>,
307  TypeList<ExternalConstructorParams...>,
308  FactoryBase,
309  Deleter>
310 
311  : public virtual FactoryBase, public v8toolkit::WrappedClassBase
312 { // Begin JSFactory class
313 
314  using ThisFactoryType = JSFactory<Base, JSWrapperClass, TypeList<InternalConstructorParams...>, TypeList<ExternalConstructorParams...>, FactoryBase>;
315 
316 
317 protected:
318  v8::Isolate * isolate;
319  v8::Global<v8::Context> global_context;
320  // Create base portion of new object using wrapped type
321 
322  // v8toolkit-wrapped Base-type constructor
323  v8::Global<v8::FunctionTemplate> js_base_constructor_function;
324 
325  // javascript callback for creating properties only on the new type
326  v8::Global<v8::Function> js_new_object_constructor_function;
327 
328  v8::Global<v8::Object> js_prototype;
329 
330  func::function<JSWrapperClass * (ExternalConstructorParams&&...)> make_jswrapper_object;
331 
332  using TupleType = std::tuple<InternalConstructorParams...>;
334 
335 
336 public:
337 
338  /**
339  * Helper function for creating JSFactory objects from javascript
340  */
341  template<int starting_info_index, std::size_t... Is>
342  static std::unique_ptr<ThisFactoryType> _create_factory_from_javascript(const v8::FunctionCallbackInfo<v8::Value> & info, std::index_sequence<Is...>) {
343 
344  auto isolate = info.GetIsolate();
345  auto context = isolate->GetCurrentContext();
346 
347  // info.Length() must be sum of any skipped parameters + 2 for the prototype and object callback + 1 for each InternalConstructorParameters
348  constexpr std::size_t parameter_count = starting_info_index + 2 + sizeof...(InternalConstructorParams);
349  if (info.Length() != parameter_count) {
350  throw InvalidCallException(fmt::format("Wrong number of parameters to create new factory - needs {}, got {}", parameter_count, info.Length()));
351  }
352 
353  int i = starting_info_index + 2; // skip the prototype object and object constructor callback as well
354  std::vector<std::unique_ptr<v8toolkit::StuffBase>> stuff;
355 
356  // create unique_ptr with new factory
357  return run_function<
358  std::unique_ptr<ThisFactoryType>, // return type
359  decltype(context), // first parameter type for function
360  decltype(info[starting_info_index + 0]->ToObject()), // second parameter type for function
362  InternalConstructorParams...> // constructor params for function
363 
364  (&std::make_unique<ThisFactoryType, // specify exactly which make_unique to give a function pointer to
365  decltype(context), // repeat types for make_unique
366  decltype(info[starting_info_index + 0]->ToObject()), // repeat types for make_unique
367  v8::Local<v8::Function>,
368  InternalConstructorParams...>, // repeat types for make_unique
369  info, // run_function needs the info object
370  context, // all the rest are the parameters to the actual function call
371  info[starting_info_index + 0]->ToObject(),
372  v8::Local<v8::Function>::Cast(info[starting_info_index + 1]),
373  ParameterBuilder<InternalConstructorParams>()(info, i, stuff)...);
374 
375  }
376 
377 
378  template<std::size_t... Is>
379  std::unique_ptr<JSWrapperClass, Deleter> call_operator_helper(v8::Local<v8::Object> new_js_object,
380  ExternalConstructorParams&&... constructor_args,
381  std::index_sequence<Is...>) const {
382 
383  return std::make_unique<JSWrapperClass>(this->global_context.Get(isolate),
384  new_js_object,
385  this->js_base_constructor_function.Get(isolate), // the v8::FunctionTemplate that created the js object
386 
387  // must const cast it since this method is const, so the tuple becomes const
388  std::forward<InternalConstructorParams>(std::get<Is>(const_cast<TupleType &>(this->internal_param_tuple)))...,
389  std::forward<ExternalConstructorParams>(constructor_args)...);
390  }
391 
392 
393  /**
394  * Takes a context to use while calling a javascript_function that returns an object
395  * inheriting from JSWrapper
396  */
398  v8::Local<v8::Object> prototype,
399  v8::Local<v8::Function> js_new_object_constructor_function,
400  InternalConstructorParams&&... internal_constructor_values) :
401 
402  isolate(context->GetIsolate()),
403  global_context(v8::Global<v8::Context>(isolate, context)),
404 
405  // use the Base type's javascript wrapper type so that all its added data members are available
406  js_base_constructor_function(v8::Global<v8::FunctionTemplate>(isolate, V8ClassWrapper<Base>::get_instance(isolate).get_function_template())),
407  js_new_object_constructor_function(v8::Global<v8::Function>(isolate, js_new_object_constructor_function)),
408  js_prototype(v8::Global<v8::Object>(isolate, prototype)),
409  internal_param_tuple(internal_constructor_values...)
410 
411  {
412 // printf("Created JSFactory object at %p\n", (void*)this);
413 
414 
415 
416  // Create a new object of the full wrapper type (i.e. JSMyType : MyType, JSWrapper<MyTYpe>)
417 
418  // It's wrong to create a new instance for the prototype of each bidirectional object - they should all have the
419  // same prototype (pretty sure)
420  auto new_js_object = js_base_constructor_function.Get(isolate)->GetFunction()->NewInstance();
421  (void) this->js_prototype.Get(isolate)->SetPrototype(context, new_js_object->GetPrototype());
422 
423  // create a callback for making a new object using the internal constructor values provided here - external ones provided at callback time
424  // DO NOT CAPTURE/USE ANY V8::LOCAL VARIABLES IN HERE, only use v8::Global::Get(...)
425  this->make_jswrapper_object =
426  [this](ExternalConstructorParams&&... external_constructor_values) mutable ->JSWrapperClass * {
427 // printf("Using JSFactory object at %p\n", (void*)this);
428 
429  auto context = this->global_context.Get(this->isolate);
430 
431  // Create a new javascript object for Base but then set its prototype to the subclass's prototype
432  v8::Local<v8::Object> new_js_object = this->js_base_constructor_function.Get(isolate)->GetFunction()->NewInstance();
433 
434  (void)new_js_object->SetPrototype(context, this->js_prototype.Get(isolate));
435 
436  // create a JSWrapper<Base> object that knws how to call all the virtual methods on Base
437  auto js_wrapper_class_cpp_object =
438  call_operator_helper(new_js_object,
439  std::forward<ExternalConstructorParams>(external_constructor_values)...,
440  std::index_sequence_for<InternalConstructorParams...>());
441 
442 
443 
444  auto & wrapper = V8ClassWrapper<JSWrapperClass>::get_instance(isolate);
445 
446  // I think thi sneeds to be leave_alone because the CPP object that this would otherwise delete is holding a v8::Global refernce
447  // to the JavaScript object which prevents it from being GC'd before the CPP object has already been deleted.
448  // Also, I was running into double-free errors with this set as _delete.
449  wrapper.template initialize_new_js_object(isolate, new_js_object, js_wrapper_class_cpp_object.get(), *wrapper.destructor_behavior_leave_alone);
450 
451  // call javascript "constructor" method (per-instance)
453  this->js_new_object_constructor_function.Get(isolate),
454  new_js_object,
455  TypeList<ExternalConstructorParams...>(),
456  std::forward<ExternalConstructorParams>(external_constructor_values)...);
457  return js_wrapper_class_cpp_object.release();
458  };
459  }
460 
462 // printf("Deleting JSFactory object at %p\n", (void*)this);
463  }
464 
465 
466 
467  /**
468  * Returns a C++ object inheriting from JSWrapper that wraps a newly created javascript object which
469  * extends the C++ functionality in javascript
470  */
471  virtual Base * operator()(ExternalConstructorParams&&... constructor_parameters) const override {
472  return this->make_jswrapper_object(std::forward<ExternalConstructorParams>(constructor_parameters)...);
473  }
474 
475 
476  template<int starting_info_index>
477  static std::unique_ptr<ThisFactoryType> create_factory_from_javascript(const v8::FunctionCallbackInfo<v8::Value> & info) {
478  return _create_factory_from_javascript<starting_info_index>(info, std::index_sequence_for<InternalConstructorParams...>());
479  }
480 
481 
482  static void wrap_factory(v8::Isolate * isolate) {
484  wrapper.add_method("create", &ThisFactoryType::operator());
485  wrapper.finalize();
486  }
487  };
488 
489 
490 
491 
492 // turn on/off print statements for helping debug JS_ACCESS functionality
493 #define JS_ACCESS_CORE_DEBUG false
494 
495 /**
496 * This code looks for a javascript method on the JavaScript object contained
497 * in the "this" JSWrapper object and call the "name"d method on it. It must work
498 * when this method is called directly to start the method call (using a bidirectional
499 * object from C++) as well as when the method call is started from javascript (where the
500 * javascript interpreter checks the prototype chain initially and might find this function)
501 * If not careful, this function can find itself while looking for a javascript version to call
502 * because even though its methods aren't mapped into javascript, the parent type's are and
503 * dynamic dispatch will call the derived class's version instead of the base class.
504 * That is why static dispatch is specifically used for the C++ fallback case:
505 * `this->BASE_TYPE::name( __VA_ARGS__ );`
506 */
507 #define JS_ACCESS_CORE(ReturnType, name, ...) \
508  bool call_native = this->called_from_javascript; \
509  \
510  /* If there is infinite recursion happening here, it is likely */ \
511  /* that when this function looks for a JavaScript function to call */ \
512  /* it actually finds this function and calls itself. This flag is supposed */ \
513  /* to protect against that but the situations are complicated and this may not be */ \
514  /* sufficient. */ \
515  this->called_from_javascript = false; \
516  if (call_native) { \
517  if(JS_ACCESS_CORE_DEBUG) printf("Calling native version of %s\n", #name); \
518  /* See comment above for why static dispatch is used */ \
519  return this->BASE_TYPE::name( __VA_ARGS__ ); \
520  } \
521  if(JS_ACCESS_CORE_DEBUG) printf("IN JS_ACCESS_CORE for %s, not calling native code\n", #name); \
522  /*auto parameter_tuple = std::make_tuple( __VA_ARGS__ ); */ \
523  /* auto parameter_tuple = make_tuple_for_variables(__VA_ARGS__); */ \
524  v8toolkit::CastToNative<std::remove_reference<ReturnType>::type> cast_to_native; \
525  GLOBAL_CONTEXT_SCOPED_RUN(isolate, global_context); \
526  auto context = global_context.Get(isolate); \
527  auto js_object = global_js_object.Get(isolate); \
528  v8::Local<v8::Function> js_function; \
529  v8::TryCatch tc(isolate); \
530  try { \
531  js_function = v8toolkit::get_key_as<v8::Function>(context, js_object, #name); \
532  } catch (...) {assert(((void)"method probably not added to wrapped parent type", false) == true);} \
533  this->called_from_javascript = true; \
534  auto result = v8toolkit::call_javascript_function_with_vars(context, js_function, js_object, typelist, ##__VA_ARGS__); \
535  this->called_from_javascript = false; \
536  return cast_to_native(isolate, result);
537 
538 
539 // defines a JS_ACCESS function for a method taking no parameters
540 #define JS_ACCESS(return_type, name)\
541 virtual return_type name() override {\
542  v8toolkit::TypeList<> typelist; \
543  JS_ACCESS_CORE(V8TOOLKIT_MACRO_TYPE(return_type), name)\
544 }
545 
546 #define JS_ACCESS_0(return_type, name)\
547 virtual return_type name() override {\
548  v8toolkit::TypeList<> typelist; \
549  JS_ACCESS_CORE(V8TOOLKIT_MACRO_TYPE(return_type), name)\
550 }
551 
552 #define JS_ACCESS_1(return_type, name, t1)\
553 virtual return_type name(t1 p1) override {\
554  v8toolkit::TypeList<t1> typelist; \
555  JS_ACCESS_CORE(V8TOOLKIT_MACRO_TYPE(return_type), name, p1)\
556 }
557 
558 #define JS_ACCESS_2(return_type, name, t1, t2) \
559 virtual return_type name(t1 p1, t2 p2) override { \
560  v8toolkit::TypeList<t1, t2> typelist; \
561  JS_ACCESS_CORE(V8TOOLKIT_MACRO_TYPE(return_type), name, p1, p2) \
562 }
563 
564 #define JS_ACCESS_3(return_type, name, t1, t2, t3)\
565 virtual return_type name(t1 p1, t2 p2, t3 p3) override { \
566  v8toolkit::TypeList<t1, t2, t3> typelist; \
567  JS_ACCESS_CORE(V8TOOLKIT_MACRO_TYPE(return_type), name, p1, p2, p3) \
568 }
569 
570 #define JS_ACCESS_4(return_type, name, t1, t2, t3, t4)\
571 virtual return_type name(t1 p1, t2 p2, t3 p3, t4 p4) override {\
572  v8toolkit::TypeList<t1, t2, t3, t4> typelist; \
573  JS_ACCESS_CORE(V8TOOLKIT_MACRO_TYPE(return_type), name, p1, p2, p3, p4)\
574 }
575 
576 #define JS_ACCESS_5(return_type, name, t1, t2, t3, t4, t5)\
577 virtual return_type name(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5) override {\
578  v8toolkit::TypeList<t1, t2, t3, t4, t5> typelist; \
579  JS_ACCESS_CORE(V8TOOLKIT_MACRO_TYPE(return_type), name, p1, p2, p3, p4, p5)\
580 }
581 
582 #define JS_ACCESS_6(return_type, name, t1, t2, t3, t4, t5, t6)\
583 virtual return_type name(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6) override {\
584  v8toolkit::TypeList<t1, t2, t3, t4, t5, t6> typelist; \
585  JS_ACCESS_CORE(V8TOOLKIT_MACRO_TYPE(return_type), name, p1, p2, p3, p4, p5, p6)\
586 }
587 
588 #define JS_ACCESS_7(return_type, name, t1, t2, t3, t4, t5, t6, t7)\
589 virtual return_type name(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7) override {\
590  v8toolkit::TypeList<t1, t2, t3, t4, t5, t6, t7> typelist; \
591  JS_ACCESS_CORE(V8TOOLKIT_MACRO_TYPE(return_type), name, p1, p2, p3, p4, p5, p6, p7)\
592 }
593 
594 #define JS_ACCESS_8(return_type, name, t1, t2, t3, t4, t5, t6, t7, t8)\
595 virtual return_type name(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8) override {\
596  v8toolkit::TypeList<t1, t2, t3, t4, t5, t6, t7, t8> typelist; \
597  JS_ACCESS_CORE(V8TOOLKIT_MACRO_TYPE(return_type), name, p1, p2, p3, p4, p5, p6, p7, p8)\
598 }
599 
600 #define JS_ACCESS_9(return_type, name, t1, t2, t3, t4, t5, t6, t7, t8, t9)\
601 virtual return_type name(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, t9 p9) override {\
602  v8toolkit::TypeList<t1, t2, t3, t4, t5, t6, t7, t8, t9> typelist; \
603  JS_ACCESS_CORE(V8TOOLKIT_MACRO_TYPE(return_type), name, p1, p2, p3, p4, p5, p6, p7, p8, p9)\
604 }
605 
606 #define JS_ACCESS_CONST(return_type, name)\
607 virtual return_type name() const override {\
608  v8toolkit::TypeList<> typelist; \
609  JS_ACCESS_CORE(V8TOOLKIT_MACRO_TYPE(return_type), name)\
610 }
611 
612 #define JS_ACCESS_0_CONST(return_type, name)\
613 virtual return_type name() const override {\
614  v8toolkit::TypeList<> typelist; \
615  JS_ACCESS_CORE(V8TOOLKIT_MACRO_TYPE(return_type), name)\
616 }
617 
618 
619 #define JS_ACCESS_1_CONST(return_type, name, t1)\
620 virtual return_type name(t1 p1) const override {\
621  v8toolkit::TypeList<t1> typelist; \
622  JS_ACCESS_CORE(V8TOOLKIT_MACRO_TYPE(return_type), name, p1)\
623 }
624 
625 #define JS_ACCESS_2_CONST(return_type, name, t1, t2)\
626 virtual return_type name(t1 p1, t2 p2) const override {\
627  v8toolkit::TypeList<t1, t2> typelist; \
628  JS_ACCESS_CORE(V8TOOLKIT_MACRO_TYPE(return_type), name, p1, p2)\
629 }
630 
631 #define JS_ACCESS_3_CONST(return_type, name, t1, t2, t3)\
632 virtual return_type name(t1 p1, t2 p2, t3 p3) const override {\
633  v8toolkit::TypeList<t1, t2, t3> typelist; \
634  JS_ACCESS_CORE(V8TOOLKIT_MACRO_TYPE(return_type), name, p1, p2, p3)\
635 }
636 
637 #define JS_ACCESS_4_CONST(return_type, name, t1, t2, t3, t4)\
638 virtual return_type name(t1 p1, t2 p2, t3 p3, t4 p4) const override {\
639  v8toolkit::TypeList<t1, t2, t3, t4> typelist; \
640  JS_ACCESS_CORE(V8TOOLKIT_MACRO_TYPE(return_type), name, p1, p2, p3, p4)\
641 }
642 
643 #define JS_ACCESS_5_CONST(return_type, name, t1, t2, t3, t4, t5)\
644 virtual return_type name(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5) const override {\
645  v8toolkit::TypeList<t1, t2, t3, t4, t5> typelist; \
646  JS_ACCESS_CORE(V8TOOLKIT_MACRO_TYPE(return_type), name, p1, p2, p3, p4, p5)\
647 }
648 
649 #define JS_ACCESS_6_CONST(return_type, name, t1, t2, t3, t4, t5, t6)\
650 virtual return_type name(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6) const override {\
651  v8toolkit::TypeList<t1, t2, t3, t4, t5, t6> typelist; \
652  JS_ACCESS_CORE(V8TOOLKIT_MACRO_TYPE(return_type), name, p1, p2, p3, p4, p5, p6)\
653 }
654 
655 #define JS_ACCESS_7_CONST(return_type, name, t1, t2, t3, t4, t5, t6, t7)\
656 virtual return_type name(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7) const override {\
657  v8toolkit::TypeList<t1, t2, t3, t4, t5, t6, t7> typelist; \
658  JS_ACCESS_CORE(V8TOOLKIT_MACRO_TYPE(return_type), name, p1, p2, p3, p4, p5, p6, p7)\
659 }
660 
661 #define JS_ACCESS_8_CONST(return_type, name, t1, t2, t3, t4, t5, t6, t7, t8)\
662 virtual return_type name(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8) const override {\
663  v8toolkit::TypeList<t1, t2, t3, t4, t5, t6, t7, t8> typelist; \
664  JS_ACCESS_CORE(V8TOOLKIT_MACRO_TYPE(return_type), name, p1, p2, p3, p4, p5, p6, p7, p8)\
665 }
666 
667 #define JS_ACCESS_9_CONST(return_type, name, t1, t2, t3, t4, t5, t6, t7, t8, t9)\
668 virtual return_type name(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, t9 p9) const override {\
669  v8toolkit::TypeList<t1, t2, t3, t4, t5, t6, t7, t8, t9> typelist; \
670  JS_ACCESS_CORE(V8TOOLKIT_MACRO_TYPE(return_type), name, p1, p2, p3, p4, p5, p6, p7, p8, p9)\
671 }
672 
673 // This can be extended to any number of parameters you need..
674 
675 }
676 
677 
678 
679 
680 /**
681 Bidirectioal inheritance prototype chain looks like:
682 
683 jswrapper instance
684 jswrapper prototype
685 --- INSERT JAVASCRIPT CREATED PROTOTYPE HERE
686 base object prototype (**)
687 empty object
688 null
689 
690 
691 (**) This is where the `Base`-class implementations are found, but since they are virtual
692  when called with a JSWrapper receiver object, the dynamic dispatch will actually call
693  the JSWrapper JS_ACCESS function unless explicit static dispatch is used.
694 
695 */
696 
std::unique_ptr< JSWrapperClass, Deleter > call_operator_helper(v8::Local< v8::Object > new_js_object, ExternalConstructorParams &&...constructor_args, std::index_sequence< Is... >) const
Base * call_operator_helper(ExternalConstructorParams &&...constructor_args, std::index_sequence< Is... >) const
static std::unique_ptr< ThisFactoryType > _create_factory_from_javascript(const v8::FunctionCallbackInfo< v8::Value > &info, std::index_sequence< Is... >)
::std::string string
Definition: gtest-port.h:1097
v8::Global< v8::Context > global_context
Definition: bidirectional.h:39
internal::ArgsMatcher< InnerMatcher > Args(const InnerMatcher &matcher)
v8::Global< v8::Object > global_js_object
Definition: bidirectional.h:40
virtual const char * what() const noexcept
Definition: bidirectional.h:31
static std::unique_ptr< ThisFactoryType > create_factory_from_javascript(const v8::FunctionCallbackInfo< v8::Value > &info)
JSWrapper(v8::Local< v8::Context > context, v8::Local< v8::Object > object, v8::Local< v8::FunctionTemplate > created_by)
Definition: bidirectional.h:81
std::enable_if_t< std::is_base_of< JSWrapperBase, T >::value, v8::Local< v8::Object > > safe_get_javascript_object(T *object)
Definition: bidirectional.h:89
Definition: sample.cpp:29
v8::Local< v8::Object > get_javascript_object() const
Definition: bidirectional.h:61
auto run_function(func::function< ReturnType(Args...)> &function, const v8::FunctionCallbackInfo< v8::Value > &info, Ts &&...ts) -> ReturnType
Definition: v8helpers.h:90
JSWrapperBase(v8::Local< v8::Context > context, v8::Local< v8::Object > object, v8::Local< v8::FunctionTemplate > created_by)
Definition: bidirectional.h:52
v8::Local< v8::Value > operator()(v8::Isolate *isolate, const JSWrapper< T > &js_wrapper)
v8::Global< v8::FunctionTemplate > global_created_by
Definition: bidirectional.h:41
JSFactory(v8::Local< v8::Context > context, v8::Local< v8::Object > prototype, v8::Local< v8::Function > js_new_object_constructor_function, InternalConstructorParams &&...internal_constructor_values)
v8::Local< v8::Value > call_javascript_function_with_vars(const v8::Local< v8::Context > context, const v8::Local< v8::Function > function, const v8::Local< v8::Object > receiver, const TypeList< OriginalTypes... > &type_list, Ts &&...ts)
Definition: v8toolkit.h:524
BidirectionalException(const std::string &reason)
Definition: bidirectional.h:29
std::unique_ptr< U > get_unique(ConstructorArgs &&...args) const