use crate::common::rc::{PyRc, PyWeak}; use crate::pyobject::{IdProtocol, PyObject, PyObjectPayload, TypeProtocol}; use std::borrow; use std::fmt; use std::ops::Deref; pub struct PyObjectRc { inner: PyRc>, } pub struct PyObjectWeak { inner: PyWeak>, } // invariant: must never be constructed directly, as a &PyObjectRcB should always be // the result of PyRc>.deref() #[repr(transparent)] pub struct PyObjectRcB(PyObject); pub trait AsPyObjectPayload: PyObjectPayload { fn rc_to_pyobj(rc: PyRc>) -> PyRc>; } impl AsPyObjectPayload for T { fn rc_to_pyobj(rc: PyRc>) -> PyRc> { rc } } impl AsPyObjectPayload for dyn PyObjectPayload { fn rc_to_pyobj(rc: PyRc>) -> PyRc> { rc } } impl PyObjectRc { pub fn into_raw(this: Self) -> *const PyObject { let ptr = PyRc::as_ptr(&this.inner); std::mem::forget(this); ptr } unsafe fn into_rc(this: Self) -> PyRc> { let raw = Self::into_raw(this); PyRc::from_raw(raw) } pub fn into_ref(this: Self) -> PyObjectRc { let rc = unsafe { Self::into_rc(this) }; PyObjectRc:: { inner: T::rc_to_pyobj(rc), } } /// # Safety /// See PyRc::from_raw pub unsafe fn from_raw(ptr: *const PyObject) -> Self { Self { inner: PyRc::from_raw(ptr), } } pub fn new(value: PyObject) -> Self where T: Sized, { Self { inner: PyRc::new(value), } } pub fn strong_count(this: &Self) -> usize { PyRc::strong_count(&this.inner) } pub fn weak_count(this: &Self) -> usize { PyRc::weak_count(&this.inner) } pub fn downgrade(this: &Self) -> PyObjectWeak { PyObjectWeak { inner: PyRc::downgrade(&this.inner), } } } impl IdProtocol for PyObjectRc { fn get_id(&self) -> usize { self.inner.get_id() } } impl PyObjectWeak { pub fn upgrade(&self) -> Option> { self.inner.upgrade().map(|inner| PyObjectRc { inner }) } } impl Drop for PyObjectRc { fn drop(&mut self) { use crate::pyobject::BorrowValue; // PyObjectRc will drop the value when its count goes to 0 if PyRc::strong_count(&self.inner) != 1 { return; } // CPython-compatible drop implementation let zelf = Self::into_ref(self.clone()); if let Some(del_slot) = zelf.class().mro_find_map(|cls| cls.slots.del.load()) { crate::vm::thread::with_vm(&zelf, |vm| { if let Err(e) = del_slot(&zelf, vm) { // exception in del will be ignored but printed print!("Exception ignored in: ",); let del_method = zelf.get_class_attr("__del__").unwrap(); let repr = vm.to_repr(&del_method); match repr { Ok(v) => println!("{}", v.to_string()), Err(_) => println!("{}", del_method.class().name), } let tb_module = vm.import("traceback", &[], 0).unwrap(); // TODO: set exc traceback let print_stack = vm.get_attribute(tb_module, "print_stack").unwrap(); vm.invoke(&print_stack, vec![]).unwrap(); if let Ok(repr) = vm.to_repr(e.as_object()) { println!("{}", repr.borrow_value()); } } }); } let _ = unsafe { PyObjectRc::::into_rc(zelf) }; debug_assert!(PyRc::strong_count(&self.inner) == 1); // make sure to keep same state } } impl Deref for PyObjectRc { type Target = PyObjectRcB; #[inline] fn deref(&self) -> &Self::Target { unsafe { &*(self.inner.deref() as *const PyObject as *const PyObjectRcB) } } } impl Deref for PyObjectRcB { type Target = PyObject; #[inline] fn deref(&self) -> &PyObject { &self.0 } } impl ToOwned for PyObjectRcB { type Owned = PyObjectRc; fn to_owned(&self) -> PyObjectRc { let x = unsafe { PyObjectRc::from_raw(&self.0) }; std::mem::forget(x.clone()); x } } impl Clone for PyObjectRc { fn clone(&self) -> Self { PyObjectRc { inner: self.inner.clone(), } } } impl fmt::Display for PyObjectRc where PyObject: fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.inner.fmt(f) } } impl fmt::Debug for PyObjectRc where PyObject: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.inner.fmt(f) } } impl fmt::Pointer for PyObjectRc where PyObject: fmt::Pointer, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.inner.fmt(f) } } impl borrow::Borrow> for PyObjectRc { fn borrow(&self) -> &PyObjectRcB { self } } impl borrow::Borrow for PyObjectRc where PyRc>: borrow::Borrow, { fn borrow(&self) -> &T { self.inner.borrow() } } impl AsRef for PyObjectRc where PyRc>: AsRef, { fn as_ref(&self) -> &T { self.inner.as_ref() } } impl Clone for PyObjectWeak { fn clone(&self) -> Self { PyObjectWeak { inner: self.inner.clone(), } } } impl fmt::Debug for PyObjectWeak where PyObject: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.inner.fmt(f) } }