polardbxengine/storage/ndb/nodejs/jones-ndb/impl/include/common/AsyncMethodCall.h

486 lines
14 KiB
C++

/*
Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2.0,
as published by the Free Software Foundation.
This program is also distributed with certain software (including
but not limited to OpenSSL) that is licensed under separate terms,
as designated in a particular file or component or in included license
documentation. The authors of MySQL hereby grant you an additional
permission to link the program and your derivative works with the
separately licensed software that they have included with MySQL.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License, version 2.0, for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef NODEJS_ADAPTER_INCLUDE_ASYNCMETHODCALL_H
#define NODEJS_ADAPTER_INCLUDE_ASYNCMETHODCALL_H
#include <assert.h>
#include "JsConverter.h"
#include "async_common.h"
using v8::Function;
using v8::Value;
using v8::Handle;
using v8::Isolate;
/** These classes wrap various sorts of C and C++ functions for use as either
* synchronous or asynchronous JavaScript methods.
*
* There are two class hierarchies declared here.
* The first hierarchy is:
* AsyncCall
* -> Call_Returning<R> template over return type
* -> NativeMethodCall<R, C> template over class
*
* The second hierarchy is a set of alternate classes
* Call_1_<A0> , Call_2_<A0,A1> , .. Call_8_<A0,A1, .. A7>
* expressing the set of arguments to a function or method call
*
* The base class AsyncCall wraps the worker-thread run() routine and the
* main thread (post-run) doAsyncCallback() needed for async execution.
*
* The run() method, declared void run(void), will be scheduled to run in a
* uv worker thread.
*
* The doAsyncCallback() method will take a JavaScript context. It is expected
* to prepare the result and call the user's callback function.
*
* The templated class AsyncCall_Returning<R> inherits from AsyncCall and
* adds a return type, which is initialized at 0.
*
* OTHER NOTES:
* The standard AsyncCall constructor allocates a persistent V8 object, so
* it can only run in the main JavaScript thread.
* However, the constructor for AsyncAsyncCall runs in a UV worker thread,
* so there is an alternative chain of protected constructors from
* AsyncAsyncCall up to AsyncCall.
*/
/** Base class
**/
class AsyncCall {
protected:
/* Member variables */
Persistent<Function> callback;
Isolate * isolate;
/* Protected constructor chain from AsyncAsyncCall */
AsyncCall(Isolate * i, Handle<Function> cb) :
isolate(i)
{
callback.Reset(isolate, cb);
};
public:
AsyncCall(Isolate * i, Local<Value> callbackFunc) :
isolate(i)
{
callback.Reset(isolate, Local<Function>::Cast(callbackFunc));
}
/* Destructor */
virtual ~AsyncCall() {
callback.Reset();
}
/* Methods (Pure virtual) */
virtual void run(void) = 0;
virtual void doAsyncCallback(Local<Object>) = 0;
/* Base Class Virtual Methods */
virtual void handleErrors(void) { }
/* Base Class Fixed Methods */
void runAsync() {
// if (callback->IsCallable()) {
uv_work_t * req = new uv_work_t;
req->data = (void *) this;
uv_queue_work(uv_default_loop(), req, work_thd_run, main_thd_complete);
// }
//else {
// isolate->ThrowException(
// Exception::TypeError(String::New("Uncallable Callback")));
//}
}
};
/** ReturnValueHandler is a base class for AsyncCall_Returning<RETURN_TYPE>
with one specialization for wrapped pointers to native objects, and
another specialization for everything else.
**/
// Primary Template: ReturnValueHandler for all non-pointer types
template<typename T>
class ReturnValueHandler {
public:
ReturnValueHandler<T>() {}
void wrapReturnValueAs(Envelope * e) { assert(false); }
Local<Value> getJsValue(Isolate * isolate, T value) {
return toJS(isolate, value);
}
};
// ReturnValueHandler specialization for wrapped pointer types
template<typename T>
class ReturnValueHandler<T*> {
private:
Envelope * envelope;
public:
ReturnValueHandler<T *>() : envelope(0) {}
void wrapReturnValueAs(Envelope * e) { envelope = e; }
Local<Value> getJsValue(Isolate * isolate, T * objPtr) {
return envelope->wrap(objPtr);
}
};
/** First-level template class;
templated over return types
**/
template <typename RETURN_TYPE>
class AsyncCall_Returning : public AsyncCall,
public ReturnValueHandler<RETURN_TYPE>
{
protected:
/* Protected Constructor Chain */
AsyncCall_Returning<RETURN_TYPE>(Isolate * isol, Handle<Function> callback) :
AsyncCall(isol, callback), ReturnValueHandler<RETURN_TYPE>(), error(0) {}
public:
/* Member variables */
NativeCodeError *error;
RETURN_TYPE return_val;
/* Constructors */
AsyncCall_Returning<RETURN_TYPE>(Isolate * isol, Local<Value> callback) :
AsyncCall(isol, callback), ReturnValueHandler<RETURN_TYPE>(), error(0) {}
AsyncCall_Returning<RETURN_TYPE>(Isolate * isol, Local<Value> callback, RETURN_TYPE rv) :
AsyncCall(isol, callback), ReturnValueHandler<RETURN_TYPE>(), error(0),
return_val(rv) {}
/* Destructor */
virtual ~AsyncCall_Returning<RETURN_TYPE>() {
if(error) delete error;
}
/* Methods */
Local<Value> jsReturnVal() {
EscapableHandleScope scope(AsyncCall::isolate);
return scope.Escape(this->getJsValue(AsyncCall::isolate, return_val));
}
/* doAsyncCallback() is an async callback, run by main_thread_complete().
*/
void doAsyncCallback(Local<Object> context) {
EscapableHandleScope scope(AsyncCall::isolate);
Handle<Value> cb_args[2];
if(error) cb_args[0] = error->toJS();
else cb_args[0] = Null(AsyncCall::isolate);
cb_args[1] = this->getJsValue(AsyncCall::isolate, return_val);
ToLocal(& callback)->Call(context, 2, cb_args);
}
};
/** Second-level template class for C++ method calls:
templated over class of native object.
This class is the home of error handling for C++ code.
**/
template <typename R, typename C>
class NativeMethodCall : public AsyncCall_Returning<R> {
public:
/* Member variables */
typedef NativeCodeError * (*errorHandler_fn_t)(R, C *);
C * native_obj;
errorHandler_fn_t errorHandler;
/* Constructor */
NativeMethodCall<R, C>(const Arguments &args, int callback_idx) :
AsyncCall_Returning<R>(args.GetIsolate(), args[callback_idx]),
errorHandler(0)
{
native_obj = unwrapPointer<C *>(args.Holder());
DEBUG_ASSERT(native_obj != NULL);
}
/* Methods */
void handleErrors(void) {
if(errorHandler) AsyncCall_Returning<R>::error =
errorHandler(AsyncCall_Returning<R>::return_val, native_obj);
}
protected:
/* Alternative constructor used only by AsyncAsyncCall */
NativeMethodCall<R, C>(C * obj,
Handle<Function> callback,
errorHandler_fn_t errHandler) :
AsyncCall_Returning<R>(v8::Isolate::GetCurrent(), callback),
native_obj(obj),
errorHandler(errHandler) {};
};
/** AsyncAsyncCall is used to wrap returns from NDB Asynchronoous APIs.
**/
template <typename R, typename C>
class AsyncAsyncCall : public NativeMethodCall<R, C> {
public:
typedef NativeCodeError * (*errorHandler_fn_t)(R, C *);
/* Constructor */
AsyncAsyncCall<R, C>(C * obj, Handle<Function> callback,
errorHandler_fn_t errHandler) :
NativeMethodCall<R, C>(obj, callback, errHandler) {};
/* Methods */
void run(void) {};
};
/** Alternate second-level template class for calls returning void.
No error handling here.
**/
template <typename C>
class NativeVoidMethodCall : public AsyncCall_Returning<int> {
public:
/* Member variables */
C * native_obj;
/* Constructor */
NativeVoidMethodCall<C>(const Arguments &args, int callback_idx) :
AsyncCall_Returning<int>(args.GetIsolate(), args[callback_idx], 1) /*callback*/
{
native_obj = unwrapPointer<C *>(args.Holder());
DEBUG_ASSERT(native_obj != NULL);
}
};
/** Base class templated over arguments
*/
template <typename A0, typename A1, typename A2, typename A3,
typename A4, typename A5, typename A6, typename A7>
class Call_8_ {
public:
/* Member variables */
JsValueConverter<A0> arg0converter; A0 arg0;
JsValueConverter<A1> arg1converter; A1 arg1;
JsValueConverter<A2> arg2converter; A2 arg2;
JsValueConverter<A3> arg3converter; A3 arg3;
JsValueConverter<A4> arg4converter; A4 arg4;
JsValueConverter<A5> arg5converter; A5 arg5;
JsValueConverter<A6> arg6converter; A6 arg6;
JsValueConverter<A7> arg7converter; A7 arg7;
/* Constructor */
Call_8_<A0, A1, A2, A3, A4, A5, A6, A7>(const Arguments &args) :
arg0converter(args[0]),
arg1converter(args[1]),
arg2converter(args[2]),
arg3converter(args[3]),
arg4converter(args[4]),
arg5converter(args[5]),
arg6converter(args[6]),
arg7converter(args[7])
{
arg0 = arg0converter.toC();
arg1 = arg1converter.toC();
arg2 = arg2converter.toC();
arg3 = arg3converter.toC();
arg4 = arg4converter.toC();
arg5 = arg5converter.toC();
arg6 = arg6converter.toC();
arg7 = arg7converter.toC();
}
};
template <typename A0, typename A1, typename A2, typename A3,
typename A4, typename A5, typename A6>
class Call_7_ {
public:
/* Member variables */
JsValueConverter<A0> arg0converter; A0 arg0;
JsValueConverter<A1> arg1converter; A1 arg1;
JsValueConverter<A2> arg2converter; A2 arg2;
JsValueConverter<A3> arg3converter; A3 arg3;
JsValueConverter<A4> arg4converter; A4 arg4;
JsValueConverter<A5> arg5converter; A5 arg5;
JsValueConverter<A6> arg6converter; A6 arg6;
/* Constructor */
Call_7_<A0, A1, A2, A3, A4, A5, A6>(const Arguments &args) :
arg0converter(args[0]),
arg1converter(args[1]),
arg2converter(args[2]),
arg3converter(args[3]),
arg4converter(args[4]),
arg5converter(args[5]),
arg6converter(args[6])
{
arg0 = arg0converter.toC();
arg1 = arg1converter.toC();
arg2 = arg2converter.toC();
arg3 = arg3converter.toC();
arg4 = arg4converter.toC();
arg5 = arg5converter.toC();
arg6 = arg6converter.toC();
}
};
template <typename A0, typename A1, typename A2, typename A3,
typename A4, typename A5>
class Call_6_ {
public:
/* Member variables */
JsValueConverter<A0> arg0converter; A0 arg0;
JsValueConverter<A1> arg1converter; A1 arg1;
JsValueConverter<A2> arg2converter; A2 arg2;
JsValueConverter<A3> arg3converter; A3 arg3;
JsValueConverter<A4> arg4converter; A4 arg4;
JsValueConverter<A5> arg5converter; A5 arg5;
/* Constructor */
Call_6_<A0, A1, A2, A3, A4, A5>(const Arguments &args) :
arg0converter(args[0]),
arg1converter(args[1]),
arg2converter(args[2]),
arg3converter(args[3]),
arg4converter(args[4]),
arg5converter(args[5])
{
arg0 = arg0converter.toC();
arg1 = arg1converter.toC();
arg2 = arg2converter.toC();
arg3 = arg3converter.toC();
arg4 = arg4converter.toC();
arg5 = arg5converter.toC();
}
};
template <typename A0, typename A1, typename A2, typename A3, typename A4>
class Call_5_ {
public:
/* Member variables */
JsValueConverter<A0> arg0converter; A0 arg0;
JsValueConverter<A1> arg1converter; A1 arg1;
JsValueConverter<A2> arg2converter; A2 arg2;
JsValueConverter<A3> arg3converter; A3 arg3;
JsValueConverter<A4> arg4converter; A4 arg4;
/* Constructor */
Call_5_<A0, A1, A2, A3, A4>(const Arguments &args) :
arg0converter(args[0]),
arg1converter(args[1]),
arg2converter(args[2]),
arg3converter(args[3]),
arg4converter(args[4])
{
arg0 = arg0converter.toC();
arg1 = arg1converter.toC();
arg2 = arg2converter.toC();
arg3 = arg3converter.toC();
arg4 = arg4converter.toC();
}
};
template <typename A0, typename A1, typename A2, typename A3>
class Call_4_ {
public:
/* Member variables */
JsValueConverter<A0> arg0converter; A0 arg0;
JsValueConverter<A1> arg1converter; A1 arg1;
JsValueConverter<A2> arg2converter; A2 arg2;
JsValueConverter<A3> arg3converter; A3 arg3;
/* Constructor */
Call_4_<A0, A1, A2, A3>(const Arguments &args) :
arg0converter(args[0]),
arg1converter(args[1]),
arg2converter(args[2]),
arg3converter(args[3])
{
arg0 = arg0converter.toC();
arg1 = arg1converter.toC();
arg2 = arg2converter.toC();
arg3 = arg3converter.toC();
}
};
template <typename A0, typename A1, typename A2>
class Call_3_ {
public:
/* Member variables */
JsValueConverter<A0> arg0converter; A0 arg0;
JsValueConverter<A1> arg1converter; A1 arg1;
JsValueConverter<A2> arg2converter; A2 arg2;
/* Constructor */
Call_3_<A0, A1, A2>(const Arguments &args) :
arg0converter(args[0]),
arg1converter(args[1]),
arg2converter(args[2])
{
arg0 = arg0converter.toC();
arg1 = arg1converter.toC();
arg2 = arg2converter.toC();
}
};
template <typename A0, typename A1>
class Call_2_ {
public:
/* Member variables */
JsValueConverter<A0> arg0converter; A0 arg0;
JsValueConverter<A1> arg1converter; A1 arg1;
/* Constructor */
Call_2_<A0, A1>(const Arguments &args) :
arg0converter(args[0]),
arg1converter(args[1])
{
arg0 = arg0converter.toC();
arg1 = arg1converter.toC();
}
};
template <typename A0>
class Call_1_ {
public:
/* Member variables */
JsValueConverter<A0> arg0converter; A0 arg0;
/* Constructor */
Call_1_<A0>(const Arguments &args) :
arg0converter(args[0])
{
arg0 = arg0converter.toC();
}
};
#endif