|
| 1 | +// Copyright (c) 2024 The pybind Community. |
| 2 | + |
| 3 | +// THIS MUST STAY AT THE TOP! |
| 4 | +#include <pybind11/pybind11.h> // EXCLUSIVELY for PYBIND11_PLATFORM_ABI_ID |
| 5 | +// Potential future direction to maximize reusability: |
| 6 | +// (e.g. for use from SWIG, Cython, PyCLIF, nanobind): |
| 7 | +// #include <pybind11/compat/platform_abi_id.h> |
| 8 | +// This would only depend on: |
| 9 | +// 1. A C++ compiler, WITHOUT requiring -fexceptions. |
| 10 | +// 2. Python.h |
| 11 | + |
| 12 | +#include "test_cpp_conduit_traveler_types.h" |
| 13 | + |
| 14 | +#include <Python.h> |
| 15 | +#include <typeinfo> |
| 16 | + |
| 17 | +namespace { |
| 18 | + |
| 19 | +void *get_cpp_conduit_void_ptr(PyObject *py_obj, const std::type_info *cpp_type_info) { |
| 20 | + PyObject *cpp_type_info_capsule |
| 21 | + = PyCapsule_New(const_cast<void *>(static_cast<const void *>(cpp_type_info)), |
| 22 | + typeid(std::type_info).name(), |
| 23 | + nullptr); |
| 24 | + if (cpp_type_info_capsule == nullptr) { |
| 25 | + return nullptr; |
| 26 | + } |
| 27 | + PyObject *cpp_conduit = PyObject_CallMethod(py_obj, |
| 28 | + "_pybind11_conduit_v1_", |
| 29 | + "yOy", |
| 30 | + PYBIND11_PLATFORM_ABI_ID, |
| 31 | + cpp_type_info_capsule, |
| 32 | + "raw_pointer_ephemeral"); |
| 33 | + Py_DECREF(cpp_type_info_capsule); |
| 34 | + if (cpp_conduit == nullptr) { |
| 35 | + return nullptr; |
| 36 | + } |
| 37 | + void *void_ptr = PyCapsule_GetPointer(cpp_conduit, cpp_type_info->name()); |
| 38 | + Py_DECREF(cpp_conduit); |
| 39 | + if (PyErr_Occurred()) { |
| 40 | + return nullptr; |
| 41 | + } |
| 42 | + return void_ptr; |
| 43 | +} |
| 44 | + |
| 45 | +template <typename T> |
| 46 | +T *get_cpp_conduit_type_ptr(PyObject *py_obj) { |
| 47 | + void *void_ptr = get_cpp_conduit_void_ptr(py_obj, &typeid(T)); |
| 48 | + if (void_ptr == nullptr) { |
| 49 | + return nullptr; |
| 50 | + } |
| 51 | + return static_cast<T *>(void_ptr); |
| 52 | +} |
| 53 | + |
| 54 | +extern "C" PyObject *wrapGetLuggage(PyObject * /*self*/, PyObject *traveler) { |
| 55 | + const auto *cpp_traveler |
| 56 | + = get_cpp_conduit_type_ptr<pybind11_tests::test_cpp_conduit::Traveler>(traveler); |
| 57 | + if (cpp_traveler == nullptr) { |
| 58 | + return nullptr; |
| 59 | + } |
| 60 | + return PyUnicode_FromString(cpp_traveler->luggage.c_str()); |
| 61 | +} |
| 62 | + |
| 63 | +extern "C" PyObject *wrapGetPoints(PyObject * /*self*/, PyObject *premium_traveler) { |
| 64 | + const auto *cpp_premium_traveler |
| 65 | + = get_cpp_conduit_type_ptr<pybind11_tests::test_cpp_conduit::PremiumTraveler>( |
| 66 | + premium_traveler); |
| 67 | + if (cpp_premium_traveler == nullptr) { |
| 68 | + return nullptr; |
| 69 | + } |
| 70 | + return PyLong_FromLong(static_cast<long>(cpp_premium_traveler->points)); |
| 71 | +} |
| 72 | + |
| 73 | +PyMethodDef ThisMethodDef[] = {{"GetLuggage", wrapGetLuggage, METH_O, nullptr}, |
| 74 | + {"GetPoints", wrapGetPoints, METH_O, nullptr}, |
| 75 | + {nullptr, nullptr, 0, nullptr}}; |
| 76 | + |
| 77 | +struct PyModuleDef ThisModuleDef = { |
| 78 | + PyModuleDef_HEAD_INIT, // m_base |
| 79 | + "exo_planet_c_api", // m_name |
| 80 | + nullptr, // m_doc |
| 81 | + -1, // m_size |
| 82 | + ThisMethodDef, // m_methods |
| 83 | + nullptr, // m_slots |
| 84 | + nullptr, // m_traverse |
| 85 | + nullptr, // m_clear |
| 86 | + nullptr // m_free |
| 87 | +}; |
| 88 | + |
| 89 | +} // namespace |
| 90 | + |
| 91 | +#if defined(WIN32) || defined(_WIN32) |
| 92 | +# define EXO_PLANET_C_API_EXPORT __declspec(dllexport) |
| 93 | +#else |
| 94 | +# define EXO_PLANET_C_API_EXPORT __attribute__((visibility("default"))) |
| 95 | +#endif |
| 96 | + |
| 97 | +extern "C" EXO_PLANET_C_API_EXPORT PyObject *PyInit_exo_planet_c_api() { |
| 98 | + PyObject *m = PyModule_Create(&ThisModuleDef); |
| 99 | + if (m == nullptr) { |
| 100 | + return nullptr; |
| 101 | + } |
| 102 | + return m; |
| 103 | +} |
0 commit comments