Skip to main content

pyo3/types/weakref/
anyref.rs

1use crate::err::PyResult;
2use crate::ffi_ptr_ext::FfiPtrExt;
3#[cfg(feature = "experimental-inspect")]
4use crate::inspect::{type_hint_union, PyStaticExpr};
5use crate::sync::PyOnceLock;
6use crate::type_object::{PyTypeCheck, PyTypeInfo};
7use crate::types::any::PyAny;
8use crate::types::{PyTuple, PyWeakrefProxy, PyWeakrefReference};
9use crate::{ffi, Bound, Py, Python};
10
11/// Represents any Python `weakref` reference.
12///
13/// In Python this is created by calling `weakref.ref` or `weakref.proxy`.
14#[repr(transparent)]
15pub struct PyWeakref(PyAny);
16
17pyobject_native_type_named!(PyWeakref);
18
19// TODO: We known the layout but this cannot be implemented, due to the lack of public typeobject pointers
20// #[cfg(not(Py_LIMITED_API))]
21// pyobject_native_type_sized!(PyWeakref, ffi::PyWeakReference);
22
23unsafe impl PyTypeCheck for PyWeakref {
24    const NAME: &'static str = "weakref";
25
26    #[cfg(feature = "experimental-inspect")]
27    const TYPE_HINT: PyStaticExpr = type_hint_union!(
28        PyWeakrefProxy::TYPE_HINT,
29        <PyWeakrefReference as PyTypeCheck>::TYPE_HINT
30    );
31
32    #[inline]
33    fn type_check(object: &Bound<'_, PyAny>) -> bool {
34        unsafe { ffi::PyWeakref_Check(object.as_ptr()) > 0 }
35    }
36
37    fn classinfo_object(py: Python<'_>) -> Bound<'_, PyAny> {
38        static TYPE: PyOnceLock<Py<PyAny>> = PyOnceLock::new();
39        TYPE.get_or_try_init(py, || {
40            PyResult::Ok(
41                PyTuple::new(
42                    py,
43                    [
44                        PyWeakrefProxy::classinfo_object(py),
45                        PyWeakrefReference::classinfo_object(py),
46                    ],
47                )?
48                .into_any()
49                .unbind(),
50            )
51        })
52        .unwrap()
53        .bind(py)
54        .clone()
55    }
56}
57
58/// Implementation of functionality for [`PyWeakref`].
59///
60/// These methods are defined for the `Bound<'py, PyWeakref>` smart pointer, so to use method call
61/// syntax these methods are separated into a trait, because stable Rust does not yet support
62/// `arbitrary_self_types`.
63#[doc(alias = "PyWeakref")]
64pub trait PyWeakrefMethods<'py>: crate::sealed::Sealed {
65    /// Upgrade the weakref to a direct Bound object reference.
66    ///
67    /// It is named `upgrade` to be inline with [rust's `Weak::upgrade`](std::rc::Weak::upgrade).
68    /// In Python it would be equivalent to [`PyWeakref_GetRef`].
69    ///
70    /// # Example
71    #[cfg_attr(
72        not(all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9))))),
73        doc = "```rust,ignore"
74    )]
75    #[cfg_attr(
76        all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9)))),
77        doc = "```rust"
78    )]
79    /// use pyo3::prelude::*;
80    /// use pyo3::types::PyWeakrefReference;
81    ///
82    /// #[pyclass(weakref)]
83    /// struct Foo { /* fields omitted */ }
84    ///
85    /// #[pymethods]
86    /// impl Foo {
87    ///     fn get_data(&self) -> (&str, u32) {
88    ///         ("Dave", 10)
89    ///     }
90    /// }
91    ///
92    /// fn parse_data(reference: Borrowed<'_, '_, PyWeakrefReference>) -> PyResult<String> {
93    ///     if let Some(data_src) = reference.upgrade_as::<Foo>()? {
94    ///         let data = data_src.borrow();
95    ///         let (name, score) = data.get_data();
96    ///         Ok(format!("Processing '{}': score = {}", name, score))
97    ///     } else {
98    ///         Ok("The supplied data reference is no longer relevant.".to_owned())
99    ///     }
100    /// }
101    ///
102    /// # fn main() -> PyResult<()> {
103    /// Python::attach(|py| {
104    ///     let data = Bound::new(py, Foo{})?;
105    ///     let reference = PyWeakrefReference::new(&data)?;
106    ///
107    ///     assert_eq!(
108    ///         parse_data(reference.as_borrowed())?,
109    ///         "Processing 'Dave': score = 10"
110    ///     );
111    ///
112    ///     drop(data);
113    ///
114    ///     assert_eq!(
115    ///         parse_data(reference.as_borrowed())?,
116    ///         "The supplied data reference is no longer relevant."
117    ///     );
118    ///
119    ///     Ok(())
120    /// })
121    /// # }
122    /// ```
123    ///
124    /// # Panics
125    /// This function panics is the current object is invalid.
126    /// If used properly this is never the case. (NonNull and actually a weakref type)
127    ///
128    /// [`PyWeakref_GetRef`]: https://docs.python.org/3/c-api/weakref.html#c.PyWeakref_GetRef
129    /// [`weakref.ReferenceType`]: https://docs.python.org/3/library/weakref.html#weakref.ReferenceType
130    /// [`weakref.ref`]: https://docs.python.org/3/library/weakref.html#weakref.ref
131    fn upgrade_as<T>(&self) -> PyResult<Option<Bound<'py, T>>>
132    where
133        T: PyTypeCheck,
134    {
135        self.upgrade()
136            .map(Bound::cast_into::<T>)
137            .transpose()
138            .map_err(Into::into)
139    }
140
141    /// Upgrade the weakref to a direct Bound object reference unchecked. The type of the recovered object is not checked before casting, this could lead to unexpected behavior. Use only when absolutely certain the type can be guaranteed. The `weakref` may still return `None`.
142    ///
143    /// It is named `upgrade` to be inline with [rust's `Weak::upgrade`](std::rc::Weak::upgrade).
144    /// In Python it would be equivalent to [`PyWeakref_GetRef`].
145    ///
146    /// # Safety
147    /// Callers must ensure that the type is valid or risk type confusion.
148    /// The `weakref` is still allowed to be `None`, if the referenced object has been cleaned up.
149    ///
150    /// # Example
151    #[cfg_attr(
152        not(all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9))))),
153        doc = "```rust,ignore"
154    )]
155    #[cfg_attr(
156        all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9)))),
157        doc = "```rust"
158    )]
159    /// use pyo3::prelude::*;
160    /// use pyo3::types::PyWeakrefReference;
161    ///
162    /// #[pyclass(weakref)]
163    /// struct Foo { /* fields omitted */ }
164    ///
165    /// #[pymethods]
166    /// impl Foo {
167    ///     fn get_data(&self) -> (&str, u32) {
168    ///         ("Dave", 10)
169    ///     }
170    /// }
171    ///
172    /// fn parse_data(reference: Borrowed<'_, '_, PyWeakrefReference>) -> String {
173    ///     if let Some(data_src) = unsafe { reference.upgrade_as_unchecked::<Foo>() } {
174    ///         let data = data_src.borrow();
175    ///         let (name, score) = data.get_data();
176    ///         format!("Processing '{}': score = {}", name, score)
177    ///     } else {
178    ///         "The supplied data reference is no longer relevant.".to_owned()
179    ///     }
180    /// }
181    ///
182    /// # fn main() -> PyResult<()> {
183    /// Python::attach(|py| {
184    ///     let data = Bound::new(py, Foo{})?;
185    ///     let reference = PyWeakrefReference::new(&data)?;
186    ///
187    ///     assert_eq!(
188    ///         parse_data(reference.as_borrowed()),
189    ///         "Processing 'Dave': score = 10"
190    ///     );
191    ///
192    ///     drop(data);
193    ///
194    ///     assert_eq!(
195    ///         parse_data(reference.as_borrowed()),
196    ///         "The supplied data reference is no longer relevant."
197    ///     );
198    ///
199    ///     Ok(())
200    /// })
201    /// # }
202    /// ```
203    ///
204    /// # Panics
205    /// This function panics is the current object is invalid.
206    /// If used properly this is never the case. (NonNull and actually a weakref type)
207    ///
208    /// [`PyWeakref_GetRef`]: https://docs.python.org/3/c-api/weakref.html#c.PyWeakref_GetRef
209    /// [`weakref.ReferenceType`]: https://docs.python.org/3/library/weakref.html#weakref.ReferenceType
210    /// [`weakref.ref`]: https://docs.python.org/3/library/weakref.html#weakref.ref
211    unsafe fn upgrade_as_unchecked<T>(&self) -> Option<Bound<'py, T>> {
212        Some(unsafe { self.upgrade()?.cast_into_unchecked() })
213    }
214
215    /// Upgrade the weakref to a exact direct Bound object reference.
216    ///
217    /// It is named `upgrade` to be inline with [rust's `Weak::upgrade`](std::rc::Weak::upgrade).
218    /// In Python it would be equivalent to [`PyWeakref_GetRef`].
219    ///
220    /// # Example
221    #[cfg_attr(
222        not(all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9))))),
223        doc = "```rust,ignore"
224    )]
225    #[cfg_attr(
226        all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9)))),
227        doc = "```rust"
228    )]
229    /// use pyo3::prelude::*;
230    /// use pyo3::types::PyWeakrefReference;
231    ///
232    /// #[pyclass(weakref)]
233    /// struct Foo { /* fields omitted */ }
234    ///
235    /// #[pymethods]
236    /// impl Foo {
237    ///     fn get_data(&self) -> (&str, u32) {
238    ///         ("Dave", 10)
239    ///     }
240    /// }
241    ///
242    /// fn parse_data(reference: Borrowed<'_, '_, PyWeakrefReference>) -> PyResult<String> {
243    ///     if let Some(data_src) = reference.upgrade_as_exact::<Foo>()? {
244    ///         let data = data_src.borrow();
245    ///         let (name, score) = data.get_data();
246    ///         Ok(format!("Processing '{}': score = {}", name, score))
247    ///     } else {
248    ///         Ok("The supplied data reference is no longer relevant.".to_owned())
249    ///     }
250    /// }
251    ///
252    /// # fn main() -> PyResult<()> {
253    /// Python::attach(|py| {
254    ///     let data = Bound::new(py, Foo{})?;
255    ///     let reference = PyWeakrefReference::new(&data)?;
256    ///
257    ///     assert_eq!(
258    ///         parse_data(reference.as_borrowed())?,
259    ///         "Processing 'Dave': score = 10"
260    ///     );
261    ///
262    ///     drop(data);
263    ///
264    ///     assert_eq!(
265    ///         parse_data(reference.as_borrowed())?,
266    ///         "The supplied data reference is no longer relevant."
267    ///     );
268    ///
269    ///     Ok(())
270    /// })
271    /// # }
272    /// ```
273    ///
274    /// # Panics
275    /// This function panics is the current object is invalid.
276    /// If used properly this is never the case. (NonNull and actually a weakref type)
277    ///
278    /// [`PyWeakref_GetRef`]: https://docs.python.org/3/c-api/weakref.html#c.PyWeakref_GetRef
279    /// [`weakref.ReferenceType`]: https://docs.python.org/3/library/weakref.html#weakref.ReferenceType
280    /// [`weakref.ref`]: https://docs.python.org/3/library/weakref.html#weakref.ref
281    fn upgrade_as_exact<T>(&self) -> PyResult<Option<Bound<'py, T>>>
282    where
283        T: PyTypeInfo,
284    {
285        self.upgrade()
286            .map(Bound::cast_into_exact)
287            .transpose()
288            .map_err(Into::into)
289    }
290
291    /// Upgrade the weakref to a Bound [`PyAny`] reference to the target object if possible.
292    ///
293    /// It is named `upgrade` to be inline with [rust's `Weak::upgrade`](std::rc::Weak::upgrade).
294    /// This function returns `Some(Bound<'py, PyAny>)` if the reference still exists, otherwise `None` will be returned.
295    ///
296    /// This function gets the optional target of this [`weakref.ReferenceType`] (result of calling [`weakref.ref`]).
297    /// It produces similar results to using [`PyWeakref_GetRef`] in the C api.
298    ///
299    /// # Example
300    #[cfg_attr(
301        not(all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9))))),
302        doc = "```rust,ignore"
303    )]
304    #[cfg_attr(
305        all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9)))),
306        doc = "```rust"
307    )]
308    /// use pyo3::prelude::*;
309    /// use pyo3::types::PyWeakrefReference;
310    ///
311    /// #[pyclass(weakref)]
312    /// struct Foo { /* fields omitted */ }
313    ///
314    /// fn parse_data(reference: Borrowed<'_, '_, PyWeakrefReference>) -> PyResult<String> {
315    ///     if let Some(object) = reference.upgrade() {
316    ///         Ok(format!("The object '{}' referred by this reference still exists.", object.getattr("__class__")?.getattr("__qualname__")?))
317    ///     } else {
318    ///         Ok("The object, which this reference referred to, no longer exists".to_owned())
319    ///     }
320    /// }
321    ///
322    /// # fn main() -> PyResult<()> {
323    /// Python::attach(|py| {
324    ///     let data = Bound::new(py, Foo{})?;
325    ///     let reference = PyWeakrefReference::new(&data)?;
326    ///
327    ///     assert_eq!(
328    ///         parse_data(reference.as_borrowed())?,
329    ///         "The object 'Foo' referred by this reference still exists."
330    ///     );
331    ///
332    ///     drop(data);
333    ///
334    ///     assert_eq!(
335    ///         parse_data(reference.as_borrowed())?,
336    ///         "The object, which this reference referred to, no longer exists"
337    ///     );
338    ///
339    ///     Ok(())
340    /// })
341    /// # }
342    /// ```
343    ///
344    /// # Panics
345    /// This function panics is the current object is invalid.
346    /// If used properly this is never the case. (NonNull and actually a weakref type)
347    ///
348    /// [`PyWeakref_GetRef`]: https://docs.python.org/3/c-api/weakref.html#c.PyWeakref_GetRef
349    /// [`weakref.ReferenceType`]: https://docs.python.org/3/library/weakref.html#weakref.ReferenceType
350    /// [`weakref.ref`]: https://docs.python.org/3/library/weakref.html#weakref.ref
351    fn upgrade(&self) -> Option<Bound<'py, PyAny>>;
352}
353
354impl<'py> PyWeakrefMethods<'py> for Bound<'py, PyWeakref> {
355    fn upgrade(&self) -> Option<Bound<'py, PyAny>> {
356        let mut obj: *mut ffi::PyObject = std::ptr::null_mut();
357        match unsafe { ffi::compat::PyWeakref_GetRef(self.as_ptr(), &mut obj) } {
358            std::ffi::c_int::MIN..=-1 => panic!("The 'weakref' weak reference instance should be valid (non-null and actually a weakref reference)"),
359            0 => None,
360            1..=std::ffi::c_int::MAX => Some(unsafe { obj.assume_owned_unchecked(self.py()) }),
361        }
362    }
363}
364
365#[cfg(test)]
366mod tests {
367    use crate::types::any::{PyAny, PyAnyMethods};
368    use crate::types::weakref::{PyWeakref, PyWeakrefMethods, PyWeakrefProxy, PyWeakrefReference};
369    use crate::{Bound, PyResult, Python};
370
371    fn new_reference<'py>(object: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyWeakref>> {
372        let reference = PyWeakrefReference::new(object)?;
373        reference.cast_into().map_err(Into::into)
374    }
375
376    fn new_proxy<'py>(object: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyWeakref>> {
377        let reference = PyWeakrefProxy::new(object)?;
378        reference.cast_into().map_err(Into::into)
379    }
380
381    mod python_class {
382        use super::*;
383        #[cfg(Py_3_10)]
384        use crate::types::PyInt;
385        use crate::PyTypeCheck;
386        use crate::{py_result_ext::PyResultExt, types::PyType};
387        use std::ptr;
388
389        fn get_type(py: Python<'_>) -> PyResult<Bound<'_, PyType>> {
390            py.run(c"class A:\n    pass\n", None, None)?;
391            py.eval(c"A", None, None).cast_into::<PyType>()
392        }
393
394        #[test]
395        fn test_weakref_upgrade_as() -> PyResult<()> {
396            fn inner(
397                create_reference: impl for<'py> FnOnce(
398                    &Bound<'py, PyAny>,
399                )
400                    -> PyResult<Bound<'py, PyWeakref>>,
401            ) -> PyResult<()> {
402                Python::attach(|py| {
403                    let class = get_type(py)?;
404                    let object = class.call0()?;
405                    let reference = create_reference(&object)?;
406
407                    {
408                        // This test is a bit weird but ok.
409                        let obj = reference.upgrade_as::<PyAny>();
410
411                        assert!(obj.is_ok());
412                        let obj = obj.unwrap();
413
414                        assert!(obj.is_some());
415                        assert!(obj.is_some_and(|obj| ptr::eq(obj.as_ptr(), object.as_ptr())
416                            && obj.is_exact_instance(&class)));
417                    }
418
419                    drop(object);
420
421                    {
422                        // This test is a bit weird but ok.
423                        let obj = reference.upgrade_as::<PyAny>();
424
425                        assert!(obj.is_ok());
426                        let obj = obj.unwrap();
427
428                        assert!(obj.is_none());
429                    }
430
431                    Ok(())
432                })
433            }
434
435            inner(new_reference)?;
436            inner(new_proxy)
437        }
438
439        #[test]
440        fn test_weakref_upgrade_as_unchecked() -> PyResult<()> {
441            fn inner(
442                create_reference: impl for<'py> FnOnce(
443                    &Bound<'py, PyAny>,
444                )
445                    -> PyResult<Bound<'py, PyWeakref>>,
446            ) -> PyResult<()> {
447                Python::attach(|py| {
448                    let class = get_type(py)?;
449                    let object = class.call0()?;
450                    let reference = create_reference(&object)?;
451
452                    {
453                        // This test is a bit weird but ok.
454                        let obj = unsafe { reference.upgrade_as_unchecked::<PyAny>() };
455
456                        assert!(obj.is_some());
457                        assert!(obj.is_some_and(|obj| ptr::eq(obj.as_ptr(), object.as_ptr())
458                            && obj.is_exact_instance(&class)));
459                    }
460
461                    drop(object);
462
463                    {
464                        // This test is a bit weird but ok.
465                        let obj = unsafe { reference.upgrade_as_unchecked::<PyAny>() };
466
467                        assert!(obj.is_none());
468                    }
469
470                    Ok(())
471                })
472            }
473
474            inner(new_reference)?;
475            inner(new_proxy)
476        }
477
478        #[test]
479        fn test_weakref_upgrade() -> PyResult<()> {
480            fn inner(
481                create_reference: impl for<'py> FnOnce(
482                    &Bound<'py, PyAny>,
483                )
484                    -> PyResult<Bound<'py, PyWeakref>>,
485                call_retrievable: bool,
486            ) -> PyResult<()> {
487                let not_call_retrievable = !call_retrievable;
488
489                Python::attach(|py| {
490                    let class = get_type(py)?;
491                    let object = class.call0()?;
492                    let reference = create_reference(&object)?;
493
494                    assert!(not_call_retrievable || reference.call0()?.is(&object));
495                    assert!(reference.upgrade().is_some());
496                    assert!(reference.upgrade().is_some_and(|obj| obj.is(&object)));
497
498                    drop(object);
499
500                    assert!(not_call_retrievable || reference.call0()?.is_none());
501                    assert!(reference.upgrade().is_none());
502
503                    Ok(())
504                })
505            }
506
507            inner(new_reference, true)?;
508            inner(new_proxy, false)
509        }
510
511        #[test]
512        fn test_classinfo_object() -> PyResult<()> {
513            fn inner(
514                create_reference: impl for<'py> FnOnce(
515                    &Bound<'py, PyAny>,
516                )
517                    -> PyResult<Bound<'py, PyWeakref>>,
518            ) -> PyResult<()> {
519                Python::attach(|py| {
520                    let class = get_type(py)?;
521                    let object = class.call0()?;
522                    let reference = create_reference(&object)?;
523                    let t = PyWeakref::classinfo_object(py);
524                    assert!(reference.is_instance(&t)?);
525                    Ok(())
526                })
527            }
528
529            inner(new_reference)?;
530            inner(new_proxy)
531        }
532
533        #[cfg(Py_3_10)] // Name is different in 3.9
534        #[test]
535        fn test_classinfo_downcast_error() -> PyResult<()> {
536            Python::attach(|py| {
537                assert_eq!(
538                    PyInt::new(py, 1)
539                        .cast_into::<PyWeakref>()
540                        .unwrap_err()
541                        .to_string(),
542                    "'int' object is not an instance of 'ProxyType | CallableProxyType | ReferenceType'"
543                );
544                Ok(())
545            })
546        }
547    }
548
549    // under 'abi3-py37' and 'abi3-py38' PyClass cannot be weakreferencable.
550    #[cfg(all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9)))))]
551    mod pyo3_pyclass {
552        use super::*;
553        use crate::{pyclass, Py};
554        use std::ptr;
555
556        #[pyclass(weakref, crate = "crate")]
557        struct WeakrefablePyClass {}
558
559        #[test]
560        fn test_weakref_upgrade_as() -> PyResult<()> {
561            fn inner(
562                create_reference: impl for<'py> FnOnce(
563                    &Bound<'py, PyAny>,
564                )
565                    -> PyResult<Bound<'py, PyWeakref>>,
566            ) -> PyResult<()> {
567                Python::attach(|py| {
568                    let object = Py::new(py, WeakrefablePyClass {})?;
569                    let reference = create_reference(object.bind(py))?;
570
571                    {
572                        let obj = reference.upgrade_as::<WeakrefablePyClass>();
573
574                        assert!(obj.is_ok());
575                        let obj = obj.unwrap();
576
577                        assert!(obj.is_some());
578                        assert!(obj.is_some_and(|obj| ptr::eq(obj.as_ptr(), object.as_ptr())));
579                    }
580
581                    drop(object);
582
583                    {
584                        let obj = reference.upgrade_as::<WeakrefablePyClass>();
585
586                        assert!(obj.is_ok());
587                        let obj = obj.unwrap();
588
589                        assert!(obj.is_none());
590                    }
591
592                    Ok(())
593                })
594            }
595
596            inner(new_reference)?;
597            inner(new_proxy)
598        }
599
600        #[test]
601        fn test_weakref_upgrade_as_unchecked() -> PyResult<()> {
602            fn inner(
603                create_reference: impl for<'py> FnOnce(
604                    &Bound<'py, PyAny>,
605                )
606                    -> PyResult<Bound<'py, PyWeakref>>,
607            ) -> PyResult<()> {
608                Python::attach(|py| {
609                    let object = Py::new(py, WeakrefablePyClass {})?;
610                    let reference = create_reference(object.bind(py))?;
611
612                    {
613                        let obj = unsafe { reference.upgrade_as_unchecked::<WeakrefablePyClass>() };
614
615                        assert!(obj.is_some());
616                        assert!(obj.is_some_and(|obj| ptr::eq(obj.as_ptr(), object.as_ptr())));
617                    }
618
619                    drop(object);
620
621                    {
622                        let obj = unsafe { reference.upgrade_as_unchecked::<WeakrefablePyClass>() };
623
624                        assert!(obj.is_none());
625                    }
626
627                    Ok(())
628                })
629            }
630
631            inner(new_reference)?;
632            inner(new_proxy)
633        }
634
635        #[test]
636        fn test_weakref_upgrade() -> PyResult<()> {
637            fn inner(
638                create_reference: impl for<'py> FnOnce(
639                    &Bound<'py, PyAny>,
640                )
641                    -> PyResult<Bound<'py, PyWeakref>>,
642                call_retrievable: bool,
643            ) -> PyResult<()> {
644                let not_call_retrievable = !call_retrievable;
645
646                Python::attach(|py| {
647                    let object = Py::new(py, WeakrefablePyClass {})?;
648                    let reference = create_reference(object.bind(py))?;
649
650                    assert!(not_call_retrievable || reference.call0()?.is(&object));
651                    assert!(reference.upgrade().is_some());
652                    assert!(reference.upgrade().is_some_and(|obj| obj.is(&object)));
653
654                    drop(object);
655
656                    assert!(not_call_retrievable || reference.call0()?.is_none());
657                    assert!(reference.upgrade().is_none());
658
659                    Ok(())
660                })
661            }
662
663            inner(new_reference, true)?;
664            inner(new_proxy, false)
665        }
666    }
667}