Интегрирую данный движок в свой проект. В процессе столкнулся с проблемой создания "переходника" из унифицированной сигнатуры колбека в разные сигнатуры экспортируемых функций. Оставляя за кадром подробности, выглядит это примерно так:
| Скрытый текст |
| //экспортируемая функция
int SomeFunc(bool arg1, int arg2)
{
//код
}
//shim function
//Указатель на shim передаётся движку v8 (то есть его сигнатура фиксированная и менять её нельзя).
void SomeFuncShim(const FunctionCallbackInfo<Value>& info)
{
//проверка совпадения кол-ва параметром с ожидаемым
auto argsCnt = info.Length();
if (argsCnt != 2)
{
//ругаемся матом и прекращаем выполнение скрипта, код пропущен
return;
}
//достаём аргументы
//первый
Local<Value> arg1 = info[0];
//распаковываем в нужный тип
bool arg1Val = arg1->Value();
//второй
Local<Value> arg2 = info[1];
int arg2Val = arg2->Value();
//прочие элементарные типы обрабатываются аналогично, за исключением строк - для них отдельный код распаковки
//распаковываем указатель на целевую функцию
auto funcPtr = static_cast<int(*)(bool arg1, int arg2)>(wrap->Value());
//вызываем собственно функцию
int result = funcPtr(arg1Val, arg2Val);
//упаковываем результат и устанавливаем возвращаемое значение
info.GetReturnValue().Set(result);
}
|
| |
Хотелось бы как-то замутить универсальный "переходник" дабы не педалить кучу однотипного кода для разного количества и типов параметров и возвращаемого значения, но тут возникают следующие проблемы:
1. Распаковка параметра в зависимости от целевого типа. Это можно сделать через частичную специализацию по типу такого:
| Скрытый текст |
| template<typename T> T UnpackParameter(const Local<Value>& val)
{
throw std::exception("no specialization exist");
}
template<> int UnpackParameter(const Local<Value>& val)
{
auto arg = val->ToInt32();
return arg->Value();
}
template<> bool UnpackParameter(const Local<Value>& val)
{
auto arg = val->ToBoolean();
return arg->Value();
}
//и т.п. для других типов
//использовать так:
auto arg1 = UnpackParameter<bool>(info[0]);
|
| |
2. Распаковка указателя на функцию:
auto funcPtrVal = info.Data();
auto wrap = Local<External>::Cast(funcPtrVal);
void* funcPtrVoid = wrap->Value();
auto funcPtr = static_cast<int(*)(bool arg1, int arg2)>(funcPtrVoid); //откуда взять тип функции?
Вот тут я забуксовал в первый раз
3. Распаковка всех параметров в зависимости от сигнатуры, а также обратная упаковка возвращаемого значения (если оно есть). Тут тоже затык.
Регистрация функции выглядит так:
global->Set(String::NewFromUtf8(isolate, "SomeFunc"), FunctionTemplate::New(isolate, SomeFuncShim, External::New(isolate, SomeFunc)));
Я подозреваю, что тут можно как-то заюзать variadic templates, но мой опыт в этом деле в районе абсолютного нуля, посему прошу помощи у всезнающего all
Надеюсь, что я достаточно подробно объяснил задачу.