Интегрируем v8
От: koandrew Канада http://thingselectronic.blogspot.ca/
Дата: 09.04.15 02:40
Оценка:
Интегрирую данный движок в свой проект. В процессе столкнулся с проблемой создания "переходника" из унифицированной сигнатуры колбека в разные сигнатуры экспортируемых функций. Оставляя за кадром подробности, выглядит это примерно так:
  Скрытый текст
//экспортируемая функция
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 Надеюсь, что я достаточно подробно объяснил задачу.
[КУ] оккупировала армия.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.