@@ -1797,22 +1797,18 @@ void keep_alive(PyObject *nurse, PyObject *patient) {
17971797 Py_INCREF (patient);
17981798 ((nb_inst *) nurse)->clear_keep_alive = true ;
17991799 } else {
1800+ #if !defined(NB_DISABLE_INTEROP)
1801+ if (pymb_binding *binding = pymb_get_binding (nurse);
1802+ binding && binding->framework ->keep_alive (nurse, patient, nullptr ))
1803+ return ;
1804+ #endif
18001805 PyObject *callback =
18011806 PyCFunction_New (&keep_alive_callback_def, patient);
18021807
18031808 PyObject *weakref = PyWeakref_NewRef (nurse, callback);
18041809 if (!weakref) {
18051810 Py_DECREF (callback);
18061811 PyErr_Clear ();
1807- #if !defined(NB_DISABLE_INTEROP)
1808- if (pymb_binding *binding = pymb_get_binding (nurse)) {
1809- // Try a foreign framework's keep_alive as a last resort
1810- if (binding->framework ->keep_alive (nurse, patient,
1811- nullptr ) == 0 )
1812- return ;
1813- raise_python_error ();
1814- }
1815- #endif
18161812 raise (" nanobind::detail::keep_alive(): could not create a weak "
18171813 " reference! Likely, the 'nurse' argument you specified is not "
18181814 " a weak-referenceable type!" );
@@ -1830,7 +1826,8 @@ void keep_alive(PyObject *nurse, void *payload,
18301826 void (*callback)(void *) noexcept ) noexcept {
18311827 check (nurse, " nanobind::detail::keep_alive(): 'nurse' is undefined!" );
18321828
1833- if (nb_type_check ((PyObject *) Py_TYPE (nurse))) {
1829+ PyObject *nurse_ty = (PyObject *) Py_TYPE (nurse);
1830+ if (nb_type_check (nurse_ty)) {
18341831#if defined(NB_FREE_THREADED)
18351832 nb_shard &shard = internals->shard (inst_ptr ((nb_inst *) nurse));
18361833 lock_shard guard (shard);
@@ -1850,6 +1847,11 @@ void keep_alive(PyObject *nurse, void *payload,
18501847
18511848 ((nb_inst *) nurse)->clear_keep_alive = true ;
18521849 } else {
1850+ #if !defined(NB_DISABLE_INTEROP)
1851+ if (pymb_binding *binding = pymb_get_binding (nurse_ty);
1852+ binding && binding->framework ->keep_alive (nurse, payload, callback))
1853+ return ;
1854+ #endif
18531855 PyObject *patient = capsule_new (payload, nullptr , callback);
18541856 keep_alive (nurse, patient);
18551857 Py_DECREF (patient);
@@ -1957,36 +1959,64 @@ PyObject *nb_type_put_foreign(nb_internals *internals_,
19571959 bool *is_new) noexcept {
19581960 struct capture {
19591961 void *value;
1960- rv_policy rvp;
1961- PyObject *parent;
1962- bool check_new;
1963- bool is_new = false ;
1964- } cap{value, rvp, cleanup ? cleanup->self () : nullptr , bool (is_new)};
1962+ pymb_rv_policy rvp = pymb_rv_policy_none; // conservative default
1963+ struct pymb_to_python_feedback feedback{};
1964+ struct pymb_framework *used_framework = nullptr ;
1965+ } cap{value};
1966+
1967+ switch (rvp) {
1968+ case rv_policy::reference_internal:
1969+ if (!cleanup || !cleanup->self ())
1970+ return nullptr ;
1971+ cap.rvp = pymb_rv_policy_share_ownership;
1972+ break ;
1973+ case rv_policy::reference:
1974+ if (is_new) {
1975+ cap.rvp = pymb_rv_policy_share_ownership;
1976+ break ;
1977+ }
1978+ [[fallthrough]];
1979+ case rv_policy::take_ownership:
1980+ case rv_policy::copy:
1981+ case rv_policy::move:
1982+ case rv_policy::none:
1983+ cap.rvp = (pymb_rv_policy) rvp;
1984+ break ;
1985+ case rv_policy::automatic:
1986+ case rv_policy::automatic_reference:
1987+ check (false ,
1988+ " nb_type_put_foreign(): automatic rvp should have been "
1989+ " converted to a different one before reaching here!" );
1990+ break ;
1991+ }
19651992
19661993 auto attempt = +[](void *closure, pymb_binding *binding) -> void * {
19671994 capture &cap = *(capture *) closure;
1968- if (cap.check_new || cap.rvp == rv_policy::none) {
1969- PyObject* existing = binding->framework ->to_python (
1970- binding, cap.value , pymb_rv_policy_none, nullptr );
1971- if (existing || cap.rvp == rv_policy::none) {
1972- cap.is_new = false ;
1973- return existing;
1974- }
1975- cap.is_new = true ;
1976- }
1995+ cap.used_framework = binding->framework ;
19771996 return binding->framework ->to_python (
1978- binding, cap.value , (pymb_rv_policy) (uint8_t ) cap.rvp ,
1979- cap.parent );
1997+ binding, cap.value , cap.rvp , &cap.feedback );
19801998 };
19811999
1982- void *result = nullptr ;
2000+ void *result_v = nullptr ;
19832001 if (cpp_type_p && cpp_type_p != cpp_type)
1984- result = nb_type_try_foreign (internals_, cpp_type_p, attempt, &cap);
1985- if (!result)
1986- result = nb_type_try_foreign (internals_, cpp_type, attempt, &cap);
2002+ result_v = nb_type_try_foreign (internals_, cpp_type_p, attempt, &cap);
2003+ if (!result_v)
2004+ result_v = nb_type_try_foreign (internals_, cpp_type, attempt, &cap);
2005+
2006+ PyObject *result = (PyObject *) result_v;
19872007 if (is_new)
1988- *is_new = cap.is_new ;
1989- return (PyObject *) result;
2008+ *is_new = cap.feedback .is_new ;
2009+ if (result && rvp == rv_policy::reference_internal && cap.feedback .is_new &&
2010+ !cap.used_framework ->keep_alive (result, cleanup->self (), nullptr )) {
2011+ try {
2012+ keep_alive (result, cleanup->self ());
2013+ } catch (python_error& exc) {
2014+ exc.restore ();
2015+ Py_DECREF (result);
2016+ return nullptr ;
2017+ }
2018+ }
2019+ return result;
19902020}
19912021#endif
19922022
0 commit comments