mirror of
https://github.com/ModOrganizer2/modorganizer-plugin_python.git
synced 2026-07-27 14:03:33 -07:00
Add python interface for IPluginInstallerSimple.
This commit is contained in:
@@ -3,9 +3,12 @@
|
||||
#include "gilock.h"
|
||||
#include <QUrl>
|
||||
#include <QWidget>
|
||||
|
||||
#include "pythonwrapperutilities.h"
|
||||
#include "sipApiAccess.h"
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
// See bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2852624
|
||||
@@ -286,27 +289,55 @@ std::map<std::type_index, boost::any> IPluginGameWrapper::featureList() const
|
||||
}
|
||||
/// end IPluginGame Wrapper
|
||||
/////////////////////////////////////
|
||||
/// IPluginInstaller macro
|
||||
|
||||
#define COMMON_I_PLUGIN_INSTALLER_WRAPPER_DEFINITIONS(class_name) \
|
||||
unsigned int class_name::priority() const { return basicWrapperFunctionImplementation<class_name, unsigned int>(this, "priority"); } \
|
||||
bool class_name::isManualInstaller() const { return basicWrapperFunctionImplementation<class_name, bool>(this, "isManualInstaller"); } \
|
||||
bool class_name::isArchiveSupported(std::shared_ptr<const IFileTree> tree) const { return basicWrapperFunctionImplementation<class_name, bool>(this, "isArchiveSupported", tree); }
|
||||
|
||||
/// end IPluginInstaller macro
|
||||
/////////////////////////////////////
|
||||
/// IPluginInstaller Wrapper
|
||||
|
||||
COMMON_I_PLUGIN_WRAPPER_DEFINITIONS(IPluginInstallerSimpleWrapper)
|
||||
COMMON_I_PLUGIN_INSTALLER_WRAPPER_DEFINITIONS(IPluginInstallerSimpleWrapper)
|
||||
|
||||
IPluginInstaller::EInstallResult IPluginInstallerSimpleWrapper::install(
|
||||
GuessedValue<QString>& modName, std::shared_ptr<IFileTree>& tree,
|
||||
QString& version, int& nexusID)
|
||||
{
|
||||
namespace bpy = boost::python;
|
||||
|
||||
using return_type = boost::variant<IPluginInstaller::EInstallResult, std::shared_ptr<IFileTree>, boost::tuple<std::shared_ptr<IFileTree>, QString, int>> ;
|
||||
auto ret = basicWrapperFunctionImplementation<IPluginInstallerSimpleWrapper, return_type>(this, "install", boost::ref(modName), tree, version, nexusID);
|
||||
|
||||
return boost::apply_visitor([&](auto const& t) {
|
||||
using type = std::decay_t<decltype(t)>;
|
||||
if constexpr (std::is_same_v<type, IPluginInstaller::EInstallResult>) {
|
||||
return t;
|
||||
}
|
||||
else if constexpr (std::is_same_v<type, std::shared_ptr<IFileTree>>) {
|
||||
tree = t;
|
||||
return IPluginInstaller::RESULT_SUCCESS;
|
||||
}
|
||||
else if constexpr (std::is_same_v<type, boost::tuple<std::shared_ptr<IFileTree>, QString, int>>) {
|
||||
tree = boost::get<0>(t);
|
||||
version = boost::get<1>(t);
|
||||
nexusID = boost::get<2>(t);
|
||||
return IPluginInstaller::RESULT_SUCCESS;
|
||||
}
|
||||
else {
|
||||
static_assert("Type not handled in boost::apply_visitor.");
|
||||
}
|
||||
}, ret);
|
||||
}
|
||||
|
||||
/// end IPluginInstallerSimple Wrapper
|
||||
/////////////////////////////////////
|
||||
/// IPluginInstallerCustom Wrapper
|
||||
|
||||
|
||||
COMMON_I_PLUGIN_WRAPPER_DEFINITIONS(IPluginInstallerCustomWrapper)
|
||||
|
||||
unsigned int IPluginInstallerCustomWrapper::priority() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginInstallerCustomWrapper, unsigned int>(this, "priority");
|
||||
}
|
||||
|
||||
bool IPluginInstallerCustomWrapper::isManualInstaller() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginInstallerCustomWrapper, bool>(this, "isManualInstaller");
|
||||
}
|
||||
|
||||
bool IPluginInstallerCustomWrapper::isArchiveSupported(const DirectoryTree &archiveTree) const
|
||||
{
|
||||
//return basicWrapperFunctionImplementation<IPluginInstallerCustomWrapper, bool>(this, "isArchiveSupported", archiveTree);
|
||||
// This was a stub implementation when I got here, and a real one won't compile.
|
||||
return false;
|
||||
}
|
||||
COMMON_I_PLUGIN_INSTALLER_WRAPPER_DEFINITIONS(IPluginInstallerCustomWrapper)
|
||||
|
||||
bool IPluginInstallerCustomWrapper::isArchiveSupported(const QString &archiveName) const
|
||||
{
|
||||
@@ -324,11 +355,6 @@ IPluginInstaller::EInstallResult IPluginInstallerCustomWrapper::install(GuessedV
|
||||
return basicWrapperFunctionImplementation<IPluginInstallerCustomWrapper, IPluginInstaller::EInstallResult>(this, "install", modName, gameName, archiveName, version, modID);
|
||||
}
|
||||
|
||||
|
||||
void IPluginInstallerCustomWrapper::setParentWidget(QWidget *parent)
|
||||
{
|
||||
basicWrapperFunctionImplementation<IPluginInstallerCustomWrapper, void>(this, "setParentWidget", parent);
|
||||
}
|
||||
/// end IPluginInstallerCustom Wrapper
|
||||
/////////////////////////////
|
||||
/// IPluginModPage Wrapper
|
||||
|
||||
@@ -132,25 +132,47 @@ protected:
|
||||
};
|
||||
|
||||
|
||||
#define COMMON_I_PLUGIN_INSTALLER_WRAPPER_DECLARATIONS public: \
|
||||
using IPluginInstaller::parentWidget; \
|
||||
using IPluginInstaller::manager; \
|
||||
virtual unsigned int priority() const override; \
|
||||
virtual bool isManualInstaller() const override; \
|
||||
virtual bool isArchiveSupported(std::shared_ptr<const MOBase::IFileTree> tree) const override;
|
||||
|
||||
|
||||
class IPluginInstallerSimpleWrapper : public MOBase::IPluginInstallerSimple, public boost::python::wrapper<MOBase::IPluginInstallerSimple>
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(MOBase::IPlugin MOBase::IPluginInstaller MOBase::IPluginInstallerSimple)
|
||||
|
||||
COMMON_I_PLUGIN_WRAPPER_DECLARATIONS
|
||||
COMMON_I_PLUGIN_INSTALLER_WRAPPER_DECLARATIONS
|
||||
|
||||
public:
|
||||
static constexpr const char* className = "IPluginInstallerSimpleWrapper";
|
||||
using boost::python::wrapper<MOBase::IPluginInstallerSimple>::get_override;
|
||||
|
||||
virtual EInstallResult install(MOBase::GuessedValue<QString>& modName, std::shared_ptr<MOBase::IFileTree>& tree,
|
||||
QString& version, int& nexusID) override;
|
||||
};
|
||||
|
||||
class IPluginInstallerCustomWrapper : public MOBase::IPluginInstallerCustom, public boost::python::wrapper<MOBase::IPluginInstallerCustom>
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(MOBase::IPlugin MOBase::IPluginInstaller MOBase::IPluginInstallerCustom)
|
||||
|
||||
COMMON_I_PLUGIN_WRAPPER_DECLARATIONS
|
||||
|
||||
COMMON_I_PLUGIN_INSTALLER_WRAPPER_DECLARATIONS
|
||||
|
||||
public:
|
||||
static constexpr const char* className = "IPluginInstallerCustomWrapper";
|
||||
using boost::python::wrapper<MOBase::IPluginInstallerCustom>::get_override;
|
||||
|
||||
virtual unsigned int priority() const;
|
||||
virtual bool isManualInstaller() const;
|
||||
virtual bool isArchiveSupported(const MOBase::DirectoryTree &tree) const;
|
||||
virtual bool isArchiveSupported(const QString &archiveName) const;
|
||||
virtual std::set<QString> supportedExtensions() const;
|
||||
virtual bool isArchiveSupported(const QString &archiveName) const override;
|
||||
virtual std::set<QString> supportedExtensions() const override;
|
||||
virtual EInstallResult install(MOBase::GuessedValue<QString> &modName, QString gameName, const QString &archiveName,
|
||||
const QString &version, int modID);
|
||||
virtual void setParentWidget(QWidget *parent);
|
||||
|
||||
const QString &version, int modID) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
+39
-61
@@ -25,9 +25,10 @@
|
||||
|
||||
#ifndef Q_MOC_RUN
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/mp11.hpp>
|
||||
#include "tuple_helper.h"
|
||||
#endif
|
||||
|
||||
|
||||
MOBase::IOrganizer *s_Organizer = nullptr;
|
||||
|
||||
|
||||
@@ -69,6 +70,7 @@ IPythonRunner *CreatePythonRunner(MOBase::IOrganizer *moInfo, const QString &pyt
|
||||
using namespace MOBase;
|
||||
|
||||
namespace bpy = boost::python;
|
||||
namespace mp11 = boost::mp11;
|
||||
|
||||
struct QString_to_python_str
|
||||
{
|
||||
@@ -161,58 +163,6 @@ struct HANDLE_converters
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct GuessedValue_converters
|
||||
{
|
||||
struct GuessedValue_to_python
|
||||
{
|
||||
static PyObject *convert(const GuessedValue<T> &var) {
|
||||
bpy::list result;
|
||||
const std::set<T> &values = var.variants();
|
||||
for (auto iter = values.begin(); iter != values.end(); ++iter) {
|
||||
result.append(bpy::make_tuple(*iter, GUESS_GOOD));
|
||||
}
|
||||
return bpy::incref(result.ptr());
|
||||
}
|
||||
};
|
||||
|
||||
struct GuessedValue_from_python
|
||||
{
|
||||
GuessedValue_from_python() {
|
||||
bpy::converter::registry::push_back(&convertible, &construct, bpy::type_id<GuessedValue<T> >());
|
||||
}
|
||||
|
||||
static void *convertible(PyObject *objPtr) {
|
||||
if PyList_Check(objPtr) {
|
||||
return objPtr;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static void construct(PyObject *objPtr, bpy::converter::rvalue_from_python_stage1_data* data) {
|
||||
void *storage = ((bpy::converter::rvalue_from_python_storage<GuessedValue<T> >*)data)->storage.bytes;
|
||||
GuessedValue<T> *result = new (storage) GuessedValue<T>();
|
||||
|
||||
bpy::list source(bpy::handle<>(bpy::borrowed(objPtr)));
|
||||
int length = bpy::len(source);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
bpy::tuple cell = bpy::extract<bpy::tuple>(source[i]);
|
||||
result->update(bpy::extract<T>(cell[0]), bpy::extract<EGuessQuality>(cell[1]));
|
||||
}
|
||||
|
||||
data->convertible = storage;
|
||||
}
|
||||
};
|
||||
|
||||
GuessedValue_converters()
|
||||
{
|
||||
GuessedValue_from_python();
|
||||
bpy::to_python_converter<GuessedValue<T>, GuessedValue_to_python>();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename key_type, typename value_type>
|
||||
struct QMap_converters
|
||||
{
|
||||
@@ -819,8 +769,19 @@ struct DowncastReturn {
|
||||
|
||||
};
|
||||
|
||||
|
||||
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(updateWithQuality, MOBase::GuessedValue<QString>::update, 2, 2)
|
||||
/**
|
||||
* @brief Register implicit conversion from any of the decayed type from the variant
|
||||
* to the variant type.
|
||||
*/
|
||||
template <class... Args>
|
||||
void register_implicit_variant() {
|
||||
mp11::mp_for_each<
|
||||
mp11::mp_list<Args... >> (
|
||||
[](auto t) {
|
||||
// take advantage of built-in conversions
|
||||
bpy::implicitly_convertible<std::decay_t<decltype(t)>, boost::variant<Args... >>();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
BOOST_PYTHON_MODULE(mobase)
|
||||
@@ -962,7 +923,9 @@ BOOST_PYTHON_MODULE(mobase)
|
||||
|
||||
// FileTreeEntry and IFileTree are only managed by shared ptr.
|
||||
bpy::register_ptr_to_python<std::shared_ptr<FileTreeEntry>>();
|
||||
bpy::register_ptr_to_python<std::shared_ptr<const FileTreeEntry>>();
|
||||
bpy::register_ptr_to_python<std::shared_ptr<IFileTree>>();
|
||||
bpy::register_ptr_to_python<std::shared_ptr<const IFileTree>>();
|
||||
|
||||
// FileTreeEntry Scope:
|
||||
auto fileTreeEntryClass = bpy::class_<FileTreeEntry, std::shared_ptr<FileTreeEntry>, boost::noncopyable>("FileTreeEntry", bpy::no_init);
|
||||
@@ -1162,11 +1125,15 @@ BOOST_PYTHON_MODULE(mobase)
|
||||
.value("user", MOBase::GUESS_USER)
|
||||
;
|
||||
|
||||
bpy::class_<MOBase::GuessedValue<QString>, boost::noncopyable>("GuessedString")
|
||||
bpy::class_<MOBase::GuessedValue<QString>, boost::noncopyable>("GuessedString", bpy::no_init)
|
||||
.def("update",
|
||||
static_cast<GuessedValue<QString> &(GuessedValue<QString>::*)(const QString&, EGuessQuality)>(&GuessedValue<QString>::update),
|
||||
bpy::return_value_policy<bpy::reference_existing_object>(), updateWithQuality())
|
||||
static_cast<GuessedValue<QString>& (GuessedValue<QString>::*)(const QString&)>(&GuessedValue<QString>::update),
|
||||
bpy::return_self<>())
|
||||
.def("update",
|
||||
static_cast<GuessedValue<QString>& (GuessedValue<QString>::*)(const QString&, EGuessQuality)>(&GuessedValue<QString>::update),
|
||||
bpy::return_self<>())
|
||||
.def("variants", &MOBase::GuessedValue<QString>::variants, bpy::return_value_policy<bpy::copy_const_reference>())
|
||||
.def("__str__", &MOBase::GuessedValue<QString>::operator const QString&, bpy::return_value_policy<bpy::copy_const_reference>())
|
||||
;
|
||||
|
||||
bpy::to_python_converter<IPluginList::PluginStates, QFlags_to_int<IPluginList::PluginState>>();
|
||||
@@ -1315,6 +1282,8 @@ BOOST_PYTHON_MODULE(mobase)
|
||||
.def("featureUnmanagedMods", &MOBase::IPluginGame::feature<UnmanagedMods>, bpy::return_value_policy<bpy::reference_existing_object>())
|
||||
;
|
||||
|
||||
bpy::register_tuple<boost::tuple<std::shared_ptr<IFileTree>, QString, int>>();
|
||||
register_implicit_variant<IPluginInstaller::EInstallResult, std::shared_ptr<IFileTree>, boost::tuple<std::shared_ptr<IFileTree>, QString, int>>();
|
||||
bpy::enum_<MOBase::IPluginInstaller::EInstallResult>("InstallResult")
|
||||
.value("success", MOBase::IPluginInstaller::RESULT_SUCCESS)
|
||||
.value("failed", MOBase::IPluginInstaller::RESULT_FAILED)
|
||||
@@ -1323,8 +1292,18 @@ BOOST_PYTHON_MODULE(mobase)
|
||||
.value("notAttempted", MOBase::IPluginInstaller::RESULT_NOTATTEMPTED)
|
||||
;
|
||||
|
||||
bpy::class_<IPluginInstallerSimpleWrapper, boost::noncopyable>("IPluginInstallerSimple")
|
||||
.def("install", &IPluginInstallerSimple::install)
|
||||
.def("getParentWidget", &IPluginInstallerSimpleWrapper::parentWidget, bpy::return_value_policy<bpy::reference_existing_object>())
|
||||
.def("getManager", &IPluginInstallerSimpleWrapper::manager, bpy::return_value_policy<bpy::reference_existing_object>())
|
||||
;
|
||||
|
||||
bpy::class_<IPluginInstallerCustomWrapper, boost::noncopyable>("IPluginInstallerCustom")
|
||||
.def("setParentWidget", bpy::pure_virtual(&MOBase::IPluginInstallerCustom::setParentWidget))
|
||||
.def("isArchiveSupported", &IPluginInstallerCustom::isArchiveSupported)
|
||||
.def("supportedExtensions", &IPluginInstallerCustom::supportedExtensions)
|
||||
.def("install", &IPluginInstallerCustom::install)
|
||||
.def("getParentWidget", &IPluginInstallerCustomWrapper::parentWidget, bpy::return_value_policy<bpy::reference_existing_object>())
|
||||
.def("getManager", &IPluginInstallerCustomWrapper::manager, bpy::return_value_policy<bpy::reference_existing_object>())
|
||||
;
|
||||
|
||||
bpy::class_<IPluginModPageWrapper, boost::noncopyable>("IPluginModPage")
|
||||
@@ -1338,8 +1317,6 @@ BOOST_PYTHON_MODULE(mobase)
|
||||
.def("setParentWidget", bpy::pure_virtual(&MOBase::IPluginTool::setParentWidget))
|
||||
;
|
||||
|
||||
GuessedValue_converters<QString>();
|
||||
|
||||
HANDLE_converters();
|
||||
|
||||
//bpy::to_python_converter<ModRepositoryFileInfo, ModRepositoryFileInfo_to_python_dict>();
|
||||
@@ -1521,6 +1498,7 @@ QList<QObject*> PythonRunner::instantiate(const QString &pluginName)
|
||||
// Must try the wrapper because it's only a plugin extension interface in C++, so doesn't extend QObject
|
||||
TRY_PLUGIN_TYPE(IPluginFileMapperWrapper, pluginObj);
|
||||
TRY_PLUGIN_TYPE(IPluginInstallerCustom, pluginObj);
|
||||
TRY_PLUGIN_TYPE(IPluginInstallerSimple, pluginObj);
|
||||
TRY_PLUGIN_TYPE(IPluginModPage, pluginObj);
|
||||
TRY_PLUGIN_TYPE(IPluginPreview, pluginObj);
|
||||
TRY_PLUGIN_TYPE(IPluginTool, pluginObj);
|
||||
|
||||
@@ -0,0 +1,253 @@
|
||||
// From: https://pyplusplus.readthedocs.io/en/latest/troubleshooting_guide/automatic_conversion/tuples.hpp.html
|
||||
// Copyright 2004-2007 Roman Yakovenko.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef TUPLES_HPP_16_JAN_2007
|
||||
#define TUPLES_HPP_16_JAN_2007
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include <boost/python/object.hpp> //len function
|
||||
#include <boost/mpl/int.hpp>
|
||||
#include <boost/mpl/next.hpp>
|
||||
|
||||
/**
|
||||
* Converts boost::tuples::tuple<...> to\from Python tuple
|
||||
*
|
||||
* The conversion is done "on-the-fly", you should only register the conversion
|
||||
* with your tuple classes.
|
||||
* For example:
|
||||
*
|
||||
* typedef boost::tuples::tuple< int, double, std::string > triplet;
|
||||
* boost::python::register_tuple< triplet >();
|
||||
*
|
||||
* That's all. After this point conversion to\from next types will be handled
|
||||
* by Boost.Python library:
|
||||
*
|
||||
* triplet
|
||||
* triplet& ( return type only )
|
||||
* const triplet
|
||||
* const triplet&
|
||||
*
|
||||
* Implementation description.
|
||||
* The conversion uses Boost.Python custom r-value converters. r-value converters
|
||||
* is very powerful and undocumented feature of the library. The only documentation
|
||||
* we have is http://boost.org/libs/python/doc/v2/faq.html#custom_string .
|
||||
*
|
||||
* The conversion consists from two parts: "to" and "from".
|
||||
*
|
||||
* "To" conversion
|
||||
* The "to" part is pretty easy and well documented ( http://docs.python.org/api/api.html ).
|
||||
* You should use Python C API to create an instance of a class and than you
|
||||
* initialize the relevant members of the instance.
|
||||
*
|
||||
* "From" conversion
|
||||
* Lets start from analyzing one of the use case Boost.Python library have to
|
||||
* deal with:
|
||||
*
|
||||
* void do_smth( const triplet& arg ){...}
|
||||
*
|
||||
* In order to allow calling this function from Python, the library should keep
|
||||
* parameter "arg" alive until the function returns. In other words, the library
|
||||
* should provide instances life-time management. The provided interface is not
|
||||
* ideal and could be improved. You have to implement two functions:
|
||||
*
|
||||
* void* convertible( PyObject* obj )
|
||||
* Checks whether the "obj" could be converted to an instance of the desired
|
||||
* class. If true, the function should return "obj", otherwise NULL
|
||||
*
|
||||
* void construct( PyObject* obj, converter::rvalue_from_python_stage1_data* data)
|
||||
* Constructs the instance of the desired class. This function will be called
|
||||
* if and only if "convertible" function returned true. The first argument
|
||||
* is Python object, which was passed as parameter to "convertible" function.
|
||||
* The second object is some kind of memory allocator for one object. Basically
|
||||
* it keeps a memory chunk. You will use the memory for object allocation.
|
||||
*
|
||||
* For some unclear for me reason, the library implements "C style Inheritance"
|
||||
* ( http://www.embedded.com/97/fe29712.htm ). So, in order to create new
|
||||
* object in the storage you have to cast to the "right" class:
|
||||
*
|
||||
* typedef converter::rvalue_from_python_storage<your_type_t> storage_t;
|
||||
* storage_t* the_storage = reinterpret_cast<storage_t*>( data );
|
||||
* void* memory_chunk = the_storage->storage.bytes;
|
||||
*
|
||||
* "memory_chunk" points to the memory, where the instance will be allocated.
|
||||
*
|
||||
* In order to create object at specific location, you should use placement new
|
||||
* operator:
|
||||
*
|
||||
* your_type_t* instance = new (memory_chunk) your_type_t();
|
||||
*
|
||||
* Now, you can continue to initialize the instance.
|
||||
*
|
||||
* instance->set_xyz = read xyz from obj
|
||||
*
|
||||
* If "your_type_t" constructor requires some arguments, "read" the Python
|
||||
* object before you call the constructor:
|
||||
*
|
||||
* xyz_type xyz = read xyz from obj
|
||||
* your_type_t* instance = new (memory_chunk) your_type_t(xyz);
|
||||
*
|
||||
* Hint:
|
||||
* In most case you don't really need\have to work with C Python API. Let
|
||||
* Boost.Python library to do some work for you!
|
||||
*
|
||||
**/
|
||||
|
||||
namespace boost {
|
||||
namespace python {
|
||||
|
||||
namespace details {
|
||||
|
||||
//Small helper function, introduced to allow short syntax for index incrementing
|
||||
template< int index>
|
||||
typename mpl::next< mpl::int_< index > >::type increment_index() {
|
||||
typedef typename mpl::next< mpl::int_< index > >::type next_index_type;
|
||||
return next_index_type();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template< class TTuple >
|
||||
struct to_py_tuple {
|
||||
|
||||
typedef mpl::int_< tuples::length< TTuple >::value > length_type;
|
||||
|
||||
static PyObject* convert(const TTuple& c_tuple) {
|
||||
list values;
|
||||
//add all c_tuple items to "values" list
|
||||
convert_impl(c_tuple, values, mpl::int_< 0 >(), length_type());
|
||||
//create Python tuple from the list
|
||||
return incref(python::tuple(values).ptr());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template< int index, int length >
|
||||
static void
|
||||
convert_impl(const TTuple& c_tuple, list& values, mpl::int_< index >, mpl::int_< length >) {
|
||||
values.append(c_tuple.template get< index >());
|
||||
convert_impl(c_tuple, values, details::increment_index<index>(), length_type());
|
||||
}
|
||||
|
||||
template< int length >
|
||||
static void
|
||||
convert_impl(const TTuple&, list& values, mpl::int_< length >, mpl::int_< length >)
|
||||
{}
|
||||
|
||||
};
|
||||
|
||||
|
||||
template< class TTuple>
|
||||
struct from_py_sequence {
|
||||
|
||||
typedef TTuple tuple_type;
|
||||
|
||||
typedef mpl::int_< tuples::length< TTuple >::value > length_type;
|
||||
|
||||
static void*
|
||||
convertible(PyObject* py_obj) {
|
||||
|
||||
if (!PySequence_Check(py_obj)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!PyObject_HasAttrString(py_obj, "__len__")) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
python::object py_sequence(handle<>(borrowed(py_obj)));
|
||||
|
||||
if (tuples::length< TTuple >::value != len(py_sequence)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (convertible_impl(py_sequence, mpl::int_< 0 >(), length_type())) {
|
||||
return py_obj;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
construct(PyObject* py_obj, converter::rvalue_from_python_stage1_data* data) {
|
||||
typedef converter::rvalue_from_python_storage<TTuple> storage_t;
|
||||
storage_t* the_storage = reinterpret_cast<storage_t*>(data);
|
||||
void* memory_chunk = the_storage->storage.bytes;
|
||||
TTuple* c_tuple = new (memory_chunk) TTuple();
|
||||
data->convertible = memory_chunk;
|
||||
|
||||
python::object py_sequence(handle<>(borrowed(py_obj)));
|
||||
construct_impl(py_sequence, *c_tuple, mpl::int_< 0 >(), length_type());
|
||||
}
|
||||
|
||||
static TTuple to_c_tuple(PyObject* py_obj) {
|
||||
if (!convertible(py_obj)) {
|
||||
throw std::runtime_error("Unable to construct boost::tuples::tuple from Python object!");
|
||||
}
|
||||
TTuple c_tuple;
|
||||
python::object py_sequence(handle<>(borrowed(py_obj)));
|
||||
construct_impl(py_sequence, c_tuple, mpl::int_< 0 >(), length_type());
|
||||
return c_tuple;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template< int index, int length >
|
||||
static bool
|
||||
convertible_impl(const python::object& py_sequence, mpl::int_< index >, mpl::int_< length >) {
|
||||
|
||||
typedef typename tuples::element< index, TTuple>::type element_type;
|
||||
|
||||
object element = py_sequence[index];
|
||||
extract<element_type> type_checker(element);
|
||||
if (!type_checker.check()) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return convertible_impl(py_sequence, details::increment_index<index>(), length_type());
|
||||
}
|
||||
}
|
||||
|
||||
template< int length >
|
||||
static bool
|
||||
convertible_impl(const python::object& py_sequence, mpl::int_< length >, mpl::int_< length >) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template< int index, int length >
|
||||
static void
|
||||
construct_impl(const python::object& py_sequence, TTuple& c_tuple, mpl::int_< index >, mpl::int_< length >) {
|
||||
|
||||
typedef typename tuples::element< index, TTuple>::type element_type;
|
||||
|
||||
object element = py_sequence[index];
|
||||
c_tuple.template get< index >() = extract<element_type>(element);
|
||||
|
||||
construct_impl(py_sequence, c_tuple, details::increment_index<index>(), length_type());
|
||||
}
|
||||
|
||||
template< int length >
|
||||
static void
|
||||
construct_impl(const python::object& py_sequence, TTuple& c_tuple, mpl::int_< length >, mpl::int_< length >)
|
||||
{}
|
||||
|
||||
};
|
||||
|
||||
template< class TTuple>
|
||||
void register_tuple() {
|
||||
|
||||
to_python_converter< TTuple, to_py_tuple<TTuple> >();
|
||||
|
||||
converter::registry::push_back(&from_py_sequence<TTuple>::convertible
|
||||
, &from_py_sequence<TTuple>::construct
|
||||
, type_id<TTuple>());
|
||||
};
|
||||
|
||||
}
|
||||
} //boost::python
|
||||
|
||||
#endif//TUPLES_HPP_16_JAN_2007
|
||||
Reference in New Issue
Block a user