#ifndef _ADDON_TOOLS_HPP_ #define _ADDON_TOOLS_HPP_ #include #define NAN_HS Nan::HandleScope scope; #define RET_VALUE(VAL) info.GetReturnValue().Set(VAL); #define RET_UNDEFINED RET_VALUE(Nan::Undefined()); typedef v8::Local V8_VAR_VAL; typedef v8::Local V8_VAR_OBJ; typedef v8::Local V8_VAR_ARR; typedef v8::Local V8_VAR_STR; typedef v8::Local V8_VAR_FUNC; typedef v8::Local V8_VAR_FT; typedef v8::Local V8_VAR_OT; typedef Nan::Persistent V8_STORE_FT; typedef Nan::Persistent V8_STORE_FUNC; typedef Nan::Persistent V8_STORE_OBJ; typedef Nan::Persistent V8_STORE_VAL; #define JS_STR(...) Nan::New(__VA_ARGS__).ToLocalChecked() #define JS_UTF8(...) Nan::New(__VA_ARGS__).ToLocalChecked() #define JS_INT(val) Nan::New(val) #define JS_INT32(val) Nan::New(val) #define JS_UINT32(val) Nan::New(val) #define JS_NUM(val) Nan::New(val) #define JS_OFFS(val) Nan::New(static_cast(val)) #define JS_FLOAT(val) Nan::New(val) #define JS_DOUBLE(val) Nan::New(val) #define JS_EXT(val) Nan::New(reinterpret_cast(val)) #define JS_BOOL(val) (val) ? Nan::True() : Nan::False() #define JS_FUN(val) Nan::New(val) #define JS_OBJ(val) Nan::New(val) #define REQ_ARGS(N) \ if (info.Length() < (N)) \ return Nan::ThrowTypeError("Expected at least " #N " arguments"); #define IS_ARG_EMPTY(I) (info[I]->IsNull() || info[I]->IsUndefined()) #define CHECK_REQ_ARG(I, C, T) \ if (info.Length() <= (I) || ! info[I]->C) \ return Nan::ThrowTypeError("Argument " #I " must be " T); #define CHECK_LET_ARG(I, C, T) \ if ( ! (IS_ARG_EMPTY(I) || info[I]->C) ) \ return Nan::ThrowTypeError("Argument " #I " must be " T " or null"); #define REQ_UTF8_ARG(I, VAR) \ CHECK_REQ_ARG(I, IsString(), "string"); \ Nan::Utf8String VAR(info[I]); #define LET_UTF8_ARG(I, VAR) \ CHECK_LET_ARG(I, IsString(), "string"); \ Nan::Utf8String VAR(JS_STR("")); #define REQ_STR_ARG(I, VAR) REQ_UTF8_ARG(I, VAR) #define LET_STR_ARG(I, VAR) LET_UTF8_ARG(I, VAR) #define REQ_INT32_ARG(I, VAR) \ CHECK_REQ_ARG(I, IsInt32(), "int32"); \ int VAR = info[I]->Int32Value(); #define LET_INT32_ARG(I, VAR) \ CHECK_LET_ARG(I, IsInt32(), "int32"); \ int VAR = IS_ARG_EMPTY(I) ? 0 : info[I]->Int32Value(); #define REQ_UINT32_ARG(I, VAR) \ CHECK_REQ_ARG(I, IsUint32(), "uint32"); \ unsigned int VAR = info[I]->Uint32Value(); #define LET_UINT32_ARG(I, VAR) \ CHECK_LET_ARG(I, IsUint32(), "uint32"); \ unsigned int VAR = IS_ARG_EMPTY(I) ? 0 : info[I]->Uint32Value(); #define REQ_INT_ARG(I, VAR) LET_INT32_ARG(I, VAR) #define LET_INT_ARG(I, VAR) REQ_UINT32_ARG(I, VAR) #define REQ_BOOL_ARG(I, VAR) \ CHECK_REQ_ARG(I, IsBoolean(), "bool"); \ bool VAR = info[I]->BooleanValue(); #define LET_BOOL_ARG(I, VAR) \ CHECK_LET_ARG(I, IsBoolean(), "bool"); \ bool VAR = IS_ARG_EMPTY(I) ? false : info[I]->BooleanValue(); #define REQ_OFFS_ARG(I, VAR) \ CHECK_REQ_ARG(I, IsNumber(), "number"); \ size_t VAR = static_cast(info[I]->IntegerValue()); #define LET_OFFS_ARG(I, VAR) \ CHECK_LET_ARG(I, IsNumber(), "number"); \ size_t VAR = IS_ARG_EMPTY(I) ? 0 : static_cast(info[I]->IntegerValue()); #define REQ_DOUBLE_ARG(I, VAR) \ CHECK_REQ_ARG(I, IsNumber(), "number"); \ double VAR = info[I]->NumberValue(); #define LET_DOUBLE_ARG(I, VAR) \ CHECK_LET_ARG(I, IsNumber(), "number"); \ double VAR = IS_ARG_EMPTY(I) ? 0.0 : info[I]->NumberValue(); #define REQ_FLOAT_ARG(I, VAR) \ CHECK_REQ_ARG(I, IsNumber(), "number"); \ float VAR = static_cast(info[I]->NumberValue()); #define LET_FLOAT_ARG(I, VAR) \ CHECK_LET_ARG(I, IsNumber(), "number"); \ float VAR = IS_ARG_EMPTY(I) ? 0.f : static_cast(info[I]->NumberValue()); #define REQ_EXT_ARG(I, VAR) \ CHECK_REQ_ARG(I, IsExternal(), "void*"); \ v8::Local VAR = v8::Local::Cast(info[I]); #define LET_EXT_ARG(I, VAR) \ CHECK_LET_ARG(I, IsExternal(), "number"); \ v8::Local VAR = IS_ARG_EMPTY(I) ? JS_EXT(nullptr) : \ v8::Local::Cast(info[I]); #define REQ_FUN_ARG(I, VAR) \ CHECK_REQ_ARG(I, IsFunction(), "function"); \ v8::Local VAR = v8::Local::Cast(info[I]); #define REQ_OBJ_ARG(I, VAR) \ CHECK_REQ_ARG(I, IsObject(), "object"); \ v8::Local VAR = v8::Local::Cast(info[I]); #define REQ_ARRV_ARG(I, VAR) \ REQ_OBJ_ARG(I, _obj_##VAR); \ if( ! _obj_##VAR->IsArrayBufferView() ) \ return Nan::ThrowTypeError("Argument " #I " must be an array buffer");\ v8::Local VAR = v8::Local::Cast(_obj_##VAR); #define SET_PROP(OBJ, KEY, VAL) OBJ->Set(JS_STR(KEY), VAL); #define SET_I(ARR, I, VAL) ARR->Set(I, VAL); #define CTOR_CHECK(T) \ if ( ! info.IsConstructCall() ) \ return Nan::ThrowTypeError(T " must be called with the 'new' keyword."); #define DES_CHECK \ if (_isDestroyed) return; #define SETTER_CHECK(C, T) \ if ( ! value->C ) \ return Nan::ThrowTypeError("Value must be " T); #define ACCESSOR_RW(OBJ, NAME) \ Nan::SetAccessor(OBJ, JS_STR(#NAME), NAME ## Getter, NAME ## Setter); #define ACCESSOR_R(OBJ, NAME) \ Nan::SetAccessor(OBJ, JS_STR(#NAME), NAME ## Getter); #define SETTER_UTF8_ARG \ SETTER_CHECK(IsString(), "string"); \ Nan::Utf8String v(value); #define SETTER_STR_ARG SETTER_UTF8_ARG #define SETTER_INT32_ARG \ SETTER_CHECK(IsInt32(), "int32"); \ int v = value->Int32Value(); #define SETTER_INT_ARG SETTER_INT32_ARG #define SETTER_BOOL_ARG \ SETTER_CHECK(IsBoolean(), "bool"); \ bool v = value->BooleanValue(); #define SETTER_UINT32_ARG \ SETTER_CHECK(IsUint32(), "uint32"); \ unsigned int v = value->Uint32Value(); #define SETTER_OFFS_ARG \ SETTER_CHECK(IsNumber(), "number"); \ size_t v = static_cast(value->IntegerValue()); #define SETTER_DOUBLE_ARG \ SETTER_CHECK(IsNumber(), "number"); \ double v = value->NumberValue(); #define SETTER_FLOAT_ARG \ SETTER_CHECK(IsNumber(), "number"); \ float v = static_cast(value->NumberValue()); #define SETTER_EXT_ARG \ SETTER_CHECK(IsExternal(), "void*"); \ v8::Local v = v8::Local::Cast(value); #define SETTER_FUN_ARG \ SETTER_CHECK(IsFunction(), "function"); \ v8::Local v = v8::Local::Cast(value); #define SETTER_OBJ_ARG \ SETTER_CHECK(IsObject(), "object"); \ v8::Local v = v8::Local::Cast(value); #define SETTER_ARRV_ARG \ SETTER_CHECK(IsObject(), "object"); \ v8::Local _obj_v = v8::Local::Cast(value); \ if( ! _obj_v->IsArrayBufferView() ) \ return Nan::ThrowTypeError("The value must be an array buffer"); \ v8::Local v = v8::Local::Cast(_obj_v); template inline Type* getArrayData(V8_VAR_OBJ obj, int *num = nullptr) { Type *data = nullptr; if (num) { *num = 0; } if ( ! arg->IsArrayBufferView() ) { Nan::ThrowError("Argument must be a TypedArray."); return data; } v8::Local arr = v8::Local::Cast(arg); if (num) { *num = arr->ByteLength() / sizeof(Type); } data = reinterpret_cast(arr->Buffer()->GetContents().Data()); return data; } inline void *getData(V8_VAR_OBJ obj) { void *pixels = nullptr; if (obj->IsArrayBufferView()) { pixels = getArrayData(obj); } else if (obj->Has(JS_STR("data"))) { pixels = node::Buffer::Data(Nan::Get(obj, JS_STR("data")).ToLocalChecked()); } else { Nan::ThrowError("Bad argument"); } return pixels; } inline void consoleLog(int argc, V8_VAR_VAL *argv) { V8_VAR_STR code = JS_STR("((...args) => console.log(...args))"); V8_VAR_FUNC log = V8_VAR_FUNC::Cast(v8::Script::Compile(code)->Run()); Nan::Callback logCb(log); Nan::AsyncResource async("consoleLog()"); logCb.Call(argc, argv, &async); } inline void consoleLog(const std::string &message) { V8_VAR_VAL arg = JS_STR(message); consoleLog(1, &arg); } #endif // _ADDON_TOOLS_HPP_