diff options
author | RaindropsSys <raindrops@equestria.dev> | 2024-06-13 15:46:03 +0200 |
---|---|---|
committer | RaindropsSys <raindrops@equestria.dev> | 2024-06-13 15:46:03 +0200 |
commit | e44e2fe070484e06d384a31ef2699c3a2d5d474e (patch) | |
tree | 2d5eb5d1b01646270d18cf1f2d94519966d6e7de /updater/sql/win/src/macros.h | |
download | faunerie-e44e2fe070484e06d384a31ef2699c3a2d5d474e.tar.gz faunerie-e44e2fe070484e06d384a31ef2699c3a2d5d474e.tar.bz2 faunerie-e44e2fe070484e06d384a31ef2699c3a2d5d474e.zip |
GitHub migration
Diffstat (limited to 'updater/sql/win/src/macros.h')
-rwxr-xr-x | updater/sql/win/src/macros.h | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/updater/sql/win/src/macros.h b/updater/sql/win/src/macros.h new file mode 100755 index 0000000..3bcde83 --- /dev/null +++ b/updater/sql/win/src/macros.h @@ -0,0 +1,207 @@ +#ifndef NODE_SQLITE3_SRC_MACROS_H +#define NODE_SQLITE3_SRC_MACROS_H + +const char* sqlite_code_string(int code); +const char* sqlite_authorizer_string(int type); +#include <vector> + +// TODO: better way to work around StringConcat? +#include <napi.h> +inline Napi::String StringConcat(Napi::Value str1, Napi::Value str2) { + return Napi::String::New(str1.Env(), str1.As<Napi::String>().Utf8Value() + + str2.As<Napi::String>().Utf8Value() ); +} + +// A Napi substitute IsInt32() +inline bool OtherIsInt(Napi::Number source) { + double orig_val = source.DoubleValue(); + double int_val = static_cast<double>(source.Int32Value()); + if (orig_val == int_val) { + return true; + } else { + return false; + } +} + +#define IS_FUNCTION(cb) \ + !cb.IsUndefined() && cb.IsFunction() + +#define REQUIRE_ARGUMENTS(n) \ + if (info.Length() < (n)) { \ + Napi::TypeError::New(env, "Expected " #n "arguments").ThrowAsJavaScriptException(); \ + return env.Null(); \ + } + + +#define REQUIRE_ARGUMENT_EXTERNAL(i, var) \ + if (info.Length() <= (i) || !info[i].IsExternal()) { \ + Napi::TypeError::New(env, "Argument " #i " invalid").ThrowAsJavaScriptException(); \ + return env.Null(); \ + } \ + Napi::External var = info[i].As<Napi::External>(); + + +#define REQUIRE_ARGUMENT_FUNCTION(i, var) \ + if (info.Length() <= (i) || !info[i].IsFunction()) { \ + Napi::TypeError::New(env, "Argument " #i " must be a function").ThrowAsJavaScriptException(); \ + return env.Null(); \ + } \ + Napi::Function var = info[i].As<Napi::Function>(); + + +#define REQUIRE_ARGUMENT_STRING(i, var) \ + if (info.Length() <= (i) || !info[i].IsString()) { \ + Napi::TypeError::New(env, "Argument " #i " must be a string").ThrowAsJavaScriptException(); \ + return env.Null(); \ + } \ + std::string var = info[i].As<Napi::String>(); + +#define REQUIRE_ARGUMENT_INTEGER(i, var) \ + if (info.Length() <= (i) || !info[i].IsNumber()) { \ + Napi::TypeError::New(env, "Argument " #i " must be an integer").ThrowAsJavaScriptException(); \ + return env.Null(); \ + } \ + int var(info[i].As<Napi::Number>().Int32Value()); + +#define OPTIONAL_ARGUMENT_FUNCTION(i, var) \ + Napi::Function var; \ + if (info.Length() > i && !info[i].IsUndefined()) { \ + if (!info[i].IsFunction()) { \ + Napi::TypeError::New(env, "Argument " #i " must be a function").ThrowAsJavaScriptException(); \ + return env.Null(); \ + } \ + var = info[i].As<Napi::Function>(); \ + } + + +#define OPTIONAL_ARGUMENT_INTEGER(i, var, default) \ + int var; \ + if (info.Length() <= (i)) { \ + var = (default); \ + } \ + else if (info[i].IsNumber()) { \ + if (OtherIsInt(info[i].As<Number>())) { \ + var = info[i].As<Napi::Number>().Int32Value(); \ + } \ + } \ + else { \ + Napi::TypeError::New(env, "Argument " #i " must be an integer").ThrowAsJavaScriptException(); \ + return env.Null(); \ + } + + +#define DEFINE_CONSTANT_INTEGER(target, constant, name) \ + Napi::PropertyDescriptor::Value(#name, Napi::Number::New(env, constant), \ + static_cast<napi_property_attributes>(napi_enumerable | napi_configurable)), + +#define DEFINE_CONSTANT_STRING(target, constant, name) \ + Napi::PropertyDescriptor::Value(#name, Napi::String::New(env, constant), \ + static_cast<napi_property_attributes>(napi_enumerable | napi_configurable)), + +#define EXCEPTION(msg, errno, name) \ + Napi::Value name = Napi::Error::New(env, \ + StringConcat( \ + StringConcat( \ + Napi::String::New(env, sqlite_code_string(errno)), \ + Napi::String::New(env, ": ") \ + ), \ + (msg) \ + ).Utf8Value() \ + ).Value(); \ + Napi::Object name ##_obj = name.As<Napi::Object>(); \ + (name ##_obj).Set( Napi::String::New(env, "errno"), Napi::Number::New(env, errno)); \ + (name ##_obj).Set( Napi::String::New(env, "code"), \ + Napi::String::New(env, sqlite_code_string(errno))); + + +#define EMIT_EVENT(obj, argc, argv) \ + TRY_CATCH_CALL((obj), \ + (obj).Get("emit").As<Napi::Function>(),\ + argc, argv \ + ); + +// The Mac OS compiler complains when argv is NULL unless we +// first assign it to a locally defined variable. +#define TRY_CATCH_CALL(context, callback, argc, argv, ...) \ + Napi::Value* passed_argv = argv;\ + std::vector<napi_value> args;\ + if ((argc != 0) && (passed_argv != NULL)) {\ + args.assign(passed_argv, passed_argv + argc);\ + }\ + Napi::Value res = (callback).Call(Napi::Value(context), args); \ + if (res.IsEmpty()) return __VA_ARGS__; + +#define WORK_DEFINITION(name) \ + Napi::Value name(const Napi::CallbackInfo& info); \ + static void Work_Begin##name(Baton* baton); \ + static void Work_##name(napi_env env, void* data); \ + static void Work_After##name(napi_env env, napi_status status, void* data); + +#ifdef DEBUG + #define ASSERT_STATUS() assert(status == 0); +#else + #define ASSERT_STATUS() (void)status; +#endif + +#define CREATE_WORK(name, workerFn, afterFn) \ + int status = napi_create_async_work(env, NULL, Napi::String::New(env, name),\ + workerFn, afterFn, baton, &baton->request); \ + \ + ASSERT_STATUS(); \ + napi_queue_async_work(env, baton->request); + +#define STATEMENT_BEGIN(type) \ + assert(baton); \ + assert(baton->stmt); \ + assert(!baton->stmt->locked); \ + assert(!baton->stmt->finalized); \ + assert(baton->stmt->prepared); \ + baton->stmt->locked = true; \ + baton->stmt->db->pending++; \ + auto env = baton->stmt->Env(); \ + CREATE_WORK("sqlite3.Statement."#type, Work_##type, Work_After##type); + +#define STATEMENT_INIT(type) \ + type* baton = static_cast<type*>(data); \ + Statement* stmt = baton->stmt; + +#define STATEMENT_MUTEX(name) \ + if (!stmt->db->_handle) { \ + stmt->status = SQLITE_MISUSE; \ + stmt->message = "Database handle is closed"; \ + return; \ + } \ + sqlite3_mutex* name = sqlite3_db_mutex(stmt->db->_handle); + +#define STATEMENT_END() \ + assert(stmt->locked); \ + assert(stmt->db->pending); \ + stmt->locked = false; \ + stmt->db->pending--; \ + stmt->Process(); \ + stmt->db->Process(); + +#define BACKUP_BEGIN(type) \ + assert(baton); \ + assert(baton->backup); \ + assert(!baton->backup->locked); \ + assert(!baton->backup->finished); \ + assert(baton->backup->inited); \ + baton->backup->locked = true; \ + baton->backup->db->pending++; \ + auto env = baton->backup->Env(); \ + CREATE_WORK("sqlite3.Backup."#type, Work_##type, Work_After##type); + +#define BACKUP_INIT(type) \ + type* baton = static_cast<type*>(data); \ + Backup* backup = baton->backup; + +#define BACKUP_END() \ + assert(backup->locked); \ + assert(backup->db->pending); \ + backup->locked = false; \ + backup->db->pending--; \ + backup->Process(); \ + backup->db->Process(); + +#endif
\ No newline at end of file |