@@ -36,6 +36,7 @@ struct is_smart_holder_type<smart_holder> : std::true_type {};
3636// SMART_HOLDER_WIP: Needs refactoring of existing pybind11 code.
3737inline void register_instance (instance *self, void *valptr, const type_info *tinfo);
3838inline bool deregister_instance (instance *self, void *valptr, const type_info *tinfo);
39+ extern " C" inline PyObject *pybind11_object_new (PyTypeObject *type, PyObject *, PyObject *);
3940
4041// Replace all occurrences of substrings in a string.
4142inline void replace_all (std::string &str, const std::string &from, const std::string &to) {
@@ -49,20 +50,52 @@ inline void replace_all(std::string &str, const std::string &from, const std::st
4950 }
5051}
5152
53+ inline bool type_is_pybind11_class_ (PyTypeObject *type_obj) {
54+ #if defined(PYPY_VERSION)
55+ auto &internals = get_internals ();
56+ return bool (internals.registered_types_py .find (type_obj)
57+ != internals.registered_types_py .end ());
58+ #else
59+ return bool (type_obj->tp_new == pybind11_object_new);
60+ #endif
61+ }
62+
63+ inline bool is_instance_method_of_type (PyTypeObject *type_obj, PyObject *attr_name) {
64+ PyObject *descr = _PyType_Lookup (type_obj, attr_name);
65+ return bool ((descr != nullptr ) && PyInstanceMethod_Check (descr));
66+ }
67+
68+ inline object try_get_as_capsule_method (PyObject *obj, PyObject *attr_name) {
69+ if (PyType_Check (obj)) {
70+ return object ();
71+ }
72+ PyTypeObject *type_obj = Py_TYPE (obj);
73+ bool known_callable = false ;
74+ if (type_is_pybind11_class_ (type_obj)) {
75+ if (!is_instance_method_of_type (type_obj, attr_name)) {
76+ return object ();
77+ }
78+ known_callable = true ;
79+ }
80+ PyObject *method = PyObject_GetAttr (obj, attr_name);
81+ if (method == nullptr ) {
82+ PyErr_Clear ();
83+ return object ();
84+ }
85+ if (!known_callable && PyCallable_Check (method) == 0 ) {
86+ Py_DECREF (method);
87+ return object ();
88+ }
89+ return reinterpret_steal<object>(method);
90+ }
91+
5292inline void *try_as_void_ptr_capsule_get_pointer (handle src, const char *typeid_name) {
53- std::string type_name = typeid_name;
54- detail::clean_type_id (type_name);
55-
56- // Convert `a::b::c` to `a_b_c`.
57- replace_all (type_name, " ::" , " _" );
58- // Remove all `*` in the type name.
59- replace_all (type_name, " *" , " " );
60-
61- std::string as_void_ptr_function_name (" as_" );
62- as_void_ptr_function_name += type_name;
63- if (hasattr (src, as_void_ptr_function_name.c_str ())) {
64- auto as_void_ptr_function = function (src.attr (as_void_ptr_function_name.c_str ()));
65- auto void_ptr_capsule = as_void_ptr_function ();
93+ std::string suffix = clean_type_id (typeid_name);
94+ replace_all (suffix, " ::" , " _" ); // Convert `a::b::c` to `a_b_c`.
95+ replace_all (suffix, " *" , " " );
96+ object as_capsule_method = try_get_as_capsule_method (src.ptr (), str (" as_" + suffix).ptr ());
97+ if (as_capsule_method) {
98+ object void_ptr_capsule = as_capsule_method ();
6699 if (isinstance<capsule>(void_ptr_capsule)) {
67100 return reinterpret_borrow<capsule>(void_ptr_capsule).get_pointer ();
68101 }
@@ -304,11 +337,8 @@ class modified_type_caster_generic_load_impl {
304337 loaded_v_h = value_and_holder ();
305338 return true ;
306339 }
307- if (convert && cpptype) {
308- const auto &bases = all_type_info (srctype);
309- if (bases.empty () && try_as_void_ptr_capsule (src)) {
310- return true ;
311- }
340+ if (convert && cpptype && try_as_void_ptr_capsule (src)) {
341+ return true ;
312342 }
313343 return false ;
314344 }
0 commit comments