1use crate::err::PyResult;
2use crate::ffi_ptr_ext::FfiPtrExt;
3use crate::py_result_ext::PyResultExt;
4use crate::type_object::PyTypeCheck;
5use crate::types::any::PyAny;
6use crate::{ffi, Borrowed, Bound, BoundObject, IntoPyObject, IntoPyObjectExt};
7
8use super::PyWeakrefMethods;
9
10#[repr(transparent)]
15pub struct PyWeakrefProxy(PyAny);
16
17pyobject_native_type_named!(PyWeakrefProxy);
18
19impl PyTypeCheck for PyWeakrefProxy {
24 const NAME: &'static str = "weakref.ProxyTypes";
25
26 fn type_check(object: &Bound<'_, PyAny>) -> bool {
27 unsafe { ffi::PyWeakref_CheckProxy(object.as_ptr()) > 0 }
28 }
29}
30
31impl PyWeakrefProxy {
33 #[cfg_attr(
39 not(all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9))))),
40 doc = "```rust,ignore"
41 )]
42 #[cfg_attr(
43 all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9)))),
44 doc = "```rust"
45 )]
46 #[inline]
73 pub fn new<'py>(object: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyWeakrefProxy>> {
74 unsafe {
75 Bound::from_owned_ptr_or_err(
76 object.py(),
77 ffi::PyWeakref_NewProxy(object.as_ptr(), ffi::Py_None()),
78 )
79 .downcast_into_unchecked()
80 }
81 }
82
83 #[cfg_attr(
89 not(all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9))))),
90 doc = "```rust,ignore"
91 )]
92 #[cfg_attr(
93 all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9)))),
94 doc = "```rust"
95 )]
96 #[inline]
139 pub fn new_with<'py, C>(
140 object: &Bound<'py, PyAny>,
141 callback: C,
142 ) -> PyResult<Bound<'py, PyWeakrefProxy>>
143 where
144 C: IntoPyObject<'py>,
145 {
146 fn inner<'py>(
147 object: &Bound<'py, PyAny>,
148 callback: Borrowed<'_, 'py, PyAny>,
149 ) -> PyResult<Bound<'py, PyWeakrefProxy>> {
150 unsafe {
151 Bound::from_owned_ptr_or_err(
152 object.py(),
153 ffi::PyWeakref_NewProxy(object.as_ptr(), callback.as_ptr()),
154 )
155 .downcast_into_unchecked()
156 }
157 }
158
159 let py = object.py();
160 inner(
161 object,
162 callback
163 .into_pyobject_or_pyerr(py)?
164 .into_any()
165 .as_borrowed(),
166 )
167 }
168}
169
170impl<'py> PyWeakrefMethods<'py> for Bound<'py, PyWeakrefProxy> {
171 fn upgrade(&self) -> Option<Bound<'py, PyAny>> {
172 let mut obj: *mut ffi::PyObject = std::ptr::null_mut();
173 match unsafe { ffi::compat::PyWeakref_GetRef(self.as_ptr(), &mut obj) } {
174 std::os::raw::c_int::MIN..=-1 => panic!("The 'weakref.ProxyType' (or `weakref.CallableProxyType`) instance should be valid (non-null and actually a weakref reference)"),
175 0 => None,
176 1..=std::os::raw::c_int::MAX => Some(unsafe { obj.assume_owned_unchecked(self.py()) }),
177 }
178 }
179}
180
181#[cfg(test)]
182mod tests {
183 use crate::exceptions::{PyAttributeError, PyReferenceError, PyTypeError};
184 use crate::types::any::{PyAny, PyAnyMethods};
185 use crate::types::weakref::{PyWeakrefMethods, PyWeakrefProxy};
186 use crate::{Bound, PyResult, Python};
187
188 #[cfg(all(Py_3_13, not(Py_LIMITED_API)))]
189 const DEADREF_FIX: Option<&str> = None;
190 #[cfg(all(not(Py_3_13), not(Py_LIMITED_API)))]
191 const DEADREF_FIX: Option<&str> = Some("NoneType");
192
193 #[cfg(not(Py_LIMITED_API))]
194 fn check_repr(
195 reference: &Bound<'_, PyWeakrefProxy>,
196 object: &Bound<'_, PyAny>,
197 class: Option<&str>,
198 ) -> PyResult<()> {
199 let repr = reference.repr()?.to_string();
200
201 #[cfg(Py_3_13)]
202 let (first_part, second_part) = repr.split_once(';').unwrap();
203 #[cfg(not(Py_3_13))]
204 let (first_part, second_part) = repr.split_once(" to ").unwrap();
205
206 {
207 let (msg, addr) = first_part.split_once("0x").unwrap();
208
209 assert_eq!(msg, "<weakproxy at ");
210 assert!(addr
211 .to_lowercase()
212 .contains(format!("{:x?}", reference.as_ptr()).split_at(2).1));
213 }
214
215 if let Some(class) = class.or(DEADREF_FIX) {
216 let (msg, addr) = second_part.split_once("0x").unwrap();
217
218 #[cfg(Py_3_13)]
220 assert!(msg.starts_with(" to '"));
221 assert!(msg.contains(class));
222 assert!(msg.ends_with(" at "));
223
224 assert!(addr
225 .to_lowercase()
226 .contains(format!("{:x?}", object.as_ptr()).split_at(2).1));
227 } else {
228 assert!(second_part.contains("dead"));
229 }
230
231 Ok(())
232 }
233
234 mod proxy {
235 use super::*;
236
237 #[cfg(all(not(Py_LIMITED_API), Py_3_10))]
238 const CLASS_NAME: &str = "'weakref.ProxyType'";
239 #[cfg(all(not(Py_LIMITED_API), not(Py_3_10)))]
240 const CLASS_NAME: &str = "'weakproxy'";
241
242 mod python_class {
243 use super::*;
244 use crate::ffi;
245 use crate::{py_result_ext::PyResultExt, types::PyDict, types::PyType};
246
247 fn get_type(py: Python<'_>) -> PyResult<Bound<'_, PyType>> {
248 let globals = PyDict::new(py);
249 py.run(ffi::c_str!("class A:\n pass\n"), Some(&globals), None)?;
250 py.eval(ffi::c_str!("A"), Some(&globals), None)
251 .downcast_into::<PyType>()
252 }
253
254 #[test]
255 fn test_weakref_proxy_behavior() -> PyResult<()> {
256 Python::with_gil(|py| {
257 let class = get_type(py)?;
258 let object = class.call0()?;
259 let reference = PyWeakrefProxy::new(&object)?;
260
261 assert!(!reference.is(&object));
262 assert!(reference.upgrade().unwrap().is(&object));
263
264 #[cfg(not(Py_LIMITED_API))]
265 assert_eq!(
266 reference.get_type().to_string(),
267 format!("<class {}>", CLASS_NAME)
268 );
269
270 assert_eq!(reference.getattr("__class__")?.to_string(), "<class 'A'>");
271 #[cfg(not(Py_LIMITED_API))]
272 check_repr(&reference, &object, Some("A"))?;
273
274 assert!(reference
275 .getattr("__callback__")
276 .err()
277 .map_or(false, |err| err.is_instance_of::<PyAttributeError>(py)));
278
279 assert!(reference.call0().err().map_or(false, |err| {
280 let result = err.is_instance_of::<PyTypeError>(py);
281 #[cfg(not(Py_LIMITED_API))]
282 let result = result
283 & (err.value(py).to_string()
284 == format!("{} object is not callable", CLASS_NAME));
285 result
286 }));
287
288 drop(object);
289
290 assert!(reference.upgrade().is_none());
291 assert!(reference
292 .getattr("__class__")
293 .err()
294 .map_or(false, |err| err.is_instance_of::<PyReferenceError>(py)));
295 #[cfg(not(Py_LIMITED_API))]
296 check_repr(&reference, py.None().bind(py), None)?;
297
298 assert!(reference
299 .getattr("__callback__")
300 .err()
301 .map_or(false, |err| err.is_instance_of::<PyReferenceError>(py)));
302
303 assert!(reference.call0().err().map_or(false, |err| {
304 let result = err.is_instance_of::<PyTypeError>(py);
305 #[cfg(not(Py_LIMITED_API))]
306 let result = result
307 & (err.value(py).to_string()
308 == format!("{} object is not callable", CLASS_NAME));
309 result
310 }));
311
312 Ok(())
313 })
314 }
315
316 #[test]
317 fn test_weakref_upgrade_as() -> PyResult<()> {
318 Python::with_gil(|py| {
319 let class = get_type(py)?;
320 let object = class.call0()?;
321 let reference = PyWeakrefProxy::new(&object)?;
322
323 {
324 let obj = reference.upgrade_as::<PyAny>();
326
327 assert!(obj.is_ok());
328 let obj = obj.unwrap();
329
330 assert!(obj.is_some());
331 assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr()
332 && obj.is_exact_instance(&class)));
333 }
334
335 drop(object);
336
337 {
338 let obj = reference.upgrade_as::<PyAny>();
340
341 assert!(obj.is_ok());
342 let obj = obj.unwrap();
343
344 assert!(obj.is_none());
345 }
346
347 Ok(())
348 })
349 }
350
351 #[test]
352 fn test_weakref_upgrade_as_unchecked() -> PyResult<()> {
353 Python::with_gil(|py| {
354 let class = get_type(py)?;
355 let object = class.call0()?;
356 let reference = PyWeakrefProxy::new(&object)?;
357
358 {
359 let obj = unsafe { reference.upgrade_as_unchecked::<PyAny>() };
361
362 assert!(obj.is_some());
363 assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr()
364 && obj.is_exact_instance(&class)));
365 }
366
367 drop(object);
368
369 {
370 let obj = unsafe { reference.upgrade_as_unchecked::<PyAny>() };
372
373 assert!(obj.is_none());
374 }
375
376 Ok(())
377 })
378 }
379
380 #[test]
381 fn test_weakref_upgrade() -> PyResult<()> {
382 Python::with_gil(|py| {
383 let class = get_type(py)?;
384 let object = class.call0()?;
385 let reference = PyWeakrefProxy::new(&object)?;
386
387 assert!(reference.upgrade().is_some());
388 assert!(reference.upgrade().map_or(false, |obj| obj.is(&object)));
389
390 drop(object);
391
392 assert!(reference.upgrade().is_none());
393
394 Ok(())
395 })
396 }
397
398 #[test]
399 fn test_weakref_get_object() -> PyResult<()> {
400 Python::with_gil(|py| {
401 let class = get_type(py)?;
402 let object = class.call0()?;
403 let reference = PyWeakrefProxy::new(&object)?;
404
405 assert!(reference.upgrade().unwrap().is(&object));
406
407 drop(object);
408
409 assert!(reference.upgrade().is_none());
410
411 Ok(())
412 })
413 }
414 }
415
416 #[cfg(all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9)))))]
418 mod pyo3_pyclass {
419 use super::*;
420 use crate::{pyclass, Py};
421
422 #[pyclass(weakref, crate = "crate")]
423 struct WeakrefablePyClass {}
424
425 #[test]
426 fn test_weakref_proxy_behavior() -> PyResult<()> {
427 Python::with_gil(|py| {
428 let object: Bound<'_, WeakrefablePyClass> =
429 Bound::new(py, WeakrefablePyClass {})?;
430 let reference = PyWeakrefProxy::new(&object)?;
431
432 assert!(!reference.is(&object));
433 assert!(reference.upgrade().unwrap().is(&object));
434 #[cfg(not(Py_LIMITED_API))]
435 assert_eq!(
436 reference.get_type().to_string(),
437 format!("<class {}>", CLASS_NAME)
438 );
439
440 assert_eq!(
441 reference.getattr("__class__")?.to_string(),
442 "<class 'builtins.WeakrefablePyClass'>"
443 );
444 #[cfg(not(Py_LIMITED_API))]
445 check_repr(&reference, object.as_any(), Some("WeakrefablePyClass"))?;
446
447 assert!(reference
448 .getattr("__callback__")
449 .err()
450 .map_or(false, |err| err.is_instance_of::<PyAttributeError>(py)));
451
452 assert!(reference.call0().err().map_or(false, |err| {
453 let result = err.is_instance_of::<PyTypeError>(py);
454 #[cfg(not(Py_LIMITED_API))]
455 let result = result
456 & (err.value(py).to_string()
457 == format!("{} object is not callable", CLASS_NAME));
458 result
459 }));
460
461 drop(object);
462
463 assert!(reference.upgrade().is_none());
464 assert!(reference
465 .getattr("__class__")
466 .err()
467 .map_or(false, |err| err.is_instance_of::<PyReferenceError>(py)));
468 #[cfg(not(Py_LIMITED_API))]
469 check_repr(&reference, py.None().bind(py), None)?;
470
471 assert!(reference
472 .getattr("__callback__")
473 .err()
474 .map_or(false, |err| err.is_instance_of::<PyReferenceError>(py)));
475
476 assert!(reference.call0().err().map_or(false, |err| {
477 let result = err.is_instance_of::<PyTypeError>(py);
478 #[cfg(not(Py_LIMITED_API))]
479 let result = result
480 & (err.value(py).to_string()
481 == format!("{} object is not callable", CLASS_NAME));
482 result
483 }));
484
485 Ok(())
486 })
487 }
488
489 #[test]
490 fn test_weakref_upgrade_as() -> PyResult<()> {
491 Python::with_gil(|py| {
492 let object = Py::new(py, WeakrefablePyClass {})?;
493 let reference = PyWeakrefProxy::new(object.bind(py))?;
494
495 {
496 let obj = reference.upgrade_as::<WeakrefablePyClass>();
497
498 assert!(obj.is_ok());
499 let obj = obj.unwrap();
500
501 assert!(obj.is_some());
502 assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr()));
503 }
504
505 drop(object);
506
507 {
508 let obj = reference.upgrade_as::<WeakrefablePyClass>();
509
510 assert!(obj.is_ok());
511 let obj = obj.unwrap();
512
513 assert!(obj.is_none());
514 }
515
516 Ok(())
517 })
518 }
519
520 #[test]
521 fn test_weakref_upgrade_as_unchecked() -> PyResult<()> {
522 Python::with_gil(|py| {
523 let object = Py::new(py, WeakrefablePyClass {})?;
524 let reference = PyWeakrefProxy::new(object.bind(py))?;
525
526 {
527 let obj = unsafe { reference.upgrade_as_unchecked::<WeakrefablePyClass>() };
528
529 assert!(obj.is_some());
530 assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr()));
531 }
532
533 drop(object);
534
535 {
536 let obj = unsafe { reference.upgrade_as_unchecked::<WeakrefablePyClass>() };
537
538 assert!(obj.is_none());
539 }
540
541 Ok(())
542 })
543 }
544
545 #[test]
546 fn test_weakref_upgrade() -> PyResult<()> {
547 Python::with_gil(|py| {
548 let object = Py::new(py, WeakrefablePyClass {})?;
549 let reference = PyWeakrefProxy::new(object.bind(py))?;
550
551 assert!(reference.upgrade().is_some());
552 assert!(reference.upgrade().map_or(false, |obj| obj.is(&object)));
553
554 drop(object);
555
556 assert!(reference.upgrade().is_none());
557
558 Ok(())
559 })
560 }
561 }
562 }
563
564 mod callable_proxy {
565 use super::*;
566
567 #[cfg(all(not(Py_LIMITED_API), Py_3_10))]
568 const CLASS_NAME: &str = "<class 'weakref.CallableProxyType'>";
569 #[cfg(all(not(Py_LIMITED_API), not(Py_3_10)))]
570 const CLASS_NAME: &str = "<class 'weakcallableproxy'>";
571
572 mod python_class {
573 use super::*;
574 use crate::ffi;
575 use crate::{py_result_ext::PyResultExt, types::PyDict, types::PyType};
576
577 fn get_type(py: Python<'_>) -> PyResult<Bound<'_, PyType>> {
578 let globals = PyDict::new(py);
579 py.run(
580 ffi::c_str!("class A:\n def __call__(self):\n return 'This class is callable!'\n"),
581 Some(&globals),
582 None,
583 )?;
584 py.eval(ffi::c_str!("A"), Some(&globals), None)
585 .downcast_into::<PyType>()
586 }
587
588 #[test]
589 fn test_weakref_proxy_behavior() -> PyResult<()> {
590 Python::with_gil(|py| {
591 let class = get_type(py)?;
592 let object = class.call0()?;
593 let reference = PyWeakrefProxy::new(&object)?;
594
595 assert!(!reference.is(&object));
596 assert!(reference.upgrade().unwrap().is(&object));
597 #[cfg(not(Py_LIMITED_API))]
598 assert_eq!(reference.get_type().to_string(), CLASS_NAME);
599
600 assert_eq!(reference.getattr("__class__")?.to_string(), "<class 'A'>");
601 #[cfg(not(Py_LIMITED_API))]
602 check_repr(&reference, &object, Some("A"))?;
603
604 assert!(reference
605 .getattr("__callback__")
606 .err()
607 .map_or(false, |err| err.is_instance_of::<PyAttributeError>(py)));
608
609 assert_eq!(reference.call0()?.to_string(), "This class is callable!");
610
611 drop(object);
612
613 assert!(reference.upgrade().is_none());
614 assert!(reference
615 .getattr("__class__")
616 .err()
617 .map_or(false, |err| err.is_instance_of::<PyReferenceError>(py)));
618 #[cfg(not(Py_LIMITED_API))]
619 check_repr(&reference, py.None().bind(py), None)?;
620
621 assert!(reference
622 .getattr("__callback__")
623 .err()
624 .map_or(false, |err| err.is_instance_of::<PyReferenceError>(py)));
625
626 assert!(reference
627 .call0()
628 .err()
629 .map_or(false, |err| err.is_instance_of::<PyReferenceError>(py)
630 & (err.value(py).to_string()
631 == "weakly-referenced object no longer exists")));
632
633 Ok(())
634 })
635 }
636
637 #[test]
638 fn test_weakref_upgrade_as() -> PyResult<()> {
639 Python::with_gil(|py| {
640 let class = get_type(py)?;
641 let object = class.call0()?;
642 let reference = PyWeakrefProxy::new(&object)?;
643
644 {
645 let obj = reference.upgrade_as::<PyAny>();
647
648 assert!(obj.is_ok());
649 let obj = obj.unwrap();
650
651 assert!(obj.is_some());
652 assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr()
653 && obj.is_exact_instance(&class)));
654 }
655
656 drop(object);
657
658 {
659 let obj = reference.upgrade_as::<PyAny>();
661
662 assert!(obj.is_ok());
663 let obj = obj.unwrap();
664
665 assert!(obj.is_none());
666 }
667
668 Ok(())
669 })
670 }
671
672 #[test]
673 fn test_weakref_upgrade_as_unchecked() -> PyResult<()> {
674 Python::with_gil(|py| {
675 let class = get_type(py)?;
676 let object = class.call0()?;
677 let reference = PyWeakrefProxy::new(&object)?;
678
679 {
680 let obj = unsafe { reference.upgrade_as_unchecked::<PyAny>() };
682
683 assert!(obj.is_some());
684 assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr()
685 && obj.is_exact_instance(&class)));
686 }
687
688 drop(object);
689
690 {
691 let obj = unsafe { reference.upgrade_as_unchecked::<PyAny>() };
693
694 assert!(obj.is_none());
695 }
696
697 Ok(())
698 })
699 }
700
701 #[test]
702 fn test_weakref_upgrade() -> PyResult<()> {
703 Python::with_gil(|py| {
704 let class = get_type(py)?;
705 let object = class.call0()?;
706 let reference = PyWeakrefProxy::new(&object)?;
707
708 assert!(reference.upgrade().is_some());
709 assert!(reference.upgrade().map_or(false, |obj| obj.is(&object)));
710
711 drop(object);
712
713 assert!(reference.upgrade().is_none());
714
715 Ok(())
716 })
717 }
718 }
719
720 #[cfg(all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9)))))]
722 mod pyo3_pyclass {
723 use super::*;
724 use crate::{pyclass, pymethods, Py};
725
726 #[pyclass(weakref, crate = "crate")]
727 struct WeakrefablePyClass {}
728
729 #[pymethods(crate = "crate")]
730 impl WeakrefablePyClass {
731 fn __call__(&self) -> &str {
732 "This class is callable!"
733 }
734 }
735
736 #[test]
737 fn test_weakref_proxy_behavior() -> PyResult<()> {
738 Python::with_gil(|py| {
739 let object: Bound<'_, WeakrefablePyClass> =
740 Bound::new(py, WeakrefablePyClass {})?;
741 let reference = PyWeakrefProxy::new(&object)?;
742
743 assert!(!reference.is(&object));
744 assert!(reference.upgrade().unwrap().is(&object));
745 #[cfg(not(Py_LIMITED_API))]
746 assert_eq!(reference.get_type().to_string(), CLASS_NAME);
747
748 assert_eq!(
749 reference.getattr("__class__")?.to_string(),
750 "<class 'builtins.WeakrefablePyClass'>"
751 );
752 #[cfg(not(Py_LIMITED_API))]
753 check_repr(&reference, object.as_any(), Some("WeakrefablePyClass"))?;
754
755 assert!(reference
756 .getattr("__callback__")
757 .err()
758 .map_or(false, |err| err.is_instance_of::<PyAttributeError>(py)));
759
760 assert_eq!(reference.call0()?.to_string(), "This class is callable!");
761
762 drop(object);
763
764 assert!(reference.upgrade().is_none());
765 assert!(reference
766 .getattr("__class__")
767 .err()
768 .map_or(false, |err| err.is_instance_of::<PyReferenceError>(py)));
769 #[cfg(not(Py_LIMITED_API))]
770 check_repr(&reference, py.None().bind(py), None)?;
771
772 assert!(reference
773 .getattr("__callback__")
774 .err()
775 .map_or(false, |err| err.is_instance_of::<PyReferenceError>(py)));
776
777 assert!(reference
778 .call0()
779 .err()
780 .map_or(false, |err| err.is_instance_of::<PyReferenceError>(py)
781 & (err.value(py).to_string()
782 == "weakly-referenced object no longer exists")));
783
784 Ok(())
785 })
786 }
787
788 #[test]
789 fn test_weakref_upgrade_as() -> PyResult<()> {
790 Python::with_gil(|py| {
791 let object = Py::new(py, WeakrefablePyClass {})?;
792 let reference = PyWeakrefProxy::new(object.bind(py))?;
793
794 {
795 let obj = reference.upgrade_as::<WeakrefablePyClass>();
796
797 assert!(obj.is_ok());
798 let obj = obj.unwrap();
799
800 assert!(obj.is_some());
801 assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr()));
802 }
803
804 drop(object);
805
806 {
807 let obj = reference.upgrade_as::<WeakrefablePyClass>();
808
809 assert!(obj.is_ok());
810 let obj = obj.unwrap();
811
812 assert!(obj.is_none());
813 }
814
815 Ok(())
816 })
817 }
818
819 #[test]
820 fn test_weakref_upgrade_as_unchecked() -> PyResult<()> {
821 Python::with_gil(|py| {
822 let object = Py::new(py, WeakrefablePyClass {})?;
823 let reference = PyWeakrefProxy::new(object.bind(py))?;
824
825 {
826 let obj = unsafe { reference.upgrade_as_unchecked::<WeakrefablePyClass>() };
827
828 assert!(obj.is_some());
829 assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr()));
830 }
831
832 drop(object);
833
834 {
835 let obj = unsafe { reference.upgrade_as_unchecked::<WeakrefablePyClass>() };
836
837 assert!(obj.is_none());
838 }
839
840 Ok(())
841 })
842 }
843
844 #[test]
845 fn test_weakref_upgrade() -> PyResult<()> {
846 Python::with_gil(|py| {
847 let object = Py::new(py, WeakrefablePyClass {})?;
848 let reference = PyWeakrefProxy::new(object.bind(py))?;
849
850 assert!(reference.upgrade().is_some());
851 assert!(reference.upgrade().map_or(false, |obj| obj.is(&object)));
852
853 drop(object);
854
855 assert!(reference.upgrade().is_none());
856
857 Ok(())
858 })
859 }
860 }
861 }
862}