Skip to content

File funcUtil.h

File List > jac > machine > funcUtil.h

Go to the documentation of this file

#pragma once

#include <exception>
#include <quickjs.h>

#include "values.h"

namespace jac {


template<typename Func>
inline JSValue propagateExceptions(ContextRef ctx, Func& f) noexcept {
    try {
        return f();
    }
    catch (Exception& e) {
        return e.throwJS(ctx);
    }
    catch (std::exception& e) {
        return Exception::create(Exception::Type::InternalError, e.what()).throwJS(ctx);
    }
    catch (...) {
        return Exception::create(Exception::Type::InternalError, "unknown error").throwJS(ctx);
    }
}

template<typename Func>
inline JSValue propagateExceptions(ContextRef ctx, Func&& f) noexcept {
    return propagateExceptions(ctx, f);
}

template<typename Func, typename Res, typename... Args>
inline JSValue processCallRaw(ContextRef ctx, JSValueConst, int argc, JSValueConst* argv, Func& f) {
    std::tuple<Args...> args = convertArgs<Args...>(ctx, argv, argc, std::make_index_sequence<sizeof...(Args)>());

    if constexpr (std::is_same_v<Res, void>) {
        std::apply(f, args);
        return JS_UNDEFINED;
    }
    else {
        return Value::from(ctx, std::apply(f, args)).loot().second;
    }
}

template<typename Func, typename Res, typename... Args>
inline Value processCall(ContextRef ctx, ValueWeak, std::vector<ValueWeak> argv, Func& f) {
    std::tuple<Args...> args = convertArgs<Args...>(ctx, argv, std::make_index_sequence<sizeof...(Args)>());

    if constexpr (std::is_same_v<Res, void>) {
        std::apply(f, args);
        return Value::undefined(ctx);
    }
    else {
        return Value::from(ctx, std::apply(f, args));
    }
}

template<typename Func, typename Res>
inline JSValue processCallVariadicRaw(ContextRef ctx, JSValueConst, int argc, JSValueConst* argv, Func& f) {
    std::vector<ValueWeak> args;
    for (int i = 0; i < argc; i++) {
        args.emplace_back(ctx, argv[i]);
    }

    if constexpr (std::is_same_v<Res, void>) {
        f(args);
        return JS_UNDEFINED;
    }
    else {
        return Value::from(ctx, f(args)).loot().second;
    }
}

template<typename Func, typename Res>
inline Value processCallVariadic(ContextRef ctx, ValueWeak, std::vector<ValueWeak> argv, Func& f) {
    if constexpr (std::is_same_v<Res, void>) {
        f(argv);
        return Value::undefined(ctx);
    }
    else {
        return Value::from(ctx, f(argv));
    }
}

template<typename Func, typename Res, typename... Args>
inline Value processCallThis(ContextRef ctx, ValueWeak thisVal, std::vector<ValueWeak> argv, Func& f) {
    std::tuple<Args...> args = convertArgs<Args...>(ctx, argv, std::make_index_sequence<sizeof...(Args)>());

    if constexpr (std::is_same_v<Res, void>) {
        std::apply(f, std::tuple_cat(std::make_tuple(ctx, thisVal), args));
        return Value::undefined(ctx);
    }
    else {
        return Value::from(ctx, std::apply(f, std::tuple_cat(std::make_tuple(ctx, thisVal), args)));
    }
}

template<typename Func, typename Res>
inline Value processCallThisVariadic(ContextRef ctx, ValueWeak thisVal, std::vector<ValueWeak> argv, Func& f) {

    if constexpr (std::is_same_v<Res, void>) {
        f(ctx, thisVal, argv);
        return Value::undefined(ctx);
    }
    else {
        return Value::from(ctx, f(ctx, thisVal, argv));
    }
}

template<typename... Args, std::size_t... Is>
inline std::tuple<Args...> convertArgs([[maybe_unused]]ContextRef ctx, std::vector<ValueWeak> argv, std::index_sequence<Is...>) {
    if (argv.size() != sizeof...(Args)) {
        throw Exception::create(Exception::Type::TypeError, "invalid number of arguments");
    }

    return std::make_tuple(argv[Is].to<Args>()...);
}

template<typename... Args, std::size_t... Is>
inline std::tuple<Args...> convertArgs([[maybe_unused]]ContextRef ctx, JSValueConst* argv, int argc, std::index_sequence<Is...>) {
    if (argc != sizeof...(Args)) {
        throw Exception::create(Exception::Type::TypeError, "invalid number of arguments");
    }

    return std::make_tuple(ValueWeak(ctx, argv[Is]).to<Args>()...);
}


} // namespace jac