|
|
|||
File indexing completed on 2026-01-09 10:20:46
0001 // Copyright (c) 2024 The pybind Community. 0002 0003 /* The pybind11_conduit_v1 feature enables type-safe interoperability between 0004 0005 * different independent Python/C++ bindings systems, 0006 0007 * including pybind11 versions with different PYBIND11_INTERNALS_VERSION's. 0008 0009 * NOTE: The conduit feature 0010 only covers from-Python-to-C++ conversions, it 0011 does not cover from-C++-to-Python conversions. 0012 (For the latter, a different feature would have to be added.) 0013 0014 The naming of the feature is a bit misleading: 0015 0016 * The feature is in no way tied to pybind11 internals. 0017 0018 * It just happens to originate from pybind11 and currently still lives there. 0019 0020 * The only external dependency is <Python.h>. 0021 0022 The implementation is a VERY light-weight dependency. It is designed to be 0023 compatible with any ISO C++11 (or higher) compiler, and does NOT require 0024 C++ Exception Handling to be enabled. 0025 0026 Please see https://github.com/pybind/pybind11/pull/5296 for more background. 0027 0028 The implementation involves a 0029 0030 def _pybind11_conduit_v1_( 0031 self, 0032 pybind11_platform_abi_id: bytes, 0033 cpp_type_info_capsule: capsule, 0034 pointer_kind: bytes) -> capsule 0035 0036 method that is meant to be added to Python objects wrapping C++ objects 0037 (e.g. pybind11::class_-wrapped types). 0038 0039 The design of the _pybind11_conduit_v1_ feature provides two layers of 0040 protection against C++ ABI mismatches: 0041 0042 * The first and most important layer is that the pybind11_platform_abi_id's 0043 must match between extensions. — This will never be perfect, but is the same 0044 pragmatic approach used in pybind11 since 2017 0045 (https://github.com/pybind/pybind11/commit/96997a4b9d4ec3d389a570604394af5d5eee2557, 0046 PYBIND11_INTERNALS_ID). 0047 0048 * The second layer is that the typeid(std::type_info).name()'s must match 0049 between extensions. 0050 0051 The implementation below (which is shorter than this comment!), serves as a 0052 battle-tested specification. The main API is this one function: 0053 0054 auto *cpp_pointer = pybind11_conduit_v1::get_type_pointer_ephemeral<YourType>(py_obj); 0055 0056 It is meant to be a minimalistic reference implementation, intentionally 0057 without comprehensive error reporting. It is expected that major bindings 0058 systems will roll their own, compatible implementations, potentially with 0059 system-specific error reporting. The essential specifications all bindings 0060 systems need to agree on are merely: 0061 0062 * PYBIND11_PLATFORM_ABI_ID (const char* literal). 0063 0064 * The cpp_type_info capsule (see below: a void *ptr and a const char *name). 0065 0066 * The cpp_conduit capsule (see below: a void *ptr and a const char *name). 0067 0068 * "raw_pointer_ephemeral" means: the lifetime of the pointer is the lifetime 0069 of the py_obj. 0070 0071 */ 0072 0073 // THIS MUST STAY AT THE TOP! 0074 #include "pybind11_platform_abi_id.h" 0075 0076 #include <Python.h> 0077 #include <typeinfo> 0078 0079 namespace pybind11_conduit_v1 { 0080 0081 inline void *get_raw_pointer_ephemeral(PyObject *py_obj, const std::type_info *cpp_type_info) { 0082 PyObject *cpp_type_info_capsule 0083 = PyCapsule_New(const_cast<void *>(static_cast<const void *>(cpp_type_info)), 0084 typeid(std::type_info).name(), 0085 nullptr); 0086 if (cpp_type_info_capsule == nullptr) { 0087 return nullptr; 0088 } 0089 PyObject *cpp_conduit = PyObject_CallMethod(py_obj, 0090 "_pybind11_conduit_v1_", 0091 "yOy", 0092 PYBIND11_PLATFORM_ABI_ID, 0093 cpp_type_info_capsule, 0094 "raw_pointer_ephemeral"); 0095 Py_DECREF(cpp_type_info_capsule); 0096 if (cpp_conduit == nullptr) { 0097 return nullptr; 0098 } 0099 void *raw_ptr = PyCapsule_GetPointer(cpp_conduit, cpp_type_info->name()); 0100 Py_DECREF(cpp_conduit); 0101 if (PyErr_Occurred()) { 0102 return nullptr; 0103 } 0104 return raw_ptr; 0105 } 0106 0107 template <typename T> 0108 T *get_type_pointer_ephemeral(PyObject *py_obj) { 0109 void *raw_ptr = get_raw_pointer_ephemeral(py_obj, &typeid(T)); 0110 if (raw_ptr == nullptr) { 0111 return nullptr; 0112 } 0113 return static_cast<T *>(raw_ptr); 0114 } 0115 0116 } // namespace pybind11_conduit_v1
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|