mirror of
https://github.com/ModOrganizer2/modorganizer-plugin_python.git
synced 2026-07-27 14:03:33 -07:00
143 lines
5.6 KiB
C++
143 lines
5.6 KiB
C++
#ifndef PYTHONWRAPPERUTILITIES_H
|
|
#define PYTHONWRAPPERUTILITIES_H
|
|
|
|
#include <functional>
|
|
|
|
#include <boost/python.hpp>
|
|
|
|
#include <log.h>
|
|
#include <utility.h>
|
|
|
|
#include "sipApiAccess.h"
|
|
#include "error.h"
|
|
#include "gilock.h"
|
|
|
|
namespace details {
|
|
|
|
/**
|
|
* @brief Common stuffs for all basicWrapperFunction methods.
|
|
*/
|
|
template <class ReturnType, class WrapperTypePtr, class Fn, class... Args>
|
|
ReturnType wrapperFunctionImplementation(WrapperTypePtr wrapper, bool apiTransfer, Fn fn, boost::python::object* objPtr, const char *methodName, Args... args) {
|
|
GILock lock;
|
|
boost::python::override implementation = wrapper->get_override(methodName);
|
|
if (!implementation) {
|
|
if constexpr (std::is_same_v<Fn, std::nullptr_t>) {
|
|
throw pyexcept::MissingImplementation(wrapper->className, methodName);
|
|
}
|
|
else {
|
|
return std::invoke(fn, wrapper, args...);
|
|
}
|
|
}
|
|
try {
|
|
boost::python::object result = implementation(args...);
|
|
if (objPtr) {
|
|
*objPtr = result;
|
|
}
|
|
else if (apiTransfer) {
|
|
sipAPIAccess::sipAPI()->api_transfer_to(result.ptr(), Py_None);
|
|
}
|
|
if constexpr (!std::is_same_v<ReturnType, void>) {
|
|
return boost::python::extract<ReturnType>(result)();
|
|
}
|
|
}
|
|
catch (const boost::python::error_already_set&) {
|
|
throw pyexcept::PythonError();
|
|
}
|
|
catch (...) {
|
|
throw pyexcept::UnknownException();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* @brief Call the given method on the wrapper with the given arguments, with proper
|
|
* exception handling.
|
|
*
|
|
* @param wrapper The wrapper object to use to retrieve the python method. Must have a publicly
|
|
* available `className` attribute.
|
|
* @param methodName The name of the method.
|
|
* @param args... Arguments for the method.
|
|
*
|
|
* @return the result of calling the given Python method on the wrapper.
|
|
*
|
|
* @throw pyexcept::MissingImplementation if the method does not exist.
|
|
* @throw pyexcept::PythonError if an error occurs while executing the python method.
|
|
* @throw pyexecpt::UnknownException if an unknown error occurs.
|
|
*/
|
|
template <class ReturnType, class WrapperType, class... Args>
|
|
ReturnType basicWrapperFunctionImplementation(const WrapperType *wrapper, const char *methodName, Args... args)
|
|
{
|
|
return details::wrapperFunctionImplementation<ReturnType>(wrapper, false, nullptr, nullptr, methodName, args...);
|
|
}
|
|
|
|
/**
|
|
* @brief Call the given method on the wrapper with the given arguments, with proper
|
|
* exception handling, and store the intermediate result in the given python object.
|
|
*
|
|
* @param wrapper The wrapper object to use to retrieve the python method. Must have a publicly
|
|
* available `className` attribute.
|
|
* @param ref Python object to which the result of `get_override()` should be stored.
|
|
* @param methodName The name of the method.
|
|
* @param args... Arguments for the method.
|
|
*
|
|
* @return the result of calling the given Python method on the wrapper.
|
|
*
|
|
* @throw pyexcept::MissingImplementation if the method does not exist.
|
|
* @throw pyexcept::PythonError if an error occurs while executing the python method.
|
|
* @throw pyexecpt::UnknownException if an unknown error occurs.
|
|
*/
|
|
template <class ReturnType, class WrapperType, class... Args>
|
|
ReturnType basicWrapperFunctionImplementation(const WrapperType* wrapper, boost::python::object &ref, const char* methodName, Args... args)
|
|
{
|
|
return details::wrapperFunctionImplementation<ReturnType>(wrapper, false, nullptr, &ref, methodName, args...);
|
|
}
|
|
|
|
/**
|
|
* @brief Call the given method on the wrapper with the given arguments, with proper
|
|
* exception handling, and transfer the responsibility of the returned object to
|
|
* the C++ side.
|
|
*
|
|
* @param wrapper The wrapper object to use to retrieve the python method. Must have a publicly
|
|
* available `className` attribute.
|
|
* @param methodName The name of the method.
|
|
* @param args... Arguments for the method.
|
|
*
|
|
* @return the result of calling the given Python method on the wrapper.
|
|
*
|
|
* @throw pyexcept::MissingImplementation if the method does not exist.
|
|
* @throw pyexcept::PythonError if an error occurs while executing the python method.
|
|
* @throw pyexecpt::UnknownException if an unknown error occurs.
|
|
*/
|
|
template <class ReturnType, class WrapperType, class... Args>
|
|
ReturnType wrapperFunctionImplementationWithApiTransfer(const WrapperType* wrapper, const char* methodName, Args... args)
|
|
{
|
|
return details::wrapperFunctionImplementation<ReturnType>(wrapper, true, nullptr, nullptr, methodName, args...);
|
|
}
|
|
|
|
/**
|
|
* @brief Call the given method on the wrapper with the given arguments, with proper
|
|
* exception handling, falling back to the given function if the method does not exist.
|
|
*
|
|
* @param wrapper The wrapper object to use to retrieve the python method. Must have a publicly
|
|
* available `className` attribute.
|
|
* @param fn The function to call if the method does not exists.
|
|
* @param methodName The name of the method.
|
|
* @param args... Arguments for the method.
|
|
*
|
|
* Note: `fn` does not have to be a member-function of `wrapper` but `std::invoke(fn, wrapper, args...)` must be valid.
|
|
*
|
|
* @return the result of calling the given Python method on the wrapper.
|
|
*
|
|
* @throw pyexcept::PythonError if an error occurs while executing the python method.
|
|
* @throw pyexecpt::UnknownException if an unknown error occurs.
|
|
*/
|
|
template <class ReturnType, class WrapperTypePtr, class Fn, class... Args>
|
|
ReturnType basicWrapperFunctionImplementationWithDefault(WrapperTypePtr wrapper, Fn fn, const char* methodName, Args... args)
|
|
{
|
|
return details::wrapperFunctionImplementation<ReturnType>(wrapper, false, fn, nullptr, methodName, args...);
|
|
}
|
|
|
|
#endif // PYTHONWRAPPERUTILITIES_H
|