pyo3/types/weakref/
anyref.rs

1use crate::err::PyResult;
2use crate::ffi_ptr_ext::FfiPtrExt;
3use crate::type_object::{PyTypeCheck, PyTypeInfo};
4use crate::types::{
5    any::{PyAny, PyAnyMethods},
6    PyNone,
7};
8use crate::{ffi, Borrowed, Bound, DowncastError};
9
10#[cfg(feature = "gil-refs")]
11use crate::PyNativeType;
12
13/// Represents any Python `weakref` reference.
14///
15/// In Python this is created by calling `weakref.ref` or `weakref.proxy`.
16#[repr(transparent)]
17pub struct PyWeakref(PyAny);
18
19pyobject_native_type_named!(PyWeakref);
20pyobject_native_type_extract!(PyWeakref);
21
22// TODO: We known the layout but this cannot be implemented, due to the lack of public typeobject pointers
23// #[cfg(not(Py_LIMITED_API))]
24// pyobject_native_type_sized!(PyWeakref, ffi::PyWeakReference);
25
26impl PyTypeCheck for PyWeakref {
27    const NAME: &'static str = "weakref";
28
29    fn type_check(object: &Bound<'_, PyAny>) -> bool {
30        unsafe { ffi::PyWeakref_Check(object.as_ptr()) > 0 }
31    }
32}
33
34#[cfg(feature = "gil-refs")]
35impl PyWeakref {
36    // TODO: MAYBE ADD CREATION METHODS OR EASY CASTING?;
37
38    /// Upgrade the weakref to a direct object reference.
39    ///
40    /// It is named `upgrade` to be inline with [rust's `Weak::upgrade`](std::rc::Weak::upgrade).
41    /// In Python it would be equivalent to [`PyWeakref_GetObject`] or retrieving the Object from Python.
42    ///
43    /// # Example
44    #[cfg_attr(
45        not(all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9))))),
46        doc = "```rust,ignore"
47    )]
48    #[cfg_attr(
49        all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9)))),
50        doc = "```rust"
51    )]
52    /// use pyo3::prelude::*;
53    /// use pyo3::types::{PyWeakref, PyWeakrefProxy};
54    ///
55    /// #[pyclass(weakref)]
56    /// struct Foo { /* fields omitted */ }
57    ///
58    /// #[pymethods]
59    /// impl Foo {
60    ///     fn get_data(&self) -> (&str, u32) {
61    ///         ("Dave", 10)
62    ///     }
63    /// }
64    ///
65    /// fn parse_data(reference: Borrowed<'_, '_, PyWeakref>) -> PyResult<String> {
66    ///     if let Some(data_src) = reference.upgrade_as::<Foo>()? {
67    ///         let data = data_src.borrow();
68    ///         let (name, score) = data.get_data();
69    ///         Ok(format!("Processing '{}': score = {}", name, score))
70    ///     } else {
71    ///         Ok("The supplied data reference is nolonger relavent.".to_owned())
72    ///     }
73    /// }
74    ///
75    /// # fn main() -> PyResult<()> {
76    /// Python::with_gil(|py| {
77    ///     let data = Bound::new(py, Foo{})?;
78    ///     let proxy = PyWeakrefProxy::new_bound(&data)?; // Retrieve this as an PyMethods argument.
79    ///     let reference = proxy.downcast::<PyWeakref>()?;
80    ///
81    ///     assert_eq!(
82    ///         parse_data(reference.as_borrowed())?,
83    ///         "Processing 'Dave': score = 10"
84    ///     );
85    ///
86    ///     drop(data);
87    ///
88    ///     assert_eq!(
89    ///         parse_data(reference.as_borrowed())?,
90    ///         "The supplied data reference is nolonger relavent."
91    ///     );
92    ///
93    ///     Ok(())
94    /// })
95    /// # }
96    /// ```
97    ///
98    /// # Panics
99    /// This function panics is the current object is invalid.
100    /// If used propperly this is never the case. (NonNull and actually a weakref type)
101    ///
102    /// [`PyWeakref_GetObject`]: https://docs.python.org/3/c-api/weakref.html#c.PyWeakref_GetObject
103    pub fn upgrade_as<T>(&self) -> PyResult<Option<&T::AsRefTarget>>
104    where
105        T: PyTypeCheck,
106    {
107        Ok(self
108            .as_borrowed()
109            .upgrade_as::<T>()?
110            .map(Bound::into_gil_ref))
111    }
112
113    /// Upgrade the weakref to a direct object reference unchecked. The type of the recovered object is not checked before downcasting, this could lead to unexpected behavior. Use only when absolutely certain the type can be guaranteed. The `weakref` may still return `None`.
114    ///
115    /// It is named `upgrade` to be inline with [rust's `Weak::upgrade`](std::rc::Weak::upgrade).
116    /// In Python it would be equivalent to [`PyWeakref_GetObject`] or retrieving the Object from Python.
117    ///
118    /// # Safety
119    /// Callers must ensure that the type is valid or risk type confusion.
120    /// The `weakref` is still allowed to be `None`, if the referenced object has been cleaned up.
121    ///
122    /// # Example
123    #[cfg_attr(
124        not(all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9))))),
125        doc = "```rust,ignore"
126    )]
127    #[cfg_attr(
128        all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9)))),
129        doc = "```rust"
130    )]
131    /// use pyo3::prelude::*;
132    /// use pyo3::types::{PyWeakref, PyWeakrefProxy};
133    ///
134    /// #[pyclass(weakref)]
135    /// struct Foo { /* fields omitted */ }
136    ///
137    /// #[pymethods]
138    /// impl Foo {
139    ///     fn get_data(&self) -> (&str, u32) {
140    ///         ("Dave", 10)
141    ///     }
142    /// }
143    ///
144    /// fn parse_data(reference: Borrowed<'_, '_, PyWeakref>) -> String {
145    ///     if let Some(data_src) = unsafe { reference.upgrade_as_unchecked::<Foo>() } {
146    ///         let data = data_src.borrow();
147    ///         let (name, score) = data.get_data();
148    ///         format!("Processing '{}': score = {}", name, score)
149    ///     } else {
150    ///         "The supplied data reference is nolonger relavent.".to_owned()
151    ///     }
152    /// }
153    ///
154    /// # fn main() -> PyResult<()> {
155    /// Python::with_gil(|py| {
156    ///     let data = Bound::new(py, Foo{})?;
157    ///     let proxy = PyWeakrefProxy::new_bound(&data)?; // Retrieve this as an PyMethods argument.
158    ///     let reference = proxy.downcast::<PyWeakref>()?;
159    ///
160    ///     assert_eq!(
161    ///         parse_data(reference.as_borrowed()),
162    ///         "Processing 'Dave': score = 10"
163    ///     );
164    ///
165    ///     drop(data);
166    ///
167    ///     assert_eq!(
168    ///         parse_data(reference.as_borrowed()),
169    ///         "The supplied data reference is nolonger relavent."
170    ///     );
171    ///
172    ///     Ok(())
173    /// })
174    /// # }
175    /// ```
176    ///
177    /// # Panics
178    /// This function panics is the current object is invalid.
179    /// If used propperly this is never the case. (NonNull and actually a weakref type)
180    ///
181    /// [`PyWeakref_GetObject`]: https://docs.python.org/3/c-api/weakref.html#c.PyWeakref_GetObject
182    pub unsafe fn upgrade_as_unchecked<T>(&self) -> Option<&T::AsRefTarget>
183    where
184        T: PyTypeCheck,
185    {
186        self.as_borrowed()
187            .upgrade_as_unchecked::<T>()
188            .map(Bound::into_gil_ref)
189    }
190
191    /// Upgrade the weakref to an exact direct object reference.
192    ///
193    /// It is named `upgrade` to be inline with [rust's `Weak::upgrade`](std::rc::Weak::upgrade).
194    /// In Python it would be equivalent to [`PyWeakref_GetObject`] or retrieving the Object from Python.
195    ///
196    /// # Example
197    #[cfg_attr(
198        not(all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9))))),
199        doc = "```rust,ignore"
200    )]
201    #[cfg_attr(
202        all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9)))),
203        doc = "```rust"
204    )]
205    /// use pyo3::prelude::*;
206    /// use pyo3::types::{PyWeakref, PyWeakrefProxy};
207    ///
208    /// #[pyclass(weakref)]
209    /// struct Foo { /* fields omitted */ }
210    ///
211    /// #[pymethods]
212    /// impl Foo {
213    ///     fn get_data(&self) -> (&str, u32) {
214    ///         ("Dave", 10)
215    ///     }
216    /// }
217    ///
218    /// fn parse_data(reference: Borrowed<'_, '_, PyWeakref>) -> PyResult<String> {
219    ///     if let Some(data_src) = reference.upgrade_as_exact::<Foo>()? {
220    ///         let data = data_src.borrow();
221    ///         let (name, score) = data.get_data();
222    ///         Ok(format!("Processing '{}': score = {}", name, score))
223    ///     } else {
224    ///         Ok("The supplied data reference is nolonger relavent.".to_owned())
225    ///     }
226    /// }
227    ///
228    /// # fn main() -> PyResult<()> {
229    /// Python::with_gil(|py| {
230    ///     let data = Bound::new(py, Foo{})?;
231    ///     let proxy = PyWeakrefProxy::new_bound(&data)?; // Retrieve this as an PyMethods argument.
232    ///     let reference = proxy.downcast::<PyWeakref>()?;
233    ///
234    ///     assert_eq!(
235    ///         parse_data(reference.as_borrowed())?,
236    ///         "Processing 'Dave': score = 10"
237    ///     );
238    ///
239    ///     drop(data);
240    ///
241    ///     assert_eq!(
242    ///         parse_data(reference.as_borrowed())?,
243    ///         "The supplied data reference is nolonger relavent."
244    ///     );
245    ///
246    ///     Ok(())
247    /// })
248    /// # }
249    /// ```
250    ///
251    /// # Panics
252    /// This function panics is the current object is invalid.
253    /// If used propperly this is never the case. (NonNull and actually a weakref type)
254    ///
255    /// [`PyWeakref_GetObject`]: https://docs.python.org/3/c-api/weakref.html#c.PyWeakref_GetObject
256    pub fn upgrade_as_exact<T>(&self) -> PyResult<Option<&T::AsRefTarget>>
257    where
258        T: PyTypeInfo,
259    {
260        Ok(self
261            .as_borrowed()
262            .upgrade_as_exact::<T>()?
263            .map(Bound::into_gil_ref))
264    }
265
266    /// Upgrade the weakref to a [`PyAny`] reference to the target if possible.
267    ///
268    /// It is named `upgrade` to be inline with [rust's `Weak::upgrade`](std::rc::Weak::upgrade).
269    /// This function returns `Some(&'py PyAny)` if the reference still exists, otherwise `None` will be returned.
270    ///
271    /// This function gets the optional target of this [`PyWeakref`] (Any Python `weakref` weakreference).
272    /// It produces similair results as using [`PyWeakref_GetObject`] in the C api or retrieving the Object from Python.
273    ///
274    /// # Example
275    #[cfg_attr(
276        not(all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9))))),
277        doc = "```rust,ignore"
278    )]
279    #[cfg_attr(
280        all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9)))),
281        doc = "```rust"
282    )]
283    /// use pyo3::prelude::*;
284    /// use pyo3::types::{PyWeakref, PyWeakrefProxy};
285    ///
286    /// #[pyclass(weakref)]
287    /// struct Foo { /* fields omitted */ }
288    ///
289    /// fn parse_data(reference: Borrowed<'_, '_, PyWeakref>) -> PyResult<String> {
290    ///     if let Some(object) = reference.upgrade() {
291    ///         Ok(format!("The object '{}' refered by this reference still exists.", object.getattr("__class__")?.getattr("__qualname__")?))
292    ///     } else {
293    ///         Ok("The object, which this reference refered to, no longer exists".to_owned())
294    ///     }
295    /// }
296    ///
297    /// # fn main() -> PyResult<()> {
298    /// Python::with_gil(|py| {
299    ///     let data = Bound::new(py, Foo{})?;
300    ///     let proxy = PyWeakrefProxy::new_bound(&data)?; // Retrieve this as an PyMethods argument.
301    ///     let reference = proxy.downcast::<PyWeakref>()?;
302    ///
303    ///     assert_eq!(
304    ///         parse_data(reference.as_borrowed())?,
305    ///         "The object 'Foo' refered by this reference still exists."
306    ///     );
307    ///
308    ///     drop(data);
309    ///
310    ///     assert_eq!(
311    ///         parse_data(reference.as_borrowed())?,
312    ///         "The object, which this reference refered to, no longer exists"
313    ///     );
314    ///
315    ///     Ok(())
316    /// })
317    /// # }
318    /// ```
319    ///
320    /// # Panics
321    /// This function panics is the current object is invalid.
322    /// If used propperly this is never the case. (NonNull and actually a weakref type)
323    ///
324    /// [`PyWeakref_GetObject`]: https://docs.python.org/3/c-api/weakref.html#c.PyWeakref_GetObject
325    pub fn upgrade(&self) -> Option<&'_ PyAny> {
326        self.as_borrowed().upgrade().map(Bound::into_gil_ref)
327    }
328
329    /// Retrieve to a object pointed to by the weakref.
330    ///
331    /// This function returns `&'py PyAny`, which is either the object if it still exists, otherwise it will refer to [`PyNone`](crate::types::PyNone).
332    ///
333    /// This function gets the optional target of this [`PyWeakref`] (Any Python `weakref` weakreference).
334    /// It produces similair results as using [`PyWeakref_GetObject`] in the C api or retrieving the Object from Python.
335    ///
336    /// # Example
337    #[cfg_attr(
338        not(all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9))))),
339        doc = "```rust,ignore"
340    )]
341    #[cfg_attr(
342        all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9)))),
343        doc = "```rust"
344    )]
345    /// use pyo3::prelude::*;
346    /// use pyo3::types::{PyWeakref, PyWeakrefProxy};
347    ///
348    /// #[pyclass(weakref)]
349    /// struct Foo { /* fields omitted */ }
350    ///
351    /// fn get_class(reference: Borrowed<'_, '_, PyWeakref>) -> PyResult<String> {
352    ///     reference
353    ///         .get_object()
354    ///         .getattr("__class__")?
355    ///         .repr()
356    ///         .map(|repr| repr.to_string())
357    /// }
358    ///
359    /// # fn main() -> PyResult<()> {
360    /// Python::with_gil(|py| {
361    ///     let object = Bound::new(py, Foo{})?;
362    ///     let proxy = PyWeakrefProxy::new_bound(&object)?; // Retrieve this as an PyMethods argument.
363    ///     let reference = proxy.downcast::<PyWeakref>()?;
364    ///
365    ///     assert_eq!(
366    ///         get_class(reference.as_borrowed())?,
367    ///         "<class 'builtins.Foo'>"
368    ///     );
369    ///
370    ///     drop(object);
371    ///
372    ///     assert_eq!(get_class(reference.as_borrowed())?, "<class 'NoneType'>");
373    ///
374    ///     Ok(())
375    /// })
376    /// # }
377    /// ```
378    ///
379    /// # Panics
380    /// This function panics is the current object is invalid.
381    /// If used propperly this is never the case. (NonNull and actually a weakref type)
382    ///
383    /// [`PyWeakref_GetObject`]: https://docs.python.org/3/c-api/weakref.html#c.PyWeakref_GetObject
384    pub fn get_object(&self) -> &'_ PyAny {
385        self.as_borrowed().get_object().into_gil_ref()
386    }
387}
388
389/// Implementation of functionality for [`PyWeakref`].
390///
391/// These methods are defined for the `Bound<'py, PyWeakref>` smart pointer, so to use method call
392/// syntax these methods are separated into a trait, because stable Rust does not yet support
393/// `arbitrary_self_types`.
394#[doc(alias = "PyWeakref")]
395pub trait PyWeakrefMethods<'py> {
396    /// Upgrade the weakref to a direct Bound object reference.
397    ///
398    /// It is named `upgrade` to be inline with [rust's `Weak::upgrade`](std::rc::Weak::upgrade).
399    /// In Python it would be equivalent to [`PyWeakref_GetRef`].
400    ///
401    /// # Example
402    #[cfg_attr(
403        not(all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9))))),
404        doc = "```rust,ignore"
405    )]
406    #[cfg_attr(
407        all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9)))),
408        doc = "```rust"
409    )]
410    /// use pyo3::prelude::*;
411    /// use pyo3::types::PyWeakrefReference;
412    ///
413    /// #[pyclass(weakref)]
414    /// struct Foo { /* fields omitted */ }
415    ///
416    /// #[pymethods]
417    /// impl Foo {
418    ///     fn get_data(&self) -> (&str, u32) {
419    ///         ("Dave", 10)
420    ///     }
421    /// }
422    ///
423    /// fn parse_data(reference: Borrowed<'_, '_, PyWeakrefReference>) -> PyResult<String> {
424    ///     if let Some(data_src) = reference.upgrade_as::<Foo>()? {
425    ///         let data = data_src.borrow();
426    ///         let (name, score) = data.get_data();
427    ///         Ok(format!("Processing '{}': score = {}", name, score))
428    ///     } else {
429    ///         Ok("The supplied data reference is nolonger relavent.".to_owned())
430    ///     }
431    /// }
432    ///
433    /// # fn main() -> PyResult<()> {
434    /// Python::with_gil(|py| {
435    ///     let data = Bound::new(py, Foo{})?;
436    ///     let reference = PyWeakrefReference::new_bound(&data)?;
437    ///
438    ///     assert_eq!(
439    ///         parse_data(reference.as_borrowed())?,
440    ///         "Processing 'Dave': score = 10"
441    ///     );
442    ///
443    ///     drop(data);
444    ///
445    ///     assert_eq!(
446    ///         parse_data(reference.as_borrowed())?,
447    ///         "The supplied data reference is nolonger relavent."
448    ///     );
449    ///
450    ///     Ok(())
451    /// })
452    /// # }
453    /// ```
454    ///
455    /// # Panics
456    /// This function panics is the current object is invalid.
457    /// If used propperly this is never the case. (NonNull and actually a weakref type)
458    ///
459    /// [`PyWeakref_GetRef`]: https://docs.python.org/3/c-api/weakref.html#c.PyWeakref_GetRef
460    /// [`weakref.ReferenceType`]: https://docs.python.org/3/library/weakref.html#weakref.ReferenceType
461    /// [`weakref.ref`]: https://docs.python.org/3/library/weakref.html#weakref.ref
462    fn upgrade_as<T>(&self) -> PyResult<Option<Bound<'py, T>>>
463    where
464        T: PyTypeCheck,
465    {
466        self.upgrade()
467            .map(Bound::downcast_into::<T>)
468            .transpose()
469            .map_err(Into::into)
470    }
471
472    /// Deprecated form of [`PyWeakrefMethods::upgrade_as`].
473    ///
474    /// Since PyO3 0.22.4 this leaks the borrowed reference to ensure the object is not
475    /// deallocated while in use. This is necessary to avoid possible use-after-free bugs.
476    #[deprecated(since = "0.22.4", note = "use `upgrade_as`")]
477    fn upgrade_borrowed_as<'a, T>(&'a self) -> PyResult<Option<Borrowed<'a, 'py, T>>>
478    where
479        T: PyTypeCheck,
480        'py: 'a,
481    {
482        #[allow(deprecated)]
483        match self.upgrade_borrowed() {
484            None => Ok(None),
485            Some(object) if T::type_check(&object) => {
486                Ok(Some(unsafe { object.downcast_unchecked() }))
487            }
488            Some(object) => Err(DowncastError::new(&object, T::NAME).into()),
489        }
490    }
491
492    /// Upgrade the weakref to a direct Bound object reference unchecked. The type of the recovered object is not checked before downcasting, this could lead to unexpected behavior. Use only when absolutely certain the type can be guaranteed. The `weakref` may still return `None`.
493    ///
494    /// It is named `upgrade` to be inline with [rust's `Weak::upgrade`](std::rc::Weak::upgrade).
495    /// In Python it would be equivalent to [`PyWeakref_GetRef`].
496    ///
497    /// # Safety
498    /// Callers must ensure that the type is valid or risk type confusion.
499    /// The `weakref` is still allowed to be `None`, if the referenced object has been cleaned up.
500    ///
501    /// # Example
502    #[cfg_attr(
503        not(all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9))))),
504        doc = "```rust,ignore"
505    )]
506    #[cfg_attr(
507        all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9)))),
508        doc = "```rust"
509    )]
510    /// use pyo3::prelude::*;
511    /// use pyo3::types::PyWeakrefReference;
512    ///
513    /// #[pyclass(weakref)]
514    /// struct Foo { /* fields omitted */ }
515    ///
516    /// #[pymethods]
517    /// impl Foo {
518    ///     fn get_data(&self) -> (&str, u32) {
519    ///         ("Dave", 10)
520    ///     }
521    /// }
522    ///
523    /// fn parse_data(reference: Borrowed<'_, '_, PyWeakrefReference>) -> String {
524    ///     if let Some(data_src) = unsafe { reference.upgrade_as_unchecked::<Foo>() } {
525    ///         let data = data_src.borrow();
526    ///         let (name, score) = data.get_data();
527    ///         format!("Processing '{}': score = {}", name, score)
528    ///     } else {
529    ///         "The supplied data reference is nolonger relavent.".to_owned()
530    ///     }
531    /// }
532    ///
533    /// # fn main() -> PyResult<()> {
534    /// Python::with_gil(|py| {
535    ///     let data = Bound::new(py, Foo{})?;
536    ///     let reference = PyWeakrefReference::new_bound(&data)?;
537    ///
538    ///     assert_eq!(
539    ///         parse_data(reference.as_borrowed()),
540    ///         "Processing 'Dave': score = 10"
541    ///     );
542    ///
543    ///     drop(data);
544    ///
545    ///     assert_eq!(
546    ///         parse_data(reference.as_borrowed()),
547    ///         "The supplied data reference is nolonger relavent."
548    ///     );
549    ///
550    ///     Ok(())
551    /// })
552    /// # }
553    /// ```
554    ///
555    /// # Panics
556    /// This function panics is the current object is invalid.
557    /// If used propperly this is never the case. (NonNull and actually a weakref type)
558    ///
559    /// [`PyWeakref_GetRef`]: https://docs.python.org/3/c-api/weakref.html#c.PyWeakref_GetRef
560    /// [`weakref.ReferenceType`]: https://docs.python.org/3/library/weakref.html#weakref.ReferenceType
561    /// [`weakref.ref`]: https://docs.python.org/3/library/weakref.html#weakref.ref
562    unsafe fn upgrade_as_unchecked<T>(&self) -> Option<Bound<'py, T>> {
563        Some(self.upgrade()?.downcast_into_unchecked())
564    }
565
566    /// Deprecated form of [`PyWeakrefMethods::upgrade_as_unchecked`].
567    ///
568    /// Since PyO3 0.22.4 this leaks the borrowed reference to ensure the object is not
569    /// deallocated while in use. This is necessary to avoid possible use-after-free bugs.
570    ///
571    /// # Safety
572    /// Callers must ensure that the type is valid or risk type confusion.
573    /// The `weakref` is still allowed to be `None`, if the referenced object has been cleaned up.
574    #[deprecated(since = "0.22.4", note = "use `upgrade_as_uncheked`")]
575    unsafe fn upgrade_borrowed_as_unchecked<'a, T>(&'a self) -> Option<Borrowed<'a, 'py, T>>
576    where
577        'py: 'a,
578    {
579        #[allow(deprecated)]
580        Some(self.upgrade_borrowed()?.downcast_unchecked())
581    }
582
583    /// Upgrade the weakref to a exact direct Bound object reference.
584    ///
585    /// It is named `upgrade` to be inline with [rust's `Weak::upgrade`](std::rc::Weak::upgrade).
586    /// In Python it would be equivalent to [`PyWeakref_GetRef`].
587    ///
588    /// # Example
589    #[cfg_attr(
590        not(all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9))))),
591        doc = "```rust,ignore"
592    )]
593    #[cfg_attr(
594        all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9)))),
595        doc = "```rust"
596    )]
597    /// use pyo3::prelude::*;
598    /// use pyo3::types::PyWeakrefReference;
599    ///
600    /// #[pyclass(weakref)]
601    /// struct Foo { /* fields omitted */ }
602    ///
603    /// #[pymethods]
604    /// impl Foo {
605    ///     fn get_data(&self) -> (&str, u32) {
606    ///         ("Dave", 10)
607    ///     }
608    /// }
609    ///
610    /// fn parse_data(reference: Borrowed<'_, '_, PyWeakrefReference>) -> PyResult<String> {
611    ///     if let Some(data_src) = reference.upgrade_as_exact::<Foo>()? {
612    ///         let data = data_src.borrow();
613    ///         let (name, score) = data.get_data();
614    ///         Ok(format!("Processing '{}': score = {}", name, score))
615    ///     } else {
616    ///         Ok("The supplied data reference is nolonger relavent.".to_owned())
617    ///     }
618    /// }
619    ///
620    /// # fn main() -> PyResult<()> {
621    /// Python::with_gil(|py| {
622    ///     let data = Bound::new(py, Foo{})?;
623    ///     let reference = PyWeakrefReference::new_bound(&data)?;
624    ///
625    ///     assert_eq!(
626    ///         parse_data(reference.as_borrowed())?,
627    ///         "Processing 'Dave': score = 10"
628    ///     );
629    ///
630    ///     drop(data);
631    ///
632    ///     assert_eq!(
633    ///         parse_data(reference.as_borrowed())?,
634    ///         "The supplied data reference is nolonger relavent."
635    ///     );
636    ///
637    ///     Ok(())
638    /// })
639    /// # }
640    /// ```
641    ///
642    /// # Panics
643    /// This function panics is the current object is invalid.
644    /// If used propperly this is never the case. (NonNull and actually a weakref type)
645    ///
646    /// [`PyWeakref_GetRef`]: https://docs.python.org/3/c-api/weakref.html#c.PyWeakref_GetRef
647    /// [`weakref.ReferenceType`]: https://docs.python.org/3/library/weakref.html#weakref.ReferenceType
648    /// [`weakref.ref`]: https://docs.python.org/3/library/weakref.html#weakref.ref
649    fn upgrade_as_exact<T>(&self) -> PyResult<Option<Bound<'py, T>>>
650    where
651        T: PyTypeInfo,
652    {
653        self.upgrade()
654            .map(Bound::downcast_into_exact)
655            .transpose()
656            .map_err(Into::into)
657    }
658
659    /// Deprecated form of [`PyWeakrefMethods::upgrade_as_exact`].
660    ///
661    /// Since PyO3 0.22.4 this leaks the borrowed reference to ensure the object is not
662    /// deallocated while in use. This is necessary to avoid possible use-after-free bugs.
663    #[deprecated(since = "0.22.4", note = "use `upgrade_as_exact`")]
664    fn upgrade_borrowed_as_exact<'a, T>(&'a self) -> PyResult<Option<Borrowed<'a, 'py, T>>>
665    where
666        T: PyTypeInfo,
667        'py: 'a,
668    {
669        #[allow(deprecated)]
670        match self.upgrade_borrowed() {
671            None => Ok(None),
672            Some(object) if object.is_exact_instance_of::<T>() => {
673                Ok(Some(unsafe { object.downcast_unchecked() }))
674            }
675            Some(object) => Err(DowncastError::new(&object, T::NAME).into()),
676        }
677    }
678
679    /// Upgrade the weakref to a Bound [`PyAny`] reference to the target object if possible.
680    ///
681    /// It is named `upgrade` to be inline with [rust's `Weak::upgrade`](std::rc::Weak::upgrade).
682    /// This function returns `Some(Bound<'py, PyAny>)` if the reference still exists, otherwise `None` will be returned.
683    ///
684    /// This function gets the optional target of this [`weakref.ReferenceType`] (result of calling [`weakref.ref`]).
685    /// It produces similar results to using [`PyWeakref_GetRef`] in the C api.
686    ///
687    /// # Example
688    #[cfg_attr(
689        not(all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9))))),
690        doc = "```rust,ignore"
691    )]
692    #[cfg_attr(
693        all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9)))),
694        doc = "```rust"
695    )]
696    /// use pyo3::prelude::*;
697    /// use pyo3::types::PyWeakrefReference;
698    ///
699    /// #[pyclass(weakref)]
700    /// struct Foo { /* fields omitted */ }
701    ///
702    /// fn parse_data(reference: Borrowed<'_, '_, PyWeakrefReference>) -> PyResult<String> {
703    ///     if let Some(object) = reference.upgrade() {
704    ///         Ok(format!("The object '{}' refered by this reference still exists.", object.getattr("__class__")?.getattr("__qualname__")?))
705    ///     } else {
706    ///         Ok("The object, which this reference refered to, no longer exists".to_owned())
707    ///     }
708    /// }
709    ///
710    /// # fn main() -> PyResult<()> {
711    /// Python::with_gil(|py| {
712    ///     let data = Bound::new(py, Foo{})?;
713    ///     let reference = PyWeakrefReference::new_bound(&data)?;
714    ///
715    ///     assert_eq!(
716    ///         parse_data(reference.as_borrowed())?,
717    ///         "The object 'Foo' refered by this reference still exists."
718    ///     );
719    ///
720    ///     drop(data);
721    ///
722    ///     assert_eq!(
723    ///         parse_data(reference.as_borrowed())?,
724    ///         "The object, which this reference refered to, no longer exists"
725    ///     );
726    ///
727    ///     Ok(())
728    /// })
729    /// # }
730    /// ```
731    ///
732    /// # Panics
733    /// This function panics is the current object is invalid.
734    /// If used propperly this is never the case. (NonNull and actually a weakref type)
735    ///
736    /// [`PyWeakref_GetRef`]: https://docs.python.org/3/c-api/weakref.html#c.PyWeakref_GetRef
737    /// [`weakref.ReferenceType`]: https://docs.python.org/3/library/weakref.html#weakref.ReferenceType
738    /// [`weakref.ref`]: https://docs.python.org/3/library/weakref.html#weakref.ref
739    fn upgrade(&self) -> Option<Bound<'py, PyAny>> {
740        let object = self.get_object();
741
742        if object.is_none() {
743            None
744        } else {
745            Some(object)
746        }
747    }
748
749    /// Deprecated form of [`PyWeakrefMethods::upgrade`].
750    ///
751    /// Since PyO3 0.22.4 this leaks the borrowed reference to ensure the object is not
752    /// deallocated while in use. This is necessary to avoid possible use-after-free bugs.
753    #[deprecated(since = "0.22.4", note = "use `upgrade`")]
754    fn upgrade_borrowed<'a>(&'a self) -> Option<Borrowed<'a, 'py, PyAny>>
755    where
756        'py: 'a,
757    {
758        #[allow(deprecated)]
759        let object = self.get_object_borrowed();
760
761        if object.is_none() {
762            None
763        } else {
764            Some(object)
765        }
766    }
767
768    /// Retrieve to a Bound object pointed to by the weakref.
769    ///
770    /// This function returns `Bound<'py, PyAny>`, which is either the object if it still exists, otherwise it will refer to [`PyNone`](crate::types::PyNone).
771    ///
772    /// This function gets the optional target of this [`weakref.ReferenceType`] (result of calling [`weakref.ref`]).
773    /// It produces similar results to using [`PyWeakref_GetRef`] in the C api.
774    ///
775    /// # Example
776    #[cfg_attr(
777        not(all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9))))),
778        doc = "```rust,ignore"
779    )]
780    #[cfg_attr(
781        all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9)))),
782        doc = "```rust"
783    )]
784    /// use pyo3::prelude::*;
785    /// use pyo3::types::PyWeakrefReference;
786    ///
787    /// #[pyclass(weakref)]
788    /// struct Foo { /* fields omitted */ }
789    ///
790    /// fn get_class(reference: Borrowed<'_, '_, PyWeakrefReference>) -> PyResult<String> {
791    ///     reference
792    ///         .get_object()
793    ///         .getattr("__class__")?
794    ///         .repr()
795    ///         .map(|repr| repr.to_string())
796    /// }
797    ///
798    /// # fn main() -> PyResult<()> {
799    /// Python::with_gil(|py| {
800    ///     let object = Bound::new(py, Foo{})?;
801    ///     let reference = PyWeakrefReference::new_bound(&object)?;
802    ///
803    ///     assert_eq!(
804    ///         get_class(reference.as_borrowed())?,
805    ///         "<class 'builtins.Foo'>"
806    ///     );
807    ///
808    ///     drop(object);
809    ///
810    ///     assert_eq!(get_class(reference.as_borrowed())?, "<class 'NoneType'>");
811    ///
812    ///     Ok(())
813    /// })
814    /// # }
815    /// ```
816    ///
817    /// # Panics
818    /// This function panics is the current object is invalid.
819    /// If used propperly this is never the case. (NonNull and actually a weakref type)
820    ///
821    /// [`PyWeakref_GetRef`]: https://docs.python.org/3/c-api/weakref.html#c.PyWeakref_GetRef
822    /// [`weakref.ReferenceType`]: https://docs.python.org/3/library/weakref.html#weakref.ReferenceType
823    /// [`weakref.ref`]: https://docs.python.org/3/library/weakref.html#weakref.ref
824    fn get_object(&self) -> Bound<'py, PyAny> {
825        #[allow(deprecated)]
826        self.get_object_borrowed().to_owned()
827    }
828
829    /// Deprecated form of [`PyWeakrefMethods::get_object`].
830    ///
831    /// Since PyO3 0.22.4 this leaks the borrowed reference to ensure the object is not
832    /// deallocated while in use. This is necessary to avoid possible use-after-free bugs.
833    #[deprecated(since = "0.22.4", note = "use `get_object`")]
834    fn get_object_borrowed(&self) -> Borrowed<'_, 'py, PyAny>;
835}
836
837impl<'py> PyWeakrefMethods<'py> for Bound<'py, PyWeakref> {
838    fn get_object(&self) -> Bound<'py, PyAny> {
839        let mut obj: *mut ffi::PyObject = std::ptr::null_mut();
840        match unsafe { ffi::compat::PyWeakref_GetRef(self.as_ptr(), &mut obj) } {
841            std::os::raw::c_int::MIN..=-1 => panic!("The 'weakref' weak reference instance should be valid (non-null and actually a weakref reference)"),
842            0 => PyNone::get_bound(self.py()).to_owned().into_any(),
843            1..=std::os::raw::c_int::MAX => unsafe { obj.assume_owned(self.py()) },
844        }
845    }
846
847    fn get_object_borrowed(&self) -> Borrowed<'_, 'py, PyAny> {
848        // XXX: this deliberately leaks a reference, but this is a necessary safety measure
849        // to ensure that the object is not deallocated while we are using it.
850        unsafe {
851            self.get_object()
852                .into_ptr()
853                .assume_borrowed_unchecked(self.py())
854        }
855    }
856}
857
858#[cfg(test)]
859mod tests {
860    use crate::types::any::{PyAny, PyAnyMethods};
861    use crate::types::weakref::{PyWeakref, PyWeakrefMethods, PyWeakrefProxy, PyWeakrefReference};
862    use crate::{Bound, PyResult, Python};
863
864    fn new_reference<'py>(object: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyWeakref>> {
865        let reference = PyWeakrefReference::new_bound(object)?;
866        reference.into_any().downcast_into().map_err(Into::into)
867    }
868
869    fn new_proxy<'py>(object: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyWeakref>> {
870        let reference = PyWeakrefProxy::new_bound(object)?;
871        reference.into_any().downcast_into().map_err(Into::into)
872    }
873
874    mod python_class {
875        use super::*;
876        use crate::{py_result_ext::PyResultExt, types::PyType};
877
878        fn get_type(py: Python<'_>) -> PyResult<Bound<'_, PyType>> {
879            py.run_bound("class A:\n    pass\n", None, None)?;
880            py.eval_bound("A", None, None).downcast_into::<PyType>()
881        }
882
883        #[test]
884        fn test_weakref_upgrade_as() -> PyResult<()> {
885            fn inner(
886                create_reference: impl for<'py> FnOnce(
887                    &Bound<'py, PyAny>,
888                )
889                    -> PyResult<Bound<'py, PyWeakref>>,
890            ) -> PyResult<()> {
891                Python::with_gil(|py| {
892                    let class = get_type(py)?;
893                    let object = class.call0()?;
894                    let reference = create_reference(&object)?;
895
896                    {
897                        // This test is a bit weird but ok.
898                        let obj = reference.upgrade_as::<PyAny>();
899
900                        assert!(obj.is_ok());
901                        let obj = obj.unwrap();
902
903                        assert!(obj.is_some());
904                        assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr()
905                            && obj.is_exact_instance(&class)));
906                    }
907
908                    drop(object);
909
910                    {
911                        // This test is a bit weird but ok.
912                        let obj = reference.upgrade_as::<PyAny>();
913
914                        assert!(obj.is_ok());
915                        let obj = obj.unwrap();
916
917                        assert!(obj.is_none());
918                    }
919
920                    Ok(())
921                })
922            }
923
924            inner(new_reference)?;
925            inner(new_proxy)
926        }
927
928        #[test]
929        fn test_weakref_upgrade_as_unchecked() -> PyResult<()> {
930            fn inner(
931                create_reference: impl for<'py> FnOnce(
932                    &Bound<'py, PyAny>,
933                )
934                    -> PyResult<Bound<'py, PyWeakref>>,
935            ) -> PyResult<()> {
936                Python::with_gil(|py| {
937                    let class = get_type(py)?;
938                    let object = class.call0()?;
939                    let reference = create_reference(&object)?;
940
941                    {
942                        // This test is a bit weird but ok.
943                        let obj = unsafe { reference.upgrade_as_unchecked::<PyAny>() };
944
945                        assert!(obj.is_some());
946                        assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr()
947                            && obj.is_exact_instance(&class)));
948                    }
949
950                    drop(object);
951
952                    {
953                        // This test is a bit weird but ok.
954                        let obj = unsafe { reference.upgrade_as_unchecked::<PyAny>() };
955
956                        assert!(obj.is_none());
957                    }
958
959                    Ok(())
960                })
961            }
962
963            inner(new_reference)?;
964            inner(new_proxy)
965        }
966
967        #[test]
968        fn test_weakref_upgrade() -> PyResult<()> {
969            fn inner(
970                create_reference: impl for<'py> FnOnce(
971                    &Bound<'py, PyAny>,
972                )
973                    -> PyResult<Bound<'py, PyWeakref>>,
974                call_retrievable: bool,
975            ) -> PyResult<()> {
976                let not_call_retrievable = !call_retrievable;
977
978                Python::with_gil(|py| {
979                    let class = get_type(py)?;
980                    let object = class.call0()?;
981                    let reference = create_reference(&object)?;
982
983                    assert!(not_call_retrievable || reference.call0()?.is(&object));
984                    assert!(reference.upgrade().is_some());
985                    assert!(reference.upgrade().map_or(false, |obj| obj.is(&object)));
986
987                    drop(object);
988
989                    assert!(not_call_retrievable || reference.call0()?.is_none());
990                    assert!(reference.upgrade().is_none());
991
992                    Ok(())
993                })
994            }
995
996            inner(new_reference, true)?;
997            inner(new_proxy, false)
998        }
999
1000        #[test]
1001        fn test_weakref_get_object() -> PyResult<()> {
1002            fn inner(
1003                create_reference: impl for<'py> FnOnce(
1004                    &Bound<'py, PyAny>,
1005                )
1006                    -> PyResult<Bound<'py, PyWeakref>>,
1007                call_retrievable: bool,
1008            ) -> PyResult<()> {
1009                let not_call_retrievable = !call_retrievable;
1010
1011                Python::with_gil(|py| {
1012                    let class = get_type(py)?;
1013                    let object = class.call0()?;
1014                    let reference = create_reference(&object)?;
1015
1016                    assert!(not_call_retrievable || reference.call0()?.is(&object));
1017                    assert!(reference.get_object().is(&object));
1018
1019                    drop(object);
1020
1021                    assert!(not_call_retrievable || reference.call0()?.is(&reference.get_object()));
1022                    assert!(not_call_retrievable || reference.call0()?.is_none());
1023                    assert!(reference.get_object().is_none());
1024
1025                    Ok(())
1026                })
1027            }
1028
1029            inner(new_reference, true)?;
1030            inner(new_proxy, false)
1031        }
1032    }
1033
1034    // under 'abi3-py37' and 'abi3-py38' PyClass cannot be weakreferencable.
1035    #[cfg(all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9)))))]
1036    mod pyo3_pyclass {
1037        use super::*;
1038        use crate::{pyclass, Py};
1039
1040        #[pyclass(weakref, crate = "crate")]
1041        struct WeakrefablePyClass {}
1042
1043        #[test]
1044        fn test_weakref_upgrade_as() -> PyResult<()> {
1045            fn inner(
1046                create_reference: impl for<'py> FnOnce(
1047                    &Bound<'py, PyAny>,
1048                )
1049                    -> PyResult<Bound<'py, PyWeakref>>,
1050            ) -> PyResult<()> {
1051                Python::with_gil(|py| {
1052                    let object = Py::new(py, WeakrefablePyClass {})?;
1053                    let reference = create_reference(object.bind(py))?;
1054
1055                    {
1056                        let obj = reference.upgrade_as::<WeakrefablePyClass>();
1057
1058                        assert!(obj.is_ok());
1059                        let obj = obj.unwrap();
1060
1061                        assert!(obj.is_some());
1062                        assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr()));
1063                    }
1064
1065                    drop(object);
1066
1067                    {
1068                        let obj = reference.upgrade_as::<WeakrefablePyClass>();
1069
1070                        assert!(obj.is_ok());
1071                        let obj = obj.unwrap();
1072
1073                        assert!(obj.is_none());
1074                    }
1075
1076                    Ok(())
1077                })
1078            }
1079
1080            inner(new_reference)?;
1081            inner(new_proxy)
1082        }
1083
1084        #[test]
1085        fn test_weakref_upgrade_as_unchecked() -> PyResult<()> {
1086            fn inner(
1087                create_reference: impl for<'py> FnOnce(
1088                    &Bound<'py, PyAny>,
1089                )
1090                    -> PyResult<Bound<'py, PyWeakref>>,
1091            ) -> PyResult<()> {
1092                Python::with_gil(|py| {
1093                    let object = Py::new(py, WeakrefablePyClass {})?;
1094                    let reference = create_reference(object.bind(py))?;
1095
1096                    {
1097                        let obj = unsafe { reference.upgrade_as_unchecked::<WeakrefablePyClass>() };
1098
1099                        assert!(obj.is_some());
1100                        assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr()));
1101                    }
1102
1103                    drop(object);
1104
1105                    {
1106                        let obj = unsafe { reference.upgrade_as_unchecked::<WeakrefablePyClass>() };
1107
1108                        assert!(obj.is_none());
1109                    }
1110
1111                    Ok(())
1112                })
1113            }
1114
1115            inner(new_reference)?;
1116            inner(new_proxy)
1117        }
1118
1119        #[test]
1120        fn test_weakref_upgrade() -> PyResult<()> {
1121            fn inner(
1122                create_reference: impl for<'py> FnOnce(
1123                    &Bound<'py, PyAny>,
1124                )
1125                    -> PyResult<Bound<'py, PyWeakref>>,
1126                call_retrievable: bool,
1127            ) -> PyResult<()> {
1128                let not_call_retrievable = !call_retrievable;
1129
1130                Python::with_gil(|py| {
1131                    let object = Py::new(py, WeakrefablePyClass {})?;
1132                    let reference = create_reference(object.bind(py))?;
1133
1134                    assert!(not_call_retrievable || reference.call0()?.is(&object));
1135                    assert!(reference.upgrade().is_some());
1136                    assert!(reference.upgrade().map_or(false, |obj| obj.is(&object)));
1137
1138                    drop(object);
1139
1140                    assert!(not_call_retrievable || reference.call0()?.is_none());
1141                    assert!(reference.upgrade().is_none());
1142
1143                    Ok(())
1144                })
1145            }
1146
1147            inner(new_reference, true)?;
1148            inner(new_proxy, false)
1149        }
1150
1151        #[test]
1152        fn test_weakref_get_object() -> PyResult<()> {
1153            fn inner(
1154                create_reference: impl for<'py> FnOnce(
1155                    &Bound<'py, PyAny>,
1156                )
1157                    -> PyResult<Bound<'py, PyWeakref>>,
1158                call_retrievable: bool,
1159            ) -> PyResult<()> {
1160                let not_call_retrievable = !call_retrievable;
1161
1162                Python::with_gil(|py| {
1163                    let object = Py::new(py, WeakrefablePyClass {})?;
1164                    let reference = create_reference(object.bind(py))?;
1165
1166                    assert!(not_call_retrievable || reference.call0()?.is(&object));
1167                    assert!(reference.get_object().is(&object));
1168
1169                    drop(object);
1170
1171                    assert!(not_call_retrievable || reference.call0()?.is(&reference.get_object()));
1172                    assert!(not_call_retrievable || reference.call0()?.is_none());
1173                    assert!(reference.get_object().is_none());
1174
1175                    Ok(())
1176                })
1177            }
1178
1179            inner(new_reference, true)?;
1180            inner(new_proxy, false)
1181        }
1182    }
1183}