#[repr(transparent)]pub struct PyClassGuard<'a, T: PyClass> {
ptr: NonNull<PyObject>,
marker: PhantomData<&'a Py<T>>,
}Expand description
A wrapper type for an immutably borrowed value from a PyClass.
Rust has strict aliasing rules - you can either have any number of immutable (shared) references or one mutable reference. Python’s ownership model is the complete opposite of that - any Python object can be referenced any number of times, and mutation is allowed from any reference.
PyO3 deals with these differences by employing the Interior Mutability pattern. This requires that PyO3 enforces the borrowing rules and it has two mechanisms for doing so:
- Statically it can enforce thread-safe access with the
Python<'py>token. All Rust code holding that token, or anything derived from it, can assume that they have safe access to the Python interpreter’s state. For this reason all the native Python objects can be mutated through shared references. - However, methods and functions in Rust usually do need
&mutreferences. While PyO3 can use thePython<'py>token to guarantee thread-safe access to them, it cannot statically guarantee uniqueness of&mutreferences. As such those references have to be tracked dynamically at runtime, usingPyClassGuardandPyClassGuardMutdefined in this module. This works similar to std’sRefCelltype. Especially when building for free-threaded Python it gets harder to track which thread borrows which object at any time. This can lead to method calls failing withPyBorrowError. In these cases consider usingfrozenclasses together with Rust interior mutability primitives likeMutexinstead of usingPyClassGuardMutto get mutable access.
§Examples
You can use PyClassGuard as an alternative to a &self receiver when
- you need to access the pointer of the
PyClass, or - you want to get a super class.
#[pyclass(subclass)]
struct Parent {
basename: &'static str,
}
#[pyclass(extends=Parent)]
struct Child {
name: &'static str,
}
#[pymethods]
impl Child {
#[new]
fn new() -> (Self, Parent) {
(Child { name: "Caterpillar" }, Parent { basename: "Butterfly" })
}
fn format(slf: PyClassGuard<'_, Self>) -> String {
// We can get &Self::BaseType by as_super
let basename = slf.as_super().basename;
format!("{}(base: {})", slf.name, basename)
}
}See also PyClassGuardMut and the guide for more information.
Fields§
§ptr: NonNull<PyObject>§marker: PhantomData<&'a Py<T>>Implementations§
Source§impl<'a, T: PyClass> PyClassGuard<'a, T>
impl<'a, T: PyClass> PyClassGuard<'a, T>
pub(crate) fn try_borrow(obj: &'a Py<T>) -> Result<Self, PyBorrowError>
pub(crate) fn try_borrow_from_borrowed( obj: Borrowed<'a, '_, T>, ) -> Result<Self, PyBorrowError>
fn try_from_class_object( obj: &'a <T as PyClassImpl>::Layout, ) -> Result<Self, PyBorrowError>
pub(crate) fn as_class_object(&self) -> &'a <T as PyClassImpl>::Layout
Sourcepub fn map<F, U: ?Sized>(self, f: F) -> PyClassGuardMap<'a, U, false>
pub fn map<F, U: ?Sized>(self, f: F) -> PyClassGuardMap<'a, U, false>
Consumes the PyClassGuard and returns a PyClassGuardMap for a component of the
borrowed data
§Examples
#[pyclass]
pub struct MyClass {
msg: String,
}
let obj = Bound::new(py, MyClass { msg: String::from("hello") })?;
let msg = obj.extract::<PyClassGuard<'_, MyClass>>()?.map(|c| &c.msg);
assert_eq!(&*msg, "hello");Source§impl<'a, T> PyClassGuard<'a, T>
impl<'a, T> PyClassGuard<'a, T>
Sourcepub fn as_super(&self) -> &PyClassGuard<'a, T::BaseType>
pub fn as_super(&self) -> &PyClassGuard<'a, T::BaseType>
Borrows a shared reference to PyClassGuard<T::BaseType>.
With the help of this method, you can access attributes and call methods
on the superclass without consuming the PyClassGuard<T>. This method
can also be chained to access the super-superclass (and so on).
§Examples
#[pyclass(subclass)]
struct Base {
base_name: &'static str,
}
#[pymethods]
impl Base {
fn base_name_len(&self) -> usize {
self.base_name.len()
}
}
#[pyclass(extends=Base)]
struct Sub {
sub_name: &'static str,
}
#[pymethods]
impl Sub {
#[new]
fn new() -> (Self, Base) {
(Self { sub_name: "sub_name" }, Base { base_name: "base_name" })
}
fn sub_name_len(&self) -> usize {
self.sub_name.len()
}
fn format_name_lengths(slf: PyClassGuard<'_, Self>) -> String {
format!("{} {}", slf.as_super().base_name_len(), slf.sub_name_len())
}
}Sourcepub fn into_super(self) -> PyClassGuard<'a, T::BaseType>
pub fn into_super(self) -> PyClassGuard<'a, T::BaseType>
Gets a PyClassGuard<T::BaseType>.
With the help of this method, you can get hold of instances of the super-superclass when needed.
§Examples
#[pyclass(subclass)]
struct Base1 {
name1: &'static str,
}
#[pyclass(extends=Base1, subclass)]
struct Base2 {
name2: &'static str,
}
#[pyclass(extends=Base2)]
struct Sub {
name3: &'static str,
}
#[pymethods]
impl Sub {
#[new]
fn new() -> PyClassInitializer<Self> {
PyClassInitializer::from(Base1 { name1: "base1" })
.add_subclass(Base2 { name2: "base2" })
.add_subclass(Self { name3: "sub" })
}
fn name(slf: PyClassGuard<'_, Self>) -> String {
let subname = slf.name3;
let super_ = slf.into_super();
format!("{} {} {}", super_.as_super().name1, super_.name2, subname)
}
}Trait Implementations§
Source§impl<T: PyClass> Deref for PyClassGuard<'_, T>
impl<T: PyClass> Deref for PyClassGuard<'_, T>
Source§impl<T: PyClass> Drop for PyClassGuard<'_, T>
impl<T: PyClass> Drop for PyClassGuard<'_, T>
Source§impl<'a, 'py, T: PyClass> FromPyObject<'a, 'py> for PyClassGuard<'a, T>
impl<'a, 'py, T: PyClass> FromPyObject<'a, 'py> for PyClassGuard<'a, T>
Source§const INPUT_TYPE: PyStaticExpr = T::TYPE_HINT
const INPUT_TYPE: PyStaticExpr = T::TYPE_HINT
experimental-inspect only.Source§type Error = PyClassGuardError<'a, 'py>
type Error = PyClassGuardError<'a, 'py>
Source§#[doc(hidden)]fn sequence_extractor(
_obj: Borrowed<'_, 'py, PyAny>,
_: Token,
) -> Option<impl FromPyObjectSequence<Target = Self>>
#[doc(hidden)]fn sequence_extractor(
_obj: Borrowed<'_, 'py, PyAny>,
_: Token,
) -> Option<impl FromPyObjectSequence<Target = Self>>
Vec<u8> and [u8; N],
where the bytes can be directly copied from some python objects without going through
iteration.Source§fn as_local_tz(_: Token) -> Option<Self>
fn as_local_tz(_: Token) -> Option<Self>
chrono-local only.DateTime<Tz> where Tz is
chrono::Local, which will accept “naive” datetime objects as being in the local timezone.Source§impl<'a, 'py, T: PyClass> IntoPyObject<'py> for &PyClassGuard<'a, T>
impl<'a, 'py, T: PyClass> IntoPyObject<'py> for &PyClassGuard<'a, T>
Source§const OUTPUT_TYPE: PyStaticExpr = T::TYPE_HINT
const OUTPUT_TYPE: PyStaticExpr = T::TYPE_HINT
experimental-inspect only.Source§type Error = Infallible
type Error = Infallible
Source§fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error>
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error>
Source§#[doc(hidden)]fn owned_sequence_into_pyobject<I>(
iter: I,
py: Python<'py>,
_: Token,
) -> Result<Bound<'py, PyAny>, PyErr>
#[doc(hidden)]fn owned_sequence_into_pyobject<I>(
iter: I,
py: Python<'py>,
_: Token,
) -> Result<Bound<'py, PyAny>, PyErr>
Vec<u8>, [u8; N]
and SmallVec<[u8; N]> as a sequence of bytes into a bytes object.Source§#[doc(hidden)]fn borrowed_sequence_into_pyobject<I>(
iter: I,
py: Python<'py>,
_: Token,
) -> Result<Bound<'py, PyAny>, PyErr>where
Self: Reference,
I: IntoIterator<Item = Self> + AsRef<[<Self as Reference>::BaseType]>,
I::IntoIter: ExactSizeIterator<Item = Self>,
#[doc(hidden)]fn borrowed_sequence_into_pyobject<I>(
iter: I,
py: Python<'py>,
_: Token,
) -> Result<Bound<'py, PyAny>, PyErr>where
Self: Reference,
I: IntoIterator<Item = Self> + AsRef<[<Self as Reference>::BaseType]>,
I::IntoIter: ExactSizeIterator<Item = Self>,
&[u8] and Cow<[u8]>
as a sequence of bytes into a bytes object.Source§#[doc(hidden)]const SEQUENCE_OUTPUT_TYPE: PyStaticExpr = _
#[doc(hidden)]const SEQUENCE_OUTPUT_TYPE: PyStaticExpr = _
experimental-inspect only.IntoPyObject::owned_sequence_into_pyobject and IntoPyObject::borrowed_sequence_into_pyobjectSource§impl<'a, 'py, T: PyClass> IntoPyObject<'py> for PyClassGuard<'a, T>
impl<'a, 'py, T: PyClass> IntoPyObject<'py> for PyClassGuard<'a, T>
Source§const OUTPUT_TYPE: PyStaticExpr = T::TYPE_HINT
const OUTPUT_TYPE: PyStaticExpr = T::TYPE_HINT
experimental-inspect only.Source§type Error = Infallible
type Error = Infallible
Source§fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error>
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error>
Source§#[doc(hidden)]fn owned_sequence_into_pyobject<I>(
iter: I,
py: Python<'py>,
_: Token,
) -> Result<Bound<'py, PyAny>, PyErr>
#[doc(hidden)]fn owned_sequence_into_pyobject<I>(
iter: I,
py: Python<'py>,
_: Token,
) -> Result<Bound<'py, PyAny>, PyErr>
Vec<u8>, [u8; N]
and SmallVec<[u8; N]> as a sequence of bytes into a bytes object.Source§#[doc(hidden)]const SEQUENCE_OUTPUT_TYPE: PyStaticExpr = _
#[doc(hidden)]const SEQUENCE_OUTPUT_TYPE: PyStaticExpr = _
experimental-inspect only.IntoPyObject::owned_sequence_into_pyobject and IntoPyObject::borrowed_sequence_into_pyobjectimpl<T: PyClass + Sync> Send for PyClassGuard<'_, T>
impl<T: PyClass + Sync> Sync for PyClassGuard<'_, T>
Auto Trait Implementations§
impl<'a, T> Freeze for PyClassGuard<'a, T>
impl<'a, T> RefUnwindSafe for PyClassGuard<'a, T>where
T: RefUnwindSafe,
impl<'a, T> Unpin for PyClassGuard<'a, T>
impl<'a, T> UnsafeUnpin for PyClassGuard<'a, T>
impl<'a, T> UnwindSafe for PyClassGuard<'a, T>where
T: RefUnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<'py, T> IntoPyCallbackOutput<'py, *mut PyObject> for Twhere
T: IntoPyObject<'py>,
impl<'py, T> IntoPyCallbackOutput<'py, *mut PyObject> for Twhere
T: IntoPyObject<'py>,
Source§impl<'py, T> IntoPyCallbackOutput<'py, Py<PyAny>> for Twhere
T: IntoPyObject<'py>,
impl<'py, T> IntoPyCallbackOutput<'py, Py<PyAny>> for Twhere
T: IntoPyObject<'py>,
Source§impl<'py, T> IntoPyObjectExt<'py> for Twhere
T: IntoPyObject<'py>,
impl<'py, T> IntoPyObjectExt<'py> for Twhere
T: IntoPyObject<'py>,
Source§fn into_bound_py_any(self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>>
fn into_bound_py_any(self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>>
self into an owned Python object, dropping type information.Source§impl<'py, T> PyClassInit<'py, false, false> for Twhere
T: IntoPyObject<'py>,
impl<'py, T> PyClassInit<'py, false, false> for Twhere
T: IntoPyObject<'py>,
Source§impl<T> PyErrArguments for T
impl<T> PyErrArguments for T
Source§impl<'a, 'py, T> PyFunctionArgument<'a, '_, 'py, true> for Twhere
T: FromPyObject<'a, 'py>,
impl<'a, 'py, T> PyFunctionArgument<'a, '_, 'py, true> for Twhere
T: FromPyObject<'a, 'py>,
Source§const INPUT_TYPE: PyStaticExpr = const INPUT_TYPE: PyStaticExpr = T::INPUT_TYPE;
const INPUT_TYPE: PyStaticExpr = const INPUT_TYPE: PyStaticExpr = T::INPUT_TYPE;
experimental-inspect only.type Holder = ()
type Error = <T as FromPyObject<'a, 'py>>::Error
fn extract( obj: Borrowed<'a, 'py, PyAny>, _: &mut (), ) -> Result<T, <T as PyFunctionArgument<'a, '_, 'py, true>>::Error>
Source§impl<'a, T> PyReturnType for Twhere
T: IntoPyObject<'a>,
impl<'a, T> PyReturnType for Twhere
T: IntoPyObject<'a>,
Source§const OUTPUT_TYPE: PyStaticExpr = const OUTPUT_TYPE: PyStaticExpr = T::OUTPUT_TYPE;
const OUTPUT_TYPE: PyStaticExpr = const OUTPUT_TYPE: PyStaticExpr = T::OUTPUT_TYPE;
experimental-inspect only.Source§impl<T> SizedTypeProperties for T
impl<T> SizedTypeProperties for T
Source§#[doc(hidden)]const SIZE: usize = _
#[doc(hidden)]const SIZE: usize = _
sized_type_properties)Source§#[doc(hidden)]const ALIGN: usize = _
#[doc(hidden)]const ALIGN: usize = _
sized_type_properties)Source§#[doc(hidden)]const ALIGNMENT: Alignment = _
#[doc(hidden)]const ALIGNMENT: Alignment = _
ptr_alignment_type)Source§#[doc(hidden)]const IS_ZST: bool = _
#[doc(hidden)]const IS_ZST: bool = _
sized_type_properties)Source§#[doc(hidden)]const LAYOUT: Layout = _
#[doc(hidden)]const LAYOUT: Layout = _
sized_type_properties)Source§#[doc(hidden)]const MAX_SLICE_LEN: usize = _
#[doc(hidden)]const MAX_SLICE_LEN: usize = _
sized_type_properties)[Self]. Read more