← Back to file list Raw

src/CCallbackHandler.h

#pragma once
#include <vector>
#include <iostream>
#include <memory>
#include <algorithm>
#include <unordered_map>
#include "CFunctionBase.h"
#include "CSwitchable.h"
#include "CFunction.h"
#include "CLuaFunction.h"
#include "CScriptObjectBase.h"
#include "U_SafeLuaCall.h"
class CSmartCallback;
using CSmartCallbackPtr = std::shared_ptr<CSmartCallback>;
class CCallbackHandlerBase : public virtual CSwitchable, public CScriptObjectBase
{
public:
virtual ~CCallbackHandlerBase();
void RegisterCallback(CSmartCallback* callback);
void UnregisterCallback(CSmartCallback* callback);
virtual sol::object CallFromLua(sol::variadic_args va, sol::state_view s) = 0;
virtual std::shared_ptr<CSmartCallback> GetLastFunctionHandleShared() = 0;
virtual CSmartCallbackPtr AddLuaFunction(sol::function func, sol::object name) = 0;
virtual sol::object CallLua(sol::variadic_args va, sol::this_state s) = 0;
DEFINE_SOL_USERTYPE();
virtual void m_deleteFunction(void* ptr) = 0;
virtual void DeleteFunctionAtIndex(size_t index) = 0;
virtual void DeleteFunctionsByName(const std::string& name) = 0;
private:
std::vector<CSmartCallback*> callbacks;
};
class CSmartCallback : public CScriptObjectBase, public std::enable_shared_from_this<CSmartCallback>
{
public:
CSmartCallback() = delete;
CSmartCallback(CCallbackHandlerBase& _handler, void* _func);
~CSmartCallback();
void Invalidate();
void ForceDelete();
bool IsValid() const;
bool V_ScriptInit(std::shared_ptr<sol::state> state, sol::table table) override;
CCallbackHandlerBase& Handler;
void* FunctionPointer = nullptr;
private:
void m_InitiateDeletion();
};
template <typename Ret, typename... Args>
class CCallbackHandler : public CCallbackHandlerBase //TODO add CallByName
{
public:
//out - CPP to LUA
//in - LUA TO CPP
using CLuaArgsOutTransformer = CLuaFunction<Ret, Args...>::CustomOutCallerFunction;
using CLuaArgsInTransformer = CFunctionBase<Ret, Args...>::CustomInCallerFunction;
CCallbackHandler() = default;
CCallbackHandler(CCallbackHandler&&) noexcept = default;
CCallbackHandler& operator=(CCallbackHandler&&) noexcept = default;
CCallbackHandler(const CCallbackHandler&) = delete;
CCallbackHandler& operator=(const CCallbackHandler&) = delete;
~CCallbackHandler()
{
for (auto& func : Functions)
{
CLuaFunction<Ret, Args...>* luafunc = dynamic_cast<CLuaFunction<Ret, Args...>*>(func.get());
if(luafunc) { std::wcout << L"detected lua func at deleting CCallbackHandler\n"; continue; }
}
}
using FuncType = CFunctionBase<Ret, Args...>;
using FuncTypeUniquePtr = std::unique_ptr<FuncType>;
using FuncTypeRawPtr = FuncType*;
using ReturnType = Ret;
using ReturnsVector = typename std::conditional<std::is_void<Ret>::value, std::vector<int>, std::vector<Ret>>::type;
CSmartCallbackPtr AddLuaFunction(sol::function func, sol::object name) override
{
Add(std::make_unique<CLuaFunction<Ret, Args...>>(func));
std::string nm;
if(name.valid() && name.is<std::string>())
{
nm = name.as<std::string>();
if(!nm.empty())
{
Functions.back()->SetName(nm);
}
}
return GetLastFunctionHandleShared();
}
sol::object CallLua(sol::variadic_args va, sol::this_state s) override
{
return CallFromLua(va, s);
}
bool V_ScriptInit(std::shared_ptr<sol::state> _state, sol::table table) override //TODO __call
{
table.set_function("add", [this](sol::function func, sol::object name) -> sol::table
{
Add(std::make_unique<CLuaFunction<Ret, Args...>>(func));
std::string nm;
if(name.valid() && name.is<std::string>())
{
nm = name.as<std::string>();
if(!nm.empty())
{
Functions.back()->SetName(nm);
}
}
sol::table tabl = sol::state_view(func.lua_state()).create_table();
FuncTypeRawPtr ptr = Functions.back().get();
tabl.set_function("delete", [this, ptr]() mutable
{
if(!ptr) { return; }
DeleteFunction(ptr);
ptr = nullptr;
});
tabl.set_function("getSmartDeleter", [this, ptr](sol::this_state ts) mutable
{
auto obj = GetFunctionHandleShared(ptr);
auto ret = obj->GetScriptTable(ts);
ret["__obj"] = obj;
return ret;
});
tabl.set("name", nm);
tabl.set("__ptr", ptr);
return tabl;
});
table.set_function("call", [this](sol::variadic_args va, sol::this_state s) -> sol::object
{
return CallFromLua(va, s);
});
table.set_function("isEnabled", [this](sol::this_state s) -> bool
{
return IsEnabled();
});
table.set_function("setState", [this](bool state, sol::this_state s) -> void
{
return SetEnabledState(state);
});
table.set_function("delete", [this](sol::object obj, sol::this_state s) -> void
{
if(!obj.valid()) { return; }
if(obj.is<sol::table>())
{
sol::table tabl = obj.as<sol::table>();
sol::object del_obj = tabl["delete"];
if(del_obj.valid() && del_obj.is<sol::function>())
{
sol::function del_func = del_obj.as<sol::function>();
SafeCallLua(del_func);
//del_func();
}
}
else if(obj.is<std::string>())
{
std::string nm = obj.as<std::string>();
DeleteFunctionsByName(nm);
}
});
table.set_function("getLastFunctionSmartDeleter", [this](sol::this_state ts) -> sol::object
{
auto obj = GetLastFunctionHandleShared();
auto ret = obj->GetScriptTable(ts);
ret["__obj"] = obj;
return ret;
});
return true;
}
CCallbackHandler& operator+=(FuncTypeUniquePtr&& func)
{
Add(std::move(func));
return *this;
}
FuncTypeRawPtr Add(FuncTypeUniquePtr&& func)
{
Functions.push_back(std::move(func));
SetupSingleFunctionTransformers(Functions.back());
return Functions.back().get();
}
bool IsEmpty() const
{
return Functions.empty();
}
operator bool() const
{
return !Functions.empty();
}
void operator()(Args... args) const
{
return Call(args...);
}
void Call(Args... args) const
{
if (!IsEnabled()) { return; }
for (auto& func : Functions)
{
(*func)(args...);
}
}
sol::object CallFromLua(sol::variadic_args va, sol::state_view s) override
{
if (!IsEnabled()) { return sol::lua_nil; }
if constexpr (std::is_same_v<Ret, void>)
{
for (auto& func : Functions)
{
func->CallFromLua(va, s);
}
return sol::lua_nil;
}
else
{
size_t index = 1;
sol::table ret = s.create_table();
for (auto& func : Functions)
{
ret[index] = func->CallFromLua(va, s);
index++;
}
return ret;
}
}
ReturnsVector CallWithReturns(Args... args) const
{
if (!IsEnabled()) { return ReturnsVector(); }
ReturnsVector ret;
if constexpr (std::is_void_v<Ret>)
{
ret.resize(Functions.size());
std::fill(ret.begin(), ret.end(), int(0));
for (auto& func : Functions)
{
(*func)(args...);
}
return ret;
}
else
{
ret.reserve(Functions.size());
for (auto& func : Functions)
{
Ret result = (*func)(args...);
ret.push_back(result);
}
return ret;
}
}
CFunction<Ret, Args...>* AddFunction(const std::function<Ret(Args...)>& func)
{
Functions.push_back(std::make_unique<CFunction<Ret, Args...>>(func));
SetupSingleFunctionTransformers(Functions.back());
return dynamic_cast<CFunction<Ret, Args...>*>(Functions.back().get());
}
CLuaFunction<Ret, Args...>* AddLuaFunction(const sol::protected_function& func)
{
Add(std::make_unique<CLuaFunction<Ret, Args...>>(func));
return dynamic_cast<CLuaFunction<Ret, Args...>*>(Functions.back().get());
}
CLuaFunction<Ret, Args...>* AddLuaFunction(std::unique_ptr<CLuaFunction<Ret, Args...>>&& func)
{
return dynamic_cast<CLuaFunction<Ret, Args...>*>(Add(func));
}
CCallbackHandler& operator+=(const std::function<Ret(Args...)>& func)
{
AddFunction(func);
return *this;
}
CCallbackHandler& operator+=(const sol::protected_function& func)
{
AddLuaFunction(func);
return *this;
}
bool IsEmpty()
{
return Functions.empty();
}
void SetupLuaTransformers(const CLuaArgsOutTransformer& outtransform, const CLuaArgsInTransformer& intransform)
{
LuaArgsOutTransformer = std::make_unique<CLuaArgsOutTransformer>(outtransform);
LuaArgsInTransformer = std::make_unique<CLuaArgsInTransformer>(intransform);
for(auto& func : Functions)
{
SetupSingleFunctionTransformers(func);
}
}
size_t GetCount()
{
return Functions.size();
}
size_t GetLastIndex()
{
if(IsEmpty()) { return 0; }
return GetCount() - 1;
}
CSmartCallback GetLastFunctionHandle()
{
return CSmartCallback(*this, Functions.empty() ? nullptr : Functions.back().get());
}
std::shared_ptr<CSmartCallback> GetLastFunctionHandleShared() override
{
return std::make_shared<CSmartCallback>(*this, Functions.empty() ? nullptr : Functions.back().get());
}
std::unique_ptr<CSmartCallback> GetLastFunctionHandleUnique()
{
return std::make_unique<CSmartCallback>(*this, Functions.empty() ? nullptr : Functions.back().get());
}
CSmartCallback GetFunctionHandle(FuncTypeRawPtr rawptr)
{
auto it = std::find_if(Functions.begin(), Functions.end(), [rawptr](auto& func) -> bool { return func.get() == rawptr; });
return CSmartCallback(*this, (it == Functions.end()) ? nullptr : (*it).get());
}
std::shared_ptr<CSmartCallback> GetFunctionHandleShared(FuncTypeRawPtr rawptr)
{
auto it = std::find_if(Functions.begin(), Functions.end(), [rawptr](auto& func) -> bool { return func.get() == rawptr; });
return std::make_shared<CSmartCallback>(*this, (it == Functions.end()) ? nullptr : (*it).get());
}
std::unique_ptr<CSmartCallback> GetFunctionHandleUnique(FuncTypeRawPtr rawptr)
{
auto it = std::find_if(Functions.begin(), Functions.end(), [rawptr](auto& func) -> bool { return func.get() == rawptr; });
return std::make_unique<CSmartCallback>(*this, (it == Functions.end()) ? nullptr : (*it).get());
}
FuncTypeUniquePtr& GetLastFunction()
{
if(IsEmpty()) { throw std::runtime_error("No functions"); }
return Functions.back();
}
FuncTypeRawPtr GetLastFunctionRaw()
{
if(IsEmpty()) { return nullptr; }
return Functions.back().get();
}
void DeleteFunctionAtIndex(size_t index) override
{
if(index >= Functions.size()) { return; }
Functions.erase(Functions.begin() + index);
}
void DeleteFunction(FuncTypeUniquePtr& smrptr)
{
auto it = std::find_if(Functions.begin(), Functions.end(), [&smrptr](auto& myptr) -> bool
{
return smrptr == myptr;
});
if(it == Functions.end()) { return; }
Functions.erase(it);
}
void DeleteFunction(FuncTypeRawPtr ptr)
{
auto it = std::find_if(Functions.begin(), Functions.end(), [ptr](auto& myptr) -> bool
{
return ptr == myptr.get();
});
if(it == Functions.end()) { return; }
Functions.erase(it);
}
void m_deleteFunction(void* ptr) override
{
auto it = std::find_if(Functions.begin(), Functions.end(), [ptr](auto& myptr) -> bool
{
return ptr == static_cast<void*>(myptr.get());
});
if(it == Functions.end()) { return; }
Functions.erase(it);
}
void DeleteFunctionsByName(const std::string& name) override
{
if(name.empty()) { return; }
std::erase_if(Functions, [&name](auto& ptr) -> bool
{
return ptr->HasName() && ptr->GetName() == name;
});
}
std::vector<FuncTypeUniquePtr> Functions;
private:
void SetupSingleFunctionTransformers(FuncTypeUniquePtr& func)
{
CLuaFunction<Ret, Args...>* luafunc = dynamic_cast<CLuaFunction<Ret, Args...>*>(func.get());
if(luafunc && LuaArgsOutTransformer)
{
luafunc->MakeCustomOutCaller(*LuaArgsOutTransformer);
}
if(LuaArgsInTransformer)
{
func->MakeCustomInCaller(*LuaArgsInTransformer);
}
}
std::unique_ptr<CLuaArgsOutTransformer> LuaArgsOutTransformer;
std::unique_ptr<CLuaArgsInTransformer> LuaArgsInTransformer;
};