Files
PyG2O/source/NoNut/include/Function.h
2025-01-25 00:02:52 +03:00

167 lines
3.9 KiB
C++

#ifndef NONUT_CORE_FUNCTION_H
#define NONUT_CORE_FUNCTION_H
#include <optional>
#include <string>
#include <sqapi.h>
#include "Utils.h"
#define FUNCTION_CTOR(function) function(#function)
namespace nonut
{
class Class;
template <typename ReturnType, typename... Args>
class Function
{
public:
// Ctor for functions
Function(const String& functionName, const SQObject env = getRootTable()) : envObj(env)
{
HSQUIRRELVM vm = Sqrat::DefaultVM::Get();
sq_pushobject(vm, envObj);
sq_pushstring(vm, functionName.c_str(), functionName.length());
// get the function from the root table
if (SQ_FAILED(sq_get(vm, -2)))
{
sq_pop(vm, 1);
throw;
}
// check the type
if (const SQObjectType value_type = sq_gettype(vm, -1); value_type != OT_CLOSURE && value_type !=
OT_NATIVECLOSURE)
{
sq_pop(vm, 2);
throw;
}
// get function and add ref
sq_getstackobj(vm, -1, &funcObj);
sq_addref(vm, &funcObj);
sq_pop(vm, 2);
}
// Ctor for class methods
Function(const String& functionName, const SQObject classObjectInstance,
const SQObject classObject) : envObj(classObjectInstance)
{
HSQUIRRELVM vm = Sqrat::DefaultVM::Get();
isClassMethod = true; // Prevent release of the resources cause we don't own them
sq_pushobject(vm, classObject);
sq_pushstring(vm, functionName.c_str(), functionName.length());
// get the function from the root table
if (SQ_FAILED(sq_get(vm, -2)))
{
sq_pop(vm, 1);
throw;
}
// check the type
if (const SQObjectType value_type = sq_gettype(vm, -1); value_type != OT_CLOSURE && value_type !=
OT_NATIVECLOSURE)
{
sq_pop(vm, 2);
throw;
}
// get function and add ref
sq_getstackobj(vm, -1, &funcObj);
sq_addref(vm, &funcObj);
sq_pop(vm, 2);
}
~Function()
{
if (!isClassMethod)
{
HSQUIRRELVM vm = Sqrat::DefaultVM::Get();
sq_release(vm, &funcObj);
sq_release(vm, &envObj);
sq_resetobject(&funcObj);
sq_resetobject(&envObj);
}
}
ReturnType operator()(Args ... args)
{
HSQUIRRELVM vm = Sqrat::DefaultVM::Get();
const auto top = sq_gettop(vm);
sq_pushobject(vm, funcObj);
sq_pushobject(vm, envObj);
auto debug = sq_gettop(vm);
(sqPushValue(vm, args), ...);
if constexpr (std::is_same_v<ReturnType, void>)
{
debug = sq_gettop(vm);
auto returnCode = sq_call(vm, ARG_COUNT + 1, SQFalse, SQFalse); // TODO: HANDLE ERROR RETURN CODE
sq_pop(vm, 2);
sq_settop(vm, top);
return void();
}
else
{
auto returnCode = sq_call(vm, ARG_COUNT + 1, SQTrue, SQFalse); // TODO: HANDLE ERROR RETURN CODE
std::optional<ReturnType> result;
if constexpr (std::derived_from<ReturnType, CustomType>)
{
result = std::make_optional<ReturnType>();
auto intermediateResult = returnVar<SQObject>();
result.value().convert(intermediateResult);
sq_release(vm, &intermediateResult);
sq_resetobject(&intermediateResult);
}
else if constexpr (std::derived_from<ReturnType, Class>)
{
auto intermediateResult = returnVar<SQObject>();
//result = std::make_optional<ReturnType>(ReturnType(intermediateResult));
result.emplace(ReturnType(intermediateResult));
sq_release(vm, &intermediateResult);
sq_resetobject(&intermediateResult);
}
else
{
result = std::make_optional<ReturnType>(returnVar<ReturnType>());
}
sq_pop(vm, 2);
sq_settop(vm, top);
return result.value();
}
}
[[nodiscard]] SQObject getObject() const
{
return funcObj;
}
private:
SQObject funcObj{};
SQObject envObj{};
bool isClassMethod = false;
static constexpr auto ARG_COUNT{sizeof...(Args)};
static SQObject getRootTable()
{
HSQUIRRELVM vm = Sqrat::DefaultVM::Get();
SQObject rootTable{};
sq_pushroottable(vm);
sq_getstackobj(vm, -1, &rootTable);
sq_addref(vm, &rootTable);
sq_pop(vm, 1); // pop root table
return rootTable;
}
};
}
#endif // NONUT_CORE_FUNCTION_H