diff --git a/examples/rustapi_module/src/datetime.rs b/examples/rustapi_module/src/datetime.rs index cc20b6c67cf..edfaa922223 100644 --- a/examples/rustapi_module/src/datetime.rs +++ b/examples/rustapi_module/src/datetime.rs @@ -6,12 +6,12 @@ use pyo3::types::{ use pyo3::wrap_pyfunction; #[pyfunction] -fn make_date<'p>(py: Python<'p>, year: i32, month: u8, day: u8) -> PyResult<&'p PyDate> { +fn make_date(py: Python, year: i32, month: u8, day: u8) -> PyResult { PyDate::new(py, year, month, day) } #[pyfunction] -fn get_date_tuple<'p>(py: Python<'p>, d: &PyDate) -> &'p PyTuple { +fn get_date_tuple<'p>(py: Python<'p>, d: &PyDate) -> PyTuple<'p> { PyTuple::new( py, &[d.get_year(), d.get_month() as i32, d.get_day() as i32], @@ -19,7 +19,7 @@ fn get_date_tuple<'p>(py: Python<'p>, d: &PyDate) -> &'p PyTuple { } #[pyfunction] -fn date_from_timestamp<'p>(py: Python<'p>, timestamp: i64) -> PyResult<&'p PyDate> { +fn date_from_timestamp(py: Python, timestamp: i64) -> PyResult { PyDate::from_timestamp(py, timestamp) } @@ -31,7 +31,7 @@ fn make_time<'p>( second: u8, microsecond: u32, tzinfo: Option<&PyTzInfo>, -) -> PyResult<&'p PyTime> { +) -> PyResult> { PyTime::new( py, hour, @@ -52,7 +52,7 @@ fn time_with_fold<'p>( microsecond: u32, tzinfo: Option<&PyTzInfo>, fold: bool, -) -> PyResult<&'p PyTime> { +) -> PyResult> { PyTime::new_with_fold( py, hour, @@ -65,7 +65,7 @@ fn time_with_fold<'p>( } #[pyfunction] -fn get_time_tuple<'p>(py: Python<'p>, dt: &PyTime) -> &'p PyTuple { +fn get_time_tuple<'p>(py: Python<'p>, dt: &PyTime) -> PyTuple<'p> { PyTuple::new( py, &[ @@ -79,7 +79,7 @@ fn get_time_tuple<'p>(py: Python<'p>, dt: &PyTime) -> &'p PyTuple { #[cfg(Py_3_6)] #[pyfunction] -fn get_time_tuple_fold<'p>(py: Python<'p>, dt: &PyTime) -> &'p PyTuple { +fn get_time_tuple_fold<'p>(py: Python<'p>, dt: &PyTime) -> PyTuple<'p> { PyTuple::new( py, &[ @@ -103,7 +103,7 @@ fn make_delta<'p>( } #[pyfunction] -fn get_delta_tuple<'p>(py: Python<'p>, delta: &PyDelta) -> &'p PyTuple { +fn get_delta_tuple<'p>(py: Python<'p>, delta: &PyDelta) -> PyTuple<'p> { PyTuple::new( py, &[ @@ -125,7 +125,7 @@ fn make_datetime<'p>( second: u8, microsecond: u32, tzinfo: Option<&PyTzInfo>, -) -> PyResult<&'p PyDateTime> { +) -> PyResult> { PyDateTime::new( py, year, @@ -140,7 +140,7 @@ fn make_datetime<'p>( } #[pyfunction] -fn get_datetime_tuple<'p>(py: Python<'p>, dt: &PyDateTime) -> &'p PyTuple { +fn get_datetime_tuple<'p>(py: Python<'p>, dt: &PyDateTime) -> PyTuple<'p> { PyTuple::new( py, &[ @@ -157,7 +157,7 @@ fn get_datetime_tuple<'p>(py: Python<'p>, dt: &PyDateTime) -> &'p PyTuple { #[cfg(Py_3_6)] #[pyfunction] -fn get_datetime_tuple_fold<'p>(py: Python<'p>, dt: &PyDateTime) -> &'p PyTuple { +fn get_datetime_tuple_fold<'p>(py: Python<'p>, dt: &PyDateTime) -> PyTuple<'p> { PyTuple::new( py, &[ @@ -178,7 +178,7 @@ fn datetime_from_timestamp<'p>( py: Python<'p>, ts: f64, tz: Option<&PyTzInfo>, -) -> PyResult<&'p PyDateTime> { +) -> PyResult> { PyDateTime::from_timestamp(py, ts, tz) } @@ -199,15 +199,15 @@ impl TzClass { TzClass {} } - fn utcoffset<'p>(&self, py: Python<'p>, _dt: &PyDateTime) -> PyResult<&'p PyDelta> { + fn utcoffset<'p>(&self, py: Python<'p>, _dt: &PyDateTime) -> PyResult> { PyDelta::new(py, 0, 3600, 0, true) } - fn tzname(&self, _py: Python<'_>, _dt: &PyDateTime) -> PyResult { + fn tzname(&self, _py: Python, _dt: &PyDateTime) -> PyResult { Ok(String::from("+01:00")) } - fn dst(&self, _py: Python<'_>, _dt: &PyDateTime) -> PyResult> { + fn dst<'p>(&self, _py: Python, _dt: &PyDateTime) -> PyResult>> { Ok(None) } } diff --git a/guide/src/class.md b/guide/src/class.md index 78a9cee1cd3..6a2b689c39b 100644 --- a/guide/src/class.md +++ b/guide/src/class.md @@ -36,7 +36,6 @@ unsafe impl pyo3::PyTypeInfo for MyClass { type BaseLayout = pyo3::pycell::PyCellBase; type Layout = PyCell; type Initializer = PyClassInitializer; - type AsRefTarget = PyCell; const NAME: &'static str = "MyClass"; const MODULE: Option<&'static str> = None; diff --git a/pyo3-derive-backend/src/func.rs b/pyo3-derive-backend/src/func.rs index 95539d8499f..c43e128528a 100644 --- a/pyo3-derive-backend/src/func.rs +++ b/pyo3-derive-backend/src/func.rs @@ -131,15 +131,16 @@ pub(crate) fn impl_method_proto( let mut slf_ty = get_arg_ty(sig, 0); // update the type if no lifetime was given: - // PyRef --> PyRef<'p, Self> + // PyRef --> PyRef<'p, 'p, Self> if let syn::Type::Path(ref mut path) = slf_ty { if let syn::PathArguments::AngleBracketed(ref mut args) = path.path.segments[0].arguments { if let syn::GenericArgument::Lifetime(_) = args.args[0] { } else { - let lt = syn::parse_quote! {'p}; - args.args.insert(0, lt); + // Insert two 'p lifetimes for PyRef / PyRefMut + args.args.insert(0, syn::parse_quote! {'p}); + args.args.insert(0, syn::parse_quote! {'p}); } } } @@ -452,8 +453,22 @@ fn get_arg_ty(sig: &syn::Signature, idx: usize) -> syn::Type { _ => panic!("fn arg type is not supported"), }; - // Add a lifetime if there is none - if let syn::Type::Reference(ref mut r) = ty { + + if let syn::Type::Reference(r) = &mut ty { + // HACK: For PyAny, add <'p> + match &mut *r.elem { + syn::Type::Path(ty) => { + let seg = ty.path.segments.last_mut().unwrap(); + if seg.ident == "PyAny" { + if let syn::PathArguments::None = seg.arguments { + seg.arguments = syn::PathArguments::AngleBracketed(syn::parse_quote!(<'p>)); + } + } + }, + _ => {} + } + + // Add a lifetime if there is none r.lifetime.get_or_insert(syn::parse_quote! {'p}); } diff --git a/pyo3-derive-backend/src/pyclass.rs b/pyo3-derive-backend/src/pyclass.rs index 5c92a75beac..c523c055dfd 100644 --- a/pyo3-derive-backend/src/pyclass.rs +++ b/pyo3-derive-backend/src/pyclass.rs @@ -43,7 +43,7 @@ impl Default for PyClassArgs { // We need the 0 as value for the constant we're later building using quote for when there // are no other flags flags: vec![parse_quote! { 0 }], - base: parse_quote! { pyo3::PyAny }, + base: parse_quote! { pyo3::type_marker::Any }, has_extends: false, } } @@ -276,7 +276,7 @@ fn impl_class( } } else { quote! { - impl pyo3::pyclass::PyClassAlloc for #cls {} + impl pyo3::pyclass::PyClassAlloc<'_> for #cls {} } } }; @@ -312,14 +312,14 @@ fn impl_class( let weakref = if has_weakref { quote! { pyo3::pyclass_slots::PyClassWeakRefSlot } } else if attr.has_extends { - quote! { ::WeakRef } + quote! { >::WeakRef } } else { quote! { pyo3::pyclass_slots::PyClassDummySlot } }; let dict = if has_dict { quote! { pyo3::pyclass_slots::PyClassDictSlot } } else if attr.has_extends { - quote! { ::Dict } + quote! { >::Dict } } else { quote! { pyo3::pyclass_slots::PyClassDummySlot } }; @@ -355,14 +355,14 @@ fn impl_class( quote! { 0 } }; let base_layout = if attr.has_extends { - quote! { ::LayoutAsBase } + quote! { >::LayoutAsBase } } else { - quote! { pyo3::pycell::PyCellBase } + quote! { pyo3::pycell::PyCellBase<'py, pyo3::type_marker::Any> } }; let base_nativetype = if attr.has_extends { - quote! { ::BaseNativeType } + quote! { >::RootType } } else { - quote! { pyo3::PyAny } + quote! { pyo3::type_marker::Any } }; // If #cls is not extended type, we allow Self->PyObject conversion @@ -379,18 +379,12 @@ fn impl_class( }; Ok(quote! { - unsafe impl pyo3::type_object::PyTypeInfo for #cls { + unsafe impl<'py> pyo3::type_object::PyTypeInfo<'py> for #cls { type Type = #cls; - type BaseType = #base; - type Layout = pyo3::PyCell; - type BaseLayout = #base_layout; - type Initializer = pyo3::pyclass_init::PyClassInitializer; - type AsRefTarget = pyo3::PyCell; const NAME: &'static str = #cls_name; const MODULE: Option<&'static str> = #module; const DESCRIPTION: &'static str = #doc; - const FLAGS: usize = #(#flags)|* | #extended; #[inline] fn type_object() -> &'static pyo3::ffi::PyTypeObject { @@ -400,20 +394,39 @@ fn impl_class( } } - impl pyo3::PyClass for #cls { + impl<'py> pyo3::PyClass<'py> for #cls { type Dict = #dict; type WeakRef = #weakref; - type BaseNativeType = #base_nativetype; + type RootType = #base_nativetype; } - impl<'a> pyo3::derive_utils::ExtractExt<'a> for &'a #cls + impl<'a, 'py: 'a> pyo3::derive_utils::ExtractExt<'a, 'py> for &'a #cls { - type Target = pyo3::PyRef<'a, #cls>; + type Target = pyo3::PyRef<'a, 'py, #cls>; } - impl<'a> pyo3::derive_utils::ExtractExt<'a> for &'a mut #cls + impl<'a, 'py: 'a> pyo3::derive_utils::ExtractExt<'a, 'py> for &'a mut #cls { - type Target = pyo3::PyRefMut<'a, #cls>; + type Target = pyo3::PyRefMut<'a, 'py, #cls>; + } + + impl<'py> pyo3::type_marker::TypeMarker<'py> for #cls { + type NativeType = pyo3::PyCell<'py, #cls>; + type Layout = pyo3::pycell::PyCellLayout<'py, Self>; + type Initializer = pyo3::pyclass_init::PyClassInitializer<'py, Self>; + + const FLAGS: usize = #(#flags)|* | #extended; + + fn type_object() -> &'static pyo3::ffi::PyTypeObject { + >::type_object() + } + } + + impl<'py> pyo3::type_marker::TypeWithBase<'py> for #cls { + type BaseType = #base; + type BaseNativeType = <#base as pyo3::type_marker::TypeMarker<'py>>::NativeType; + type BaseLayout = #base_layout; + type BaseInitializer = <#base as pyo3::type_marker::TypeMarker<'py>>::Initializer; } #into_pyobject diff --git a/pyo3-derive-backend/src/pymethod.rs b/pyo3-derive-backend/src/pymethod.rs index 3d19983e5a0..4f090b0dc4c 100644 --- a/pyo3-derive-backend/src/pymethod.rs +++ b/pyo3-derive-backend/src/pymethod.rs @@ -128,7 +128,7 @@ fn impl_wrap_common( let _py = _pool.python(); pyo3::run_callback(_py, || { #slf - let _args = _py.from_borrowed_ptr::(_args); + let _args = pyo3::PyAny::raw_borrowed(_py, &_args).downcast::()?; let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs); #body @@ -451,8 +451,8 @@ fn impl_arg_params_(spec: &FnSpec<'_>, body: TokenStream, into_result: TokenStre ]; let mut output = [None; #num_normal_params]; - let mut _args = _args; - let mut _kwargs = _kwargs; + let _args = _args; + let _kwargs = _kwargs; let (_args, _kwargs) = pyo3::derive_utils::parse_fn_args( Some(_LOCATION), @@ -503,7 +503,7 @@ fn impl_arg_param( }; } else if spec.is_kwargs(&name) { return quote! { - let #arg_name = _kwargs; + let #arg_name = _kwargs.as_ref(); }; } let arg_value = quote!(output[#option_pos]); diff --git a/src/buffer.rs b/src/buffer.rs index cf9b5c1c135..8a62ef16460 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -719,7 +719,7 @@ mod test { .unwrap() .call_method("array", ("f", (1.0, 1.5, 2.0, 2.5)), None) .unwrap(); - let buffer = PyBuffer::get(py, array).unwrap(); + let buffer = PyBuffer::get(py, &array).unwrap(); assert_eq!(buffer.dimensions(), 1); assert_eq!(buffer.item_count(), 4); assert_eq!(buffer.format().to_str().unwrap(), "f"); diff --git a/src/class/basic.rs b/src/class/basic.rs index 74057bb57c5..96dfc246ca0 100644 --- a/src/class/basic.rs +++ b/src/class/basic.rs @@ -29,7 +29,7 @@ pub enum CompareOp { /// Basic Python class customization #[allow(unused_variables)] -pub trait PyObjectProtocol<'p>: PyClass { +pub trait PyObjectProtocol<'p>: PyClass<'p> { fn __getattr__(&'p self, name: Self::Name) -> Self::Result where Self: PyObjectGetAttrProtocol<'p>, @@ -102,17 +102,17 @@ pub trait PyObjectProtocol<'p>: PyClass { } pub trait PyObjectGetAttrProtocol<'p>: PyObjectProtocol<'p> { - type Name: FromPyObject<'p>; + type Name: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyObjectSetAttrProtocol<'p>: PyObjectProtocol<'p> { - type Name: FromPyObject<'p>; - type Value: FromPyObject<'p>; + type Name: FromPyObject<'p, 'p>; + type Value: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyObjectDelAttrProtocol<'p>: PyObjectProtocol<'p> { - type Name: FromPyObject<'p>; + type Name: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyObjectStrProtocol<'p>: PyObjectProtocol<'p> { @@ -124,7 +124,7 @@ pub trait PyObjectReprProtocol<'p>: PyObjectProtocol<'p> { type Result: Into>; } pub trait PyObjectFormatProtocol<'p>: PyObjectProtocol<'p> { - type Format: FromPyObject<'p>; + type Format: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } @@ -139,7 +139,7 @@ pub trait PyObjectBytesProtocol<'p>: PyObjectProtocol<'p> { type Result: Into>; } pub trait PyObjectRichcmpProtocol<'p>: PyObjectProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } diff --git a/src/class/buffer.rs b/src/class/buffer.rs index d812cbfbe92..ffc4fc77211 100644 --- a/src/class/buffer.rs +++ b/src/class/buffer.rs @@ -14,15 +14,15 @@ use std::os::raw::c_int; /// For more information check [buffer protocol](https://docs.python.org/3/c-api/buffer.html) /// c-api #[allow(unused_variables)] -pub trait PyBufferProtocol<'p>: PyClass { - fn bf_getbuffer(slf: PyRefMut, view: *mut ffi::Py_buffer, flags: c_int) -> Self::Result +pub trait PyBufferProtocol<'p>: PyClass<'p> { + fn bf_getbuffer(slf: PyRefMut<'_, 'p, Self>, view: *mut ffi::Py_buffer, flags: c_int) -> Self::Result where Self: PyBufferGetBufferProtocol<'p>, { unimplemented!() } - fn bf_releasebuffer(slf: PyRefMut, view: *mut ffi::Py_buffer) -> Self::Result + fn bf_releasebuffer(slf: PyRefMut<'_, 'p, Self>, view: *mut ffi::Py_buffer) -> Self::Result where Self: PyBufferReleaseBufferProtocol<'p>, { diff --git a/src/class/context.rs b/src/class/context.rs index 9a9e0e98167..18b6cadd3e9 100644 --- a/src/class/context.rs +++ b/src/class/context.rs @@ -10,7 +10,7 @@ use crate::{PyClass, PyObject}; /// Context manager interface #[allow(unused_variables)] -pub trait PyContextProtocol<'p>: PyClass { +pub trait PyContextProtocol<'p>: PyClass<'p> { fn __enter__(&'p mut self) -> Self::Result where Self: PyContextEnterProtocol<'p>, @@ -37,9 +37,9 @@ pub trait PyContextEnterProtocol<'p>: PyContextProtocol<'p> { } pub trait PyContextExitProtocol<'p>: PyContextProtocol<'p> { - type ExcType: crate::FromPyObject<'p>; - type ExcValue: crate::FromPyObject<'p>; - type Traceback: crate::FromPyObject<'p>; + type ExcType: crate::FromPyObject<'p, 'p>; + type ExcValue: crate::FromPyObject<'p, 'p>; + type Traceback: crate::FromPyObject<'p, 'p>; type Success: crate::IntoPy; type Result: Into>; } diff --git a/src/class/descr.rs b/src/class/descr.rs index fb36b72a23e..f288a2e19a4 100644 --- a/src/class/descr.rs +++ b/src/class/descr.rs @@ -13,7 +13,7 @@ use std::os::raw::c_int; /// Descriptor interface #[allow(unused_variables)] -pub trait PyDescrProtocol<'p>: PyClass { +pub trait PyDescrProtocol<'p>: PyClass<'p> { fn __get__(&'p self, instance: &'p PyAny, owner: Option<&'p PyType>) -> Self::Result where Self: PyDescrGetProtocol<'p>, @@ -44,25 +44,25 @@ pub trait PyDescrProtocol<'p>: PyClass { } pub trait PyDescrGetProtocol<'p>: PyDescrProtocol<'p> { - type Inst: FromPyObject<'p>; - type Owner: FromPyObject<'p>; + type Inst: FromPyObject<'p, 'p>; + type Owner: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyDescrSetProtocol<'p>: PyDescrProtocol<'p> { - type Inst: FromPyObject<'p>; - type Value: FromPyObject<'p>; + type Inst: FromPyObject<'p, 'p>; + type Value: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyDescrDeleteProtocol<'p>: PyDescrProtocol<'p> { - type Inst: FromPyObject<'p>; + type Inst: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyDescrSetNameProtocol<'p>: PyDescrProtocol<'p> { - type Inst: FromPyObject<'p>; + type Inst: FromPyObject<'p, 'p>; type Result: Into>; } diff --git a/src/class/gc.rs b/src/class/gc.rs index 040a6352410..4f1c9ea9340 100644 --- a/src/class/gc.rs +++ b/src/class/gc.rs @@ -10,7 +10,7 @@ use std::os::raw::{c_int, c_void}; pub struct PyTraverseError(c_int); /// GC support -pub trait PyGCProtocol<'p>: PyClass { +pub trait PyGCProtocol<'p>: PyClass<'p> { fn __traverse__(&'p self, visit: PyVisit) -> Result<(), PyTraverseError>; fn __clear__(&'p mut self); } diff --git a/src/class/iter.rs b/src/class/iter.rs index 08c12963df3..a4a43e55b5d 100644 --- a/src/class/iter.rs +++ b/src/class/iter.rs @@ -12,7 +12,7 @@ use crate::{ffi, IntoPy, IntoPyPointer, PyClass, PyObject, Python}; /// Check [CPython doc](https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_iter) /// for more. #[allow(unused_variables)] -pub trait PyIterProtocol<'p>: PyClass { +pub trait PyIterProtocol<'p>: PyClass<'p> { fn __iter__(slf: Self::Receiver) -> Self::Result where Self: PyIterIterProtocol<'p>, @@ -29,13 +29,13 @@ pub trait PyIterProtocol<'p>: PyClass { } pub trait PyIterIterProtocol<'p>: PyIterProtocol<'p> { - type Receiver: TryFromPyCell<'p, Self>; + type Receiver: TryFromPyCell<'p, 'p, Self>; type Success: crate::IntoPy; type Result: Into>; } pub trait PyIterNextProtocol<'p>: PyIterProtocol<'p> { - type Receiver: TryFromPyCell<'p, Self>; + type Receiver: TryFromPyCell<'p, 'p, Self>; type Success: crate::IntoPy; type Result: Into>>; } diff --git a/src/class/mapping.rs b/src/class/mapping.rs index 4d82a9dd5fc..6ac411abb72 100644 --- a/src/class/mapping.rs +++ b/src/class/mapping.rs @@ -9,7 +9,7 @@ use crate::{exceptions, ffi, FromPyObject, IntoPy, PyClass, PyObject}; /// Mapping interface #[allow(unused_variables)] -pub trait PyMappingProtocol<'p>: PyClass { +pub trait PyMappingProtocol<'p>: PyClass<'p> { fn __len__(&'p self) -> Self::Result where Self: PyMappingLenProtocol<'p>, @@ -54,19 +54,19 @@ pub trait PyMappingLenProtocol<'p>: PyMappingProtocol<'p> { } pub trait PyMappingGetItemProtocol<'p>: PyMappingProtocol<'p> { - type Key: FromPyObject<'p>; + type Key: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyMappingSetItemProtocol<'p>: PyMappingProtocol<'p> { - type Key: FromPyObject<'p>; - type Value: FromPyObject<'p>; + type Key: FromPyObject<'p, 'p>; + type Value: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyMappingDelItemProtocol<'p>: PyMappingProtocol<'p> { - type Key: FromPyObject<'p>; + type Key: FromPyObject<'p, 'p>; type Result: Into>; } diff --git a/src/class/number.rs b/src/class/number.rs index 207a5b3a6a0..33fe58d9655 100644 --- a/src/class/number.rs +++ b/src/class/number.rs @@ -10,7 +10,7 @@ use crate::{ffi, FromPyObject, IntoPy, PyClass, PyObject}; /// Number interface #[allow(unused_variables)] -pub trait PyNumberProtocol<'p>: PyClass { +pub trait PyNumberProtocol<'p>: PyClass<'p> { fn __add__(lhs: Self::Left, rhs: Self::Right) -> Self::Result where Self: PyNumberAddProtocol<'p>, @@ -318,256 +318,256 @@ pub trait PyNumberProtocol<'p>: PyClass { } pub trait PyNumberAddProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberSubProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberMulProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberMatmulProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberTruedivProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberFloordivProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberModProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberDivmodProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberPowProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; - type Modulo: FromPyObject<'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; + type Modulo: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberLShiftProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRShiftProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberAndProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberXorProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberOrProtocol<'p>: PyNumberProtocol<'p> { - type Left: FromPyObject<'p>; - type Right: FromPyObject<'p>; + type Left: FromPyObject<'p, 'p>; + type Right: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRAddProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRSubProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRMulProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRMatmulProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRTruedivProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRFloordivProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRModProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRDivmodProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRPowProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; - type Modulo: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; + type Modulo: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRLShiftProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRRShiftProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRAndProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberRXorProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberROrProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PyNumberIAddProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyNumberISubProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyNumberIMulProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyNumberIMatmulProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyNumberITruedivProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyNumberIFloordivProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyNumberIModProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyNumberIDivmodProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyNumberIPowProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyNumberILShiftProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyNumberIRShiftProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyNumberIAndProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyNumberIXorProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PyNumberIOrProtocol<'p>: PyNumberProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } @@ -608,7 +608,7 @@ pub trait PyNumberFloatProtocol<'p>: PyNumberProtocol<'p> { pub trait PyNumberRoundProtocol<'p>: PyNumberProtocol<'p> { type Success: IntoPy; - type NDigits: FromPyObject<'p>; + type NDigits: FromPyObject<'p, 'p>; type Result: Into>; } diff --git a/src/class/pyasync.rs b/src/class/pyasync.rs index a43dc57cd85..e9a79751ff0 100644 --- a/src/class/pyasync.rs +++ b/src/class/pyasync.rs @@ -16,7 +16,7 @@ use crate::{ffi, PyClass, PyObject}; /// /// Each method in this trait corresponds to Python async/await implementation. #[allow(unused_variables)] -pub trait PyAsyncProtocol<'p>: PyClass { +pub trait PyAsyncProtocol<'p>: PyClass<'p> { fn __await__(&'p self) -> Self::Result where Self: PyAsyncAwaitProtocol<'p>, @@ -79,9 +79,9 @@ pub trait PyAsyncAenterProtocol<'p>: PyAsyncProtocol<'p> { } pub trait PyAsyncAexitProtocol<'p>: PyAsyncProtocol<'p> { - type ExcType: crate::FromPyObject<'p>; - type ExcValue: crate::FromPyObject<'p>; - type Traceback: crate::FromPyObject<'p>; + type ExcType: crate::FromPyObject<'p, 'p>; + type ExcValue: crate::FromPyObject<'p, 'p>; + type Traceback: crate::FromPyObject<'p, 'p>; type Success: crate::IntoPy; type Result: Into>; } diff --git a/src/class/sequence.rs b/src/class/sequence.rs index 4d31ce57d38..00c8e5c449f 100644 --- a/src/class/sequence.rs +++ b/src/class/sequence.rs @@ -12,7 +12,7 @@ use std::os::raw::c_int; /// Sequence interface #[allow(unused_variables)] -pub trait PySequenceProtocol<'p>: PyClass + Sized { +pub trait PySequenceProtocol<'p>: PyClass<'p> + Sized { fn __len__(&'p self) -> Self::Result where Self: PySequenceLenProtocol<'p>, @@ -85,46 +85,46 @@ pub trait PySequenceLenProtocol<'p>: PySequenceProtocol<'p> { } pub trait PySequenceGetItemProtocol<'p>: PySequenceProtocol<'p> { - type Index: FromPyObject<'p> + From; + type Index: FromPyObject<'p, 'p> + From; type Success: IntoPy; type Result: Into>; } pub trait PySequenceSetItemProtocol<'p>: PySequenceProtocol<'p> { - type Index: FromPyObject<'p> + From; - type Value: FromPyObject<'p>; + type Index: FromPyObject<'p, 'p> + From; + type Value: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PySequenceDelItemProtocol<'p>: PySequenceProtocol<'p> { - type Index: FromPyObject<'p> + From; + type Index: FromPyObject<'p, 'p> + From; type Result: Into>; } pub trait PySequenceContainsProtocol<'p>: PySequenceProtocol<'p> { - type Item: FromPyObject<'p>; + type Item: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PySequenceConcatProtocol<'p>: PySequenceProtocol<'p> { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Success: IntoPy; type Result: Into>; } pub trait PySequenceRepeatProtocol<'p>: PySequenceProtocol<'p> { - type Index: FromPyObject<'p> + From; + type Index: FromPyObject<'p, 'p> + From; type Success: IntoPy; type Result: Into>; } pub trait PySequenceInplaceConcatProtocol<'p>: PySequenceProtocol<'p> + IntoPy { - type Other: FromPyObject<'p>; + type Other: FromPyObject<'p, 'p>; type Result: Into>; } pub trait PySequenceInplaceRepeatProtocol<'p>: PySequenceProtocol<'p> + IntoPy { - type Index: FromPyObject<'p> + From; + type Index: FromPyObject<'p, 'p> + From; type Result: Into>; } diff --git a/src/conversion.rs b/src/conversion.rs index 6ca0792a58d..ed9bdd4bc4a 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -5,8 +5,8 @@ use crate::err::{self, PyDowncastError, PyResult}; use crate::object::PyObject; use crate::type_object::{PyDowncastImpl, PyTypeInfo}; use crate::types::PyTuple; -use crate::{ffi, gil, Py, PyAny, PyCell, PyClass, PyNativeType, PyRef, PyRefMut, Python}; -use std::ptr::NonNull; +use crate::type_marker::Tuple; +use crate::{ffi, Py, PyAny, PyCell, PyClass, PyNativeType, PyRef, PyRefMut, Python}; /// This trait represents that **we can do zero-cost conversion from the object /// to a FFI pointer**. @@ -64,16 +64,10 @@ where impl<'a, T> IntoPyPointer for &'a T where - T: AsPyPointer, + T: IntoPyPointer + Clone, { fn into_ptr(self) -> *mut ffi::PyObject { - let ptr = self.as_ptr(); - if !ptr.is_null() { - unsafe { - ffi::Py_INCREF(ptr); - } - } - ptr + self.clone().into_ptr() } } @@ -186,9 +180,9 @@ impl FromPy for T { /// /// The trait's conversion method takes a `&PyAny` argument but is called /// `FromPyObject` for historical reasons. -pub trait FromPyObject<'source>: Sized { +pub trait FromPyObject<'a, 'py>: Sized { /// Extracts `Self` from the source `PyObject`. - fn extract(ob: &'source PyAny) -> PyResult; + fn extract(ob: &'a PyAny<'py>) -> PyResult; } /// Identity conversion: allows using existing `PyObject` instances where @@ -252,50 +246,41 @@ where } } -impl<'a, T> FromPyObject<'a> for &'a PyCell -where - T: PyClass, -{ - fn extract(obj: &'a PyAny) -> PyResult { - PyTryFrom::try_from(obj).map_err(Into::into) - } -} - -impl<'a, T> FromPyObject<'a> for T +impl<'py, T> FromPyObject<'_, 'py> for T where - T: PyClass + Clone, + T: PyClass<'py> + Clone, { - fn extract(obj: &'a PyAny) -> PyResult { + fn extract(obj: &'_ PyAny<'py>) -> PyResult { let cell: &PyCell = PyTryFrom::try_from(obj)?; Ok(unsafe { cell.try_borrow_unguarded()?.clone() }) } } -impl<'a, T> FromPyObject<'a> for PyRef<'a, T> +impl<'a, 'py, T> FromPyObject<'a, 'py> for PyRef<'a, 'py, T> where - T: PyClass, + T: PyClass<'py>, { - fn extract(obj: &'a PyAny) -> PyResult { + fn extract(obj: &'a PyAny<'py>) -> PyResult { let cell: &PyCell = PyTryFrom::try_from(obj)?; cell.try_borrow().map_err(Into::into) } } -impl<'a, T> FromPyObject<'a> for PyRefMut<'a, T> +impl<'a, 'py, T> FromPyObject<'a, 'py> for PyRefMut<'a, 'py, T> where - T: PyClass, + T: PyClass<'py>, { - fn extract(obj: &'a PyAny) -> PyResult { + fn extract(obj: &'a PyAny<'py>) -> PyResult { let cell: &PyCell = PyTryFrom::try_from(obj)?; cell.try_borrow_mut().map_err(Into::into) } } -impl<'a, T> FromPyObject<'a> for Option +impl<'a, 'py, T> FromPyObject<'a, 'py> for Option where - T: FromPyObject<'a>, + T: FromPyObject<'a, 'py>, { - fn extract(obj: &'a PyAny) -> PyResult { + fn extract(obj: &'a PyAny<'py>) -> PyResult { if obj.as_ptr() == unsafe { ffi::Py_None() } { Ok(None) } else { @@ -311,16 +296,16 @@ where /// If `T` implements `PyTryFrom`, we can convert `&PyAny` to `&T`. /// /// This trait is similar to `std::convert::TryFrom` -pub trait PyTryFrom<'v>: Sized + PyDowncastImpl { +pub trait PyTryFrom<'py>: Sized + PyDowncastImpl<'py> { /// Cast from a concrete Python object type to PyObject. - fn try_from>(value: V) -> Result<&'v Self, PyDowncastError>; + fn try_from<'a>(value: &'a PyAny<'py>) -> Result<&'a Self, PyDowncastError>; /// Cast from a concrete Python object type to PyObject. With exact type check. - fn try_from_exact>(value: V) -> Result<&'v Self, PyDowncastError>; + fn try_from_exact<'a>(value: &'a PyAny<'py>) -> Result<&'a Self, PyDowncastError>; /// Cast a PyAny to a specific type of PyObject. The caller must /// have already verified the reference is for this type. - unsafe fn try_from_unchecked>(value: V) -> &'v Self; + unsafe fn try_from_unchecked<'a>(value: &'a PyAny<'py>) -> &'a Self; } /// Trait implemented by Python object types that allow a checked downcast. @@ -334,9 +319,9 @@ pub trait PyTryInto: Sized { } // TryFrom implies TryInto -impl PyTryInto for PyAny +impl<'v, U> PyTryInto for PyAny<'v> where - U: for<'v> PyTryFrom<'v>, + U: PyTryFrom<'v>, { fn try_into(&self) -> Result<&U, PyDowncastError> { U::try_from(self) @@ -346,12 +331,11 @@ where } } -impl<'v, T> PyTryFrom<'v> for T +impl<'py, T> PyTryFrom<'py> for T where - T: PyDowncastImpl + PyTypeInfo + PyNativeType, + T: PyDowncastImpl<'py> + PyTypeInfo<'py> + PyNativeType<'py>, { - fn try_from>(value: V) -> Result<&'v Self, PyDowncastError> { - let value = value.into(); + fn try_from<'a>(value: &'a PyAny<'py>) -> Result<&'a Self, PyDowncastError> { unsafe { if T::is_instance(value) { Ok(Self::try_from_unchecked(value)) @@ -361,8 +345,7 @@ where } } - fn try_from_exact>(value: V) -> Result<&'v Self, PyDowncastError> { - let value = value.into(); + fn try_from_exact<'a>(value: &'a PyAny<'py>) -> Result<&'a Self, PyDowncastError> { unsafe { if T::is_exact_instance(value) { Ok(Self::try_from_unchecked(value)) @@ -373,29 +356,28 @@ where } #[inline] - unsafe fn try_from_unchecked>(value: V) -> &'v Self { + unsafe fn try_from_unchecked<'a>(value: &'a PyAny<'py>) -> &'a Self { Self::unchecked_downcast(value.into()) } } -impl<'v, T> PyTryFrom<'v> for PyCell +impl<'py, T> PyTryFrom<'py> for PyCell<'py, T> where - T: 'v + PyClass, + T: 'py + PyClass<'py>, { - fn try_from>(value: V) -> Result<&'v Self, PyDowncastError> { + fn try_from<'a>(value: &'a PyAny<'py>) -> Result<&'a Self, PyDowncastError> { let value = value.into(); unsafe { - if T::is_instance(value) { + if >::is_instance(value) { Ok(Self::try_from_unchecked(value)) } else { Err(PyDowncastError) } } } - fn try_from_exact>(value: V) -> Result<&'v Self, PyDowncastError> { - let value = value.into(); + fn try_from_exact<'a>(value: &'a PyAny<'py>) -> Result<&'a Self, PyDowncastError> { unsafe { - if T::is_exact_instance(value) { + if >::is_exact_instance(value) { Ok(Self::try_from_unchecked(value)) } else { Err(PyDowncastError) @@ -403,31 +385,31 @@ where } } #[inline] - unsafe fn try_from_unchecked>(value: V) -> &'v Self { - Self::unchecked_downcast(value.into()) + unsafe fn try_from_unchecked<'a>(value: &'a PyAny<'py>) -> &'a Self { + Self::unchecked_downcast(value) } } /// Converts `()` to an empty Python tuple. -impl FromPy<()> for Py { - fn from_py(_: (), py: Python) -> Py { - Py::from_py(PyTuple::empty(py), py) +impl FromPy<()> for Py { + fn from_py(_: (), py: Python) -> Py { + Py::from(PyTuple::empty(py)) } } /// Raw level conversion between `*mut ffi::PyObject` and PyO3 types. pub unsafe trait FromPyPointer<'p>: Sized { - unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<&'p Self>; - unsafe fn from_owned_ptr_or_panic(py: Python<'p>, ptr: *mut ffi::PyObject) -> &'p Self { + unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option; + unsafe fn from_owned_ptr_or_panic(py: Python<'p>, ptr: *mut ffi::PyObject) -> Self { match Self::from_owned_ptr_or_opt(py, ptr) { Some(s) => s, None => err::panic_after_error(), } } - unsafe fn from_owned_ptr(py: Python<'p>, ptr: *mut ffi::PyObject) -> &'p Self { + unsafe fn from_owned_ptr(py: Python<'p>, ptr: *mut ffi::PyObject) -> Self { Self::from_owned_ptr_or_panic(py, ptr) } - unsafe fn from_owned_ptr_or_err(py: Python<'p>, ptr: *mut ffi::PyObject) -> PyResult<&'p Self> { + unsafe fn from_owned_ptr_or_err(py: Python<'p>, ptr: *mut ffi::PyObject) -> PyResult { match Self::from_owned_ptr_or_opt(py, ptr) { Some(s) => Ok(s), None => Err(err::PyErr::fetch(py)), @@ -455,36 +437,6 @@ pub unsafe trait FromPyPointer<'p>: Sized { } } -unsafe impl<'p, T> FromPyPointer<'p> for T -where - T: 'p + crate::PyNativeType, -{ - unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<&'p Self> { - NonNull::new(ptr).map(|p| Self::unchecked_downcast(gil::register_owned(py, p))) - } - unsafe fn from_borrowed_ptr_or_opt( - py: Python<'p>, - ptr: *mut ffi::PyObject, - ) -> Option<&'p Self> { - NonNull::new(ptr).map(|p| Self::unchecked_downcast(gil::register_borrowed(py, p))) - } -} - -unsafe impl<'p, T> FromPyPointer<'p> for PyCell -where - T: PyClass, -{ - unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<&'p Self> { - NonNull::new(ptr).map(|p| &*(gil::register_owned(py, p).as_ptr() as *const PyCell)) - } - unsafe fn from_borrowed_ptr_or_opt( - py: Python<'p>, - ptr: *mut ffi::PyObject, - ) -> Option<&'p Self> { - NonNull::new(ptr).map(|p| &*(gil::register_borrowed(py, p).as_ptr() as *const PyCell)) - } -} - #[cfg(test)] mod test { use crate::types::PyList; @@ -498,6 +450,6 @@ mod test { let py = gil.python(); let list = PyList::new(py, &[1, 2, 3]); let val = unsafe { ::try_from_unchecked(list.as_ref()) }; - assert_eq!(list, val); + assert_eq!(&list, val); } } diff --git a/src/derive_utils.rs b/src/derive_utils.rs index 76a05182b9d..7deb875853d 100644 --- a/src/derive_utils.rs +++ b/src/derive_utils.rs @@ -6,7 +6,6 @@ use crate::err::{PyErr, PyResult}; use crate::exceptions::TypeError; -use crate::instance::PyNativeType; use crate::pyclass::PyClass; use crate::pyclass_init::PyClassInitializer; use crate::types::{PyAny, PyDict, PyModule, PyTuple}; @@ -32,15 +31,15 @@ pub struct ParamDescription { /// * kwargs: Keyword arguments /// * output: Output array that receives the arguments. /// Must have same length as `params` and must be initialized to `None`. -pub fn parse_fn_args<'p>( +pub fn parse_fn_args<'py>( fname: Option<&str>, params: &[ParamDescription], - args: &'p PyTuple, - kwargs: Option<&'p PyDict>, + args: &'py PyTuple<'py>, + kwargs: Option<&'py PyDict<'py>>, accept_args: bool, accept_kwargs: bool, - output: &mut [Option<&'p PyAny>], -) -> PyResult<(&'p PyTuple, Option<&'p PyDict>)> { + output: &mut [Option<&'py PyAny<'py>>], +) -> PyResult<(PyTuple<'py>, Option>)> { let nargs = args.len(); let mut used_args = 0; macro_rules! raise_error { @@ -48,11 +47,10 @@ pub fn parse_fn_args<'p>( concat!("{} ", $s), fname.unwrap_or("function") $(,$arg)* )))) } - // Copy kwargs not to modify it - let kwargs = match kwargs { - Some(k) => Some(k.copy()?), - None => None, - }; + + // Copy unrecognised_kwargs not to modify it + let unrecognized_kwargs = kwargs.as_ref().map(|d| d.copy()).transpose()?; + // Iterate through the parameters and assign values to output: for (i, (p, out)) in params.iter().zip(output).enumerate() { *out = match kwargs.and_then(|d| d.get_item(p.name)) { @@ -60,7 +58,8 @@ pub fn parse_fn_args<'p>( if i < nargs { raise_error!("got multiple values for argument: {}", p.name) } - kwargs.as_ref().unwrap().del_item(p.name)?; + + unrecognized_kwargs.as_ref().unwrap().del_item(p.name)?; Some(kwarg) } None => { @@ -81,10 +80,13 @@ pub fn parse_fn_args<'p>( } } } + + let kwargs = unrecognized_kwargs; + let is_kwargs_empty = kwargs.as_ref().map_or(true, |dict| dict.is_empty()); // Raise an error when we get an unknown key if !accept_kwargs && !is_kwargs_empty { - let (key, _) = kwargs.unwrap().iter().next().unwrap(); + let (key, _) = kwargs.as_ref().unwrap().iter().next().unwrap(); raise_error!("got an unexpected keyword argument: {}", key) } // Raise an error when we get too many positional args @@ -98,17 +100,16 @@ pub fn parse_fn_args<'p>( } // Adjust the remaining args let args = if accept_args { - let py = args.py(); - let slice = args.slice(used_args as isize, nargs as isize).into_py(py); - py.checked_cast_as(slice).unwrap() + args.slice(used_args as isize, nargs as isize) } else { - args + args.clone() }; let kwargs = if accept_kwargs && is_kwargs_empty { None } else { kwargs }; + Ok((args, kwargs)) } @@ -151,7 +152,7 @@ impl ModuleDef { } let module = py.from_owned_ptr_or_err::(module)?; module.add("__doc__", doc)?; - initializer(py, module)?; + initializer(py, &module)?; Ok(crate::IntoPyPointer::into_ptr(module)) } } @@ -179,17 +180,17 @@ impl> IntoPyResult for PyResult { /// Variant of IntoPyResult for the specific case of `#[new]`. In the case of returning (Sub, Base) /// from `#[new]`, IntoPyResult can't apply because (Sub, Base) doesn't implement IntoPy. -pub trait IntoPyNewResult>> { +pub trait IntoPyNewResult<'py, T: PyClass<'py>, I: Into>> { fn into_pynew_result(self) -> PyResult; } -impl>> IntoPyNewResult for I { +impl<'py, T: PyClass<'py>, I: Into>> IntoPyNewResult<'py, T, I> for I { fn into_pynew_result(self) -> PyResult { Ok(self) } } -impl>> IntoPyNewResult for PyResult { +impl<'py, T: PyClass<'py>, I: Into>> IntoPyNewResult<'py, T, I> for PyResult { fn into_pynew_result(self) -> PyResult { self } @@ -223,29 +224,29 @@ impl GetPropertyValue for Py { /// Utilities for basetype #[doc(hidden)] -pub trait PyBaseTypeUtils { +pub trait PyBaseTypeUtils<'py> { type Dict; type WeakRef; type LayoutAsBase; - type BaseNativeType; + type RootType; } -impl PyBaseTypeUtils for T { +impl<'py, T: PyClass<'py>> PyBaseTypeUtils<'py> for T { type Dict = T::Dict; type WeakRef = T::WeakRef; - type LayoutAsBase = crate::pycell::PyCellInner; - type BaseNativeType = T::BaseNativeType; + type LayoutAsBase = crate::pycell::PyCellInner<'py, T>; + type RootType = T::BaseNativeType; } /// Utility trait to enable &PyClass as a pymethod/function argument #[doc(hidden)] -pub trait ExtractExt<'a> { - type Target: crate::FromPyObject<'a>; +pub trait ExtractExt<'a, 'py> { + type Target: crate::FromPyObject<'a, 'py>; } -impl<'a, T> ExtractExt<'a> for T +impl<'a, 'py, T> ExtractExt<'a, 'py> for T where - T: crate::FromPyObject<'a>, + T: crate::FromPyObject<'a, 'py>, { type Target = T; } @@ -255,19 +256,19 @@ where /// This serves to unify the use of `PyRef` and `PyRefMut` in automatically /// derived code, since both types can be obtained from a `PyCell`. #[doc(hidden)] -pub trait TryFromPyCell<'a, T: PyClass>: Sized { +pub trait TryFromPyCell<'a, 'py: 'a, T: PyClass<'py>>: Sized { type Error: Into; - fn try_from_pycell(cell: &'a crate::PyCell) -> Result; + fn try_from_pycell(cell: &'a crate::PyCell<'py, T>) -> Result; } -impl<'a, T, R> TryFromPyCell<'a, T> for R +impl<'a, 'py: 'a, T, R> TryFromPyCell<'a, 'py, T> for R where - T: 'a + PyClass, - R: std::convert::TryFrom<&'a PyCell>, + T: 'py + PyClass<'py>, + R: std::convert::TryFrom<&'a PyCell<'py, T>>, R::Error: Into, { type Error = R::Error; - fn try_from_pycell(cell: &'a crate::PyCell) -> Result { - >>::try_from(cell) + fn try_from_pycell(cell: &'a crate::PyCell<'py, T>) -> Result { + >>::try_from(cell) } } diff --git a/src/err.rs b/src/err.rs index 2cdfcac32c2..1b45daace7f 100644 --- a/src/err.rs +++ b/src/err.rs @@ -2,6 +2,7 @@ use crate::type_object::PyTypeObject; use crate::types::PyType; +use crate::type_marker::Type; use crate::{exceptions, ffi}; use crate::{ AsPyPointer, FromPy, IntoPy, IntoPyPointer, Py, PyAny, PyObject, Python, ToBorrowedObject, @@ -37,7 +38,7 @@ impl PyErrValue { /// Represents a Python exception that was raised. pub struct PyErr { /// The type of the exception. This should be either a `PyClass` or a `PyType`. - pub ptype: Py, + pub ptype: Py, /// The value of the exception. /// @@ -102,7 +103,7 @@ impl PyErr { /// `exc` is the exception type; usually one of the standard exceptions /// like `exceptions::RuntimeError`. /// `args` is the a tuple of arguments to pass to the exception constructor. - pub fn from_type(exc: Py, args: A) -> PyErr + pub fn from_type(exc: Py, args: A) -> PyErr where A: ToPyObject + 'static, { @@ -140,7 +141,7 @@ impl PyErr { if unsafe { ffi::PyExceptionInstance_Check(ptr) } != 0 { PyErr { ptype: unsafe { Py::from_borrowed_ptr(ffi::PyExceptionInstance_Class(ptr)) }, - pvalue: PyErrValue::Value(obj.into()), + pvalue: PyErrValue::Value(obj.clone().into()), ptraceback: None, } } else if unsafe { ffi::PyExceptionClass_Check(obj.as_ptr()) } != 0 { diff --git a/src/exceptions.rs b/src/exceptions.rs index 4d7d476840d..ceae83d0cfb 100644 --- a/src/exceptions.rs +++ b/src/exceptions.rs @@ -2,12 +2,13 @@ //! Exception types defined by Python. +use crate::conversion::AsPyPointer; use crate::err::{PyErr, PyResult}; use crate::ffi; use crate::type_object::PyTypeObject; use crate::types::{PyAny, PyTuple}; use crate::Python; -use crate::{AsPyPointer, ToPyObject}; +use crate::ToPyObject; use std::ffi::CStr; use std::ops; use std::os::raw::c_char; @@ -89,7 +90,7 @@ macro_rules! import_exception { macro_rules! import_exception_type_object { ($module: expr, $name: ident) => { unsafe impl $crate::type_object::PyTypeObject for $name { - fn type_object() -> $crate::Py<$crate::types::PyType> { + fn type_object() -> $crate::Py<$crate::type_marker::Type> { use $crate::type_object::LazyHeapType; static TYPE_OBJECT: LazyHeapType = LazyHeapType::new(); @@ -173,7 +174,7 @@ macro_rules! create_exception { macro_rules! create_exception_type_object { ($module: ident, $name: ident, $base: ty) => { unsafe impl $crate::type_object::PyTypeObject for $name { - fn type_object() -> $crate::Py<$crate::types::PyType> { + fn type_object() -> $crate::Py<$crate::type_marker::Type> { use $crate::type_object::LazyHeapType; static TYPE_OBJECT: LazyHeapType = LazyHeapType::new(); @@ -215,7 +216,7 @@ macro_rules! impl_native_exception ( } } unsafe impl PyTypeObject for $name { - fn type_object() -> $crate::Py<$crate::types::PyType> { + fn type_object() -> $crate::Py<$crate::type_marker::Type> { unsafe { $crate::Py::from_borrowed_ptr(ffi::$exc_name) } } } @@ -291,7 +292,7 @@ impl UnicodeDecodeError { input: &[u8], range: ops::Range, reason: &CStr, - ) -> PyResult<&'p PyAny> { + ) -> PyResult> { unsafe { let input: &[c_char] = &*(input as *const [u8] as *const [c_char]); py.from_owned_ptr_or_err(ffi::PyUnicodeDecodeError_Create( @@ -310,7 +311,7 @@ impl UnicodeDecodeError { py: Python<'p>, input: &[u8], err: std::str::Utf8Error, - ) -> PyResult<&'p PyAny> { + ) -> PyResult> { let pos = err.valid_up_to(); UnicodeDecodeError::new_err( py, @@ -380,7 +381,7 @@ mod test { .map_err(|e| e.print(py)) .expect("could not setitem"); - py.run("assert isinstance(exc, socket.gaierror)", None, Some(d)) + py.run("assert isinstance(exc, socket.gaierror)", None, Some(&d)) .map_err(|e| e.print(py)) .expect("assertion failed"); } @@ -407,7 +408,7 @@ mod test { py.run( "assert isinstance(exc, email.errors.MessageError)", None, - Some(d), + Some(&d), ) .map_err(|e| e.print(py)) .expect("assertion failed"); diff --git a/src/freelist.rs b/src/freelist.rs index d3a4ae4e413..8e52c971c84 100644 --- a/src/freelist.rs +++ b/src/freelist.rs @@ -4,7 +4,8 @@ use crate::ffi; use crate::pyclass::{tp_free_fallback, PyClassAlloc}; -use crate::type_object::{PyLayout, PyTypeInfo}; +use crate::type_object::PyLayout; +use crate::type_marker::TypeWithBase; use crate::Python; use std::mem; use std::os::raw::c_void; @@ -68,13 +69,13 @@ impl FreeList { } } -impl PyClassAlloc for T +impl<'py, T> PyClassAlloc<'py> for T where - T: PyTypeInfo + PyClassWithFreeList, + T: TypeWithBase<'py> + PyClassWithFreeList, { unsafe fn alloc(_py: Python) -> *mut Self::Layout { if let Some(obj) = ::get_free_list().pop() { - ffi::PyObject_Init(obj, ::type_object() as *const _ as _); + ffi::PyObject_Init(obj, Self::type_object() as *const _ as _); obj as _ } else { crate::pyclass::default_alloc::() as _ diff --git a/src/gil.rs b/src/gil.rs index 72ff1781adc..9ff43e43f49 100644 --- a/src/gil.rs +++ b/src/gil.rs @@ -394,7 +394,7 @@ mod test { { let gil = Python::acquire_gil(); let py = gil.python(); - let _ = gil::register_owned(py, obj.into_nonnull()); + let _ = gil::register_owned(py, obj.into_non_null()); assert_eq!(ffi::Py_REFCNT(obj_ptr), 2); assert_eq!(p.owned.len(), 1); @@ -423,14 +423,14 @@ mod test { let _pool = GILPool::new(); assert_eq!(p.owned.len(), 0); - let _ = gil::register_owned(py, obj.into_nonnull()); + let _ = gil::register_owned(py, obj.into_non_null()); assert_eq!(p.owned.len(), 1); assert_eq!(ffi::Py_REFCNT(obj_ptr), 2); { let _pool = GILPool::new(); let obj = get_object(); - let _ = gil::register_owned(py, obj.into_nonnull()); + let _ = gil::register_owned(py, obj.into_non_null()); assert_eq!(p.owned.len(), 2); } assert_eq!(p.owned.len(), 1); diff --git a/src/instance.rs b/src/instance.rs index 8afaa6f2dbb..21cced64c88 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -1,12 +1,12 @@ // Copyright (c) 2017-present PyO3 Project and Contributors -use crate::err::{PyErr, PyResult}; +use crate::err::{PyErr, PyResult, PyDowncastError}; use crate::gil; use crate::object::PyObject; -use crate::objectprotocol::ObjectProtocol; use crate::type_object::{PyBorrowFlagLayout, PyDowncastImpl}; +use crate::type_marker::TypeMarker; use crate::{ - ffi, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, PyAny, PyCell, PyClass, - PyClassInitializer, PyRef, PyRefMut, PyTypeInfo, Python, ToPyObject, + ffi, AsPyPointer, IntoPy, IntoPyPointer, PyCell, PyClass, + PyClassInitializer, PyRef, PyRefMut, Python, ToPyObject, PyAny, FromPyObject, FromPyPointer }; use std::marker::PhantomData; use std::mem; @@ -17,8 +17,8 @@ use std::ptr::NonNull; /// PyO3 is designed in a way that all references to those types are bound /// to the GIL, which is why you can get a token from all references of those /// types. -pub unsafe trait PyNativeType: Sized { - fn py(&self) -> Python { +pub unsafe trait PyNativeType<'p>: Sized { + fn py(&self) -> Python<'p> { unsafe { Python::assume_gil_acquired() } } } @@ -35,7 +35,7 @@ pub unsafe trait PyNativeType: Sized { /// specified type information. #[derive(Debug)] #[repr(transparent)] -pub struct Py(NonNull, PhantomData); +pub struct Py(NonNull, PhantomData); unsafe impl Send for Py {} @@ -47,10 +47,10 @@ impl Py { /// This method is **soft-duplicated** since PyO3 0.9.0. /// Use [`PyCell::new`](../pycell/struct.PyCell.html#method.new) and /// `Py::from` instead. - pub fn new(py: Python, value: impl Into>) -> PyResult> + pub fn new<'py>(py: Python<'py>, value: impl Into>) -> PyResult> where - T: PyClass, - T::BaseLayout: PyBorrowFlagLayout, + T: PyClass<'py>, + T::BaseLayout: PyBorrowFlagLayout<'py, T::BaseType>, { let initializer = value.into(); let obj = unsafe { initializer.create_cell(py)? }; @@ -164,20 +164,21 @@ impl Py { /// let py = gil.python(); /// assert_eq!(obj.as_ref(py).len().unwrap(), 0); // PyAny implements ObjectProtocol /// ``` -pub trait AsPyRef: Sized { - type Target; +pub trait AsPyRef<'py>: Sized { + type Target: 'py; /// Return reference to object. - fn as_ref<'p>(&'p self, py: Python<'p>) -> &'p Self::Target; + fn as_ref<'a>(&'a self, py: Python<'py>) -> &'a Self::Target where 'py: 'a; } -impl AsPyRef for Py +impl<'py, T> AsPyRef<'py> for Py where - T: PyTypeInfo, + T: TypeMarker<'py> { - type Target = T::AsRefTarget; - fn as_ref<'p>(&'p self, _py: Python<'p>) -> &'p Self::Target { - let any = self as *const Py as *const PyAny; - unsafe { PyDowncastImpl::unchecked_downcast(&*any) } + type Target = T::NativeType; + fn as_ref<'a>(&'a self, _py: Python<'py>) -> &'a Self::Target + where 'py: 'a + { + unsafe { PyDowncastImpl::unchecked_downcast(std::mem::transmute(self)) } } } @@ -193,7 +194,7 @@ impl IntoPy for Py { /// Consumes `self` without calling `Py_DECREF()`. #[inline] fn into_py(self, _py: Python) -> PyObject { - unsafe { PyObject::from_not_null(self.into_non_null()) } + unsafe { PyObject::from_non_null(self.into_non_null()) } } } @@ -217,7 +218,7 @@ impl IntoPyPointer for Py { // Native types `&T` can be converted to `Py` impl<'a, T> std::convert::From<&'a T> for Py where - T: AsPyPointer + PyNativeType, + T: AsPyPointer + PyNativeType<'a>, { fn from(obj: &'a T) -> Self { unsafe { Py::from_borrowed_ptr(obj.as_ptr()) } @@ -225,29 +226,29 @@ where } // `&PyCell` can be converted to `Py` -impl<'a, T> std::convert::From<&PyCell> for Py +impl<'py, T> std::convert::From<&PyCell<'py, T>> for Py where - T: PyClass, + T: PyClass<'py>, { - fn from(cell: &PyCell) -> Self { + fn from(cell: &PyCell<'py, T>) -> Self { unsafe { Py::from_borrowed_ptr(cell.as_ptr()) } } } -impl<'a, T> std::convert::From> for Py +impl<'py, T> std::convert::From> for Py where - T: PyClass, + T: PyClass<'py>, { - fn from(pyref: PyRef<'a, T>) -> Self { + fn from(pyref: PyRef<'_, 'py, T>) -> Self { unsafe { Py::from_borrowed_ptr(pyref.as_ptr()) } } } -impl<'a, T> std::convert::From> for Py +impl<'py, T> std::convert::From> for Py where - T: PyClass, + T: PyClass<'py>, { - fn from(pyref: PyRefMut<'a, T>) -> Self { + fn from(pyref: PyRefMut<'_, 'py, T>) -> Self { unsafe { Py::from_borrowed_ptr(pyref.as_ptr()) } } } @@ -271,39 +272,23 @@ impl Drop for Py { impl std::convert::From> for PyObject { #[inline] fn from(ob: Py) -> Self { - unsafe { PyObject::from_not_null(ob.into_non_null()) } - } -} - -impl<'a, T> std::convert::From<&'a T> for PyObject -where - T: AsPyPointer, -{ - fn from(ob: &'a T) -> Self { - unsafe { Py::::from_borrowed_ptr(ob.as_ptr()) }.into() + unsafe { PyObject::from_non_null(ob.into_non_null()) } } } -impl<'a, T> std::convert::From<&'a mut T> for PyObject +impl<'py, T> FromPyObject<'_, 'py> for Py where - T: AsPyPointer, -{ - fn from(ob: &'a mut T) -> Self { - unsafe { Py::::from_borrowed_ptr(ob.as_ptr()) }.into() - } -} - -impl<'a, T> FromPyObject<'a> for Py -where - T: PyTypeInfo, - &'a T::AsRefTarget: FromPyObject<'a>, - T::AsRefTarget: 'a + AsPyPointer, + T: TypeMarker<'py>, + T::NativeType: 'py + FromPyPointer<'py> + AsPyPointer, { /// Extracts `Self` from the source `PyObject`. - fn extract(ob: &'a PyAny) -> PyResult { + fn extract(ob: &PyAny<'py>) -> PyResult { unsafe { - ob.extract::<&T::AsRefTarget>() - .map(|val| Py::from_borrowed_ptr(val.as_ptr())) + if T::is_instance(ob) { + Ok(Py::from_borrowed_ptr(ob.as_ptr())) + } else { + Err(PyDowncastError.into()) + } } } } @@ -431,7 +416,7 @@ mod test { let py = gil.python(); let native = PyDict::new(py); let ref_count = unsafe { ffi::Py_REFCNT(native.as_ptr()) }; - let borrowed = ManagedPyRef::from_to_pyobject(py, native); + let borrowed = ManagedPyRef::from_to_pyobject(py, &native); assert_eq!(native.as_ptr(), borrowed.data); assert_eq!(ref_count, unsafe { ffi::Py_REFCNT(borrowed.data) }); drop(borrowed); diff --git a/src/lib.rs b/src/lib.rs index 883b43622dc..3f067659cc7 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -195,6 +195,7 @@ pub mod pyclass; pub mod pyclass_init; pub mod pyclass_slots; mod python; +pub mod type_marker; pub mod type_object; pub mod types; @@ -297,7 +298,7 @@ macro_rules! py_run_impl { use pyo3::ToPyObject; let d = [$((stringify!($val), $val.to_object($py)),)+].into_py_dict($py); - $py.run($code, None, Some(d)) + $py.run($code, None, Some(&d)) .map_err(|e| { e.print($py); // So when this c api function the last line called printed the error to stderr, diff --git a/src/marshal.rs b/src/marshal.rs index d0c7350b912..7150fbedd2f 100644 --- a/src/marshal.rs +++ b/src/marshal.rs @@ -27,7 +27,7 @@ pub const VERSION: i32 = 4; /// /// let bytes = marshal::dumps(py, dict, marshal::VERSION); /// ``` -pub fn dumps<'a>(py: Python<'a>, object: &impl AsPyPointer, version: i32) -> PyResult<&'a PyBytes> { +pub fn dumps<'py>(py: Python<'py>, object: &impl AsPyPointer, version: i32) -> PyResult> { unsafe { let bytes = ffi::PyMarshal_WriteObjectToString(object.as_ptr(), version as c_int); FromPyPointer::from_owned_ptr_or_err(py, bytes) @@ -35,7 +35,7 @@ pub fn dumps<'a>(py: Python<'a>, object: &impl AsPyPointer, version: i32) -> PyR } /// Deserialize an object from bytes using the Python built-in marshal module. -pub fn loads<'a, B>(py: Python<'a>, data: &B) -> PyResult<&'a PyAny> +pub fn loads<'py, B>(py: Python<'py>, data: &B) -> PyResult> where B: AsRef<[u8]> + ?Sized, { @@ -62,12 +62,12 @@ mod test { dict.set_item("mies", "wim").unwrap(); dict.set_item("zus", "jet").unwrap(); - let bytes = dumps(py, dict, VERSION) - .expect("marshalling failed") - .as_bytes(); - let deserialzed = loads(py, bytes).expect("unmarshalling failed"); + let bytes = dumps(py, &dict, VERSION) + .expect("marshalling failed"); - assert!(equal(py, dict, deserialzed)); + let deserialized = loads(py, bytes.as_bytes()).expect("unmarshalling failed"); + + assert!(equal(py, &*dict, &deserialized)); } fn equal(_py: Python, a: &impl AsPyPointer, b: &impl AsPyPointer) -> bool { diff --git a/src/object.rs b/src/object.rs index 642c94c48c4..e6e3a094b9d 100644 --- a/src/object.rs +++ b/src/object.rs @@ -4,7 +4,8 @@ use crate::err::{PyDowncastError, PyErr, PyResult}; use crate::ffi; use crate::gil; use crate::instance::{AsPyRef, PyNativeType}; -use crate::types::{PyAny, PyDict, PyTuple}; +use crate::types::{PyAny, PyDict}; +use crate::type_marker::Tuple; use crate::{AsPyPointer, Py, Python}; use crate::{FromPyObject, IntoPy, IntoPyPointer, PyTryFrom, ToBorrowedObject, ToPyObject}; use std::ptr::NonNull; @@ -28,11 +29,11 @@ unsafe impl Sync for PyObject {} impl PyObject { /// For internal conversions - pub(crate) unsafe fn from_not_null(ptr: NonNull) -> PyObject { + pub(crate) unsafe fn from_non_null(ptr: NonNull) -> PyObject { PyObject(ptr) } - pub(crate) unsafe fn into_nonnull(self) -> NonNull { + pub(crate) unsafe fn into_non_null(self) -> NonNull { let res = self.0; std::mem::forget(self); // Avoid Drop res @@ -156,9 +157,9 @@ impl PyObject { /// Casts the PyObject to a concrete Python object type. /// /// This can cast only to native Python types, not types implemented in Rust. - pub fn cast_as<'p, D>(&'p self, py: Python<'p>) -> Result<&'p D, PyDowncastError> + pub fn cast_as<'a, 'py: 'a, D>(&'a self, py: Python<'py>) -> Result<&'a D, PyDowncastError> where - D: PyTryFrom<'p>, + D: PyTryFrom<'py> { D::try_from(self.as_ref(py)) } @@ -166,9 +167,9 @@ impl PyObject { /// Extracts some type from the Python object. /// /// This is a wrapper function around `FromPyObject::extract()`. - pub fn extract<'p, D>(&'p self, py: Python<'p>) -> PyResult + pub fn extract<'a, 'py: 'a, D>(&'a self, py: Python<'py>) -> PyResult where - D: FromPyObject<'p>, + D: FromPyObject<'a, 'py> { FromPyObject::extract(self.as_ref(py)) } @@ -191,7 +192,7 @@ impl PyObject { pub fn call( &self, py: Python, - args: impl IntoPy>, + args: impl IntoPy>, kwargs: Option<&PyDict>, ) -> PyResult { let args = args.into_py(py).into_ptr(); @@ -209,7 +210,7 @@ impl PyObject { /// Calls the object with only positional arguments. /// /// This is equivalent to the Python expression `self(*args)`. - pub fn call1(&self, py: Python, args: impl IntoPy>) -> PyResult { + pub fn call1(&self, py: Python, args: impl IntoPy>) -> PyResult { self.call(py, args, None) } @@ -227,7 +228,7 @@ impl PyObject { &self, py: Python, name: &str, - args: impl IntoPy>, + args: impl IntoPy>, kwargs: Option<&PyDict>, ) -> PyResult { name.with_borrowed_ptr(py, |name| unsafe { @@ -252,7 +253,7 @@ impl PyObject { &self, py: Python, name: &str, - args: impl IntoPy>, + args: impl IntoPy>, ) -> PyResult { self.call_method(py, name, args, None) } @@ -265,10 +266,21 @@ impl PyObject { } } -impl AsPyRef for PyObject { - type Target = PyAny; - fn as_ref<'p>(&'p self, _py: Python<'p>) -> &'p PyAny { - unsafe { &*(self as *const _ as *const PyAny) } +impl<'a, 'py, T> std::convert::From for PyObject +where + T: IntoPyPointer + PyNativeType<'py> +{ + fn from(ob: T) -> Self { + unsafe { PyObject::from_non_null(NonNull::new(ob.into_ptr()).expect("Null ptr")) } + } +} + +impl<'py> AsPyRef<'py> for PyObject { + type Target = PyAny<'py>; + fn as_ref<'a>(&'a self, _py: Python<'py>) -> &'a PyAny<'py> + where 'py: 'a + { + unsafe { std::mem::transmute(self) } } } @@ -306,10 +318,10 @@ impl PartialEq for PyObject { } } -impl<'a> FromPyObject<'a> for PyObject { +impl<'py> FromPyObject<'_, 'py> for PyObject { #[inline] /// Extracts `Self` from the source `PyObject`. - fn extract(ob: &'a PyAny) -> PyResult { + fn extract(ob: &PyAny<'py>) -> PyResult { unsafe { Ok(PyObject::from_borrowed_ptr(ob.py(), ob.as_ptr())) } } } diff --git a/src/objectprotocol.rs b/src/objectprotocol.rs index 04a70d4bada..e8ed12fc80e 100644 --- a/src/objectprotocol.rs +++ b/src/objectprotocol.rs @@ -3,7 +3,8 @@ use crate::class::basic::CompareOp; use crate::err::{self, PyDowncastError, PyErr, PyResult}; use crate::exceptions::TypeError; -use crate::types::{PyAny, PyDict, PyIterator, PyString, PyTuple, PyType}; +use crate::types::{PyAny, PyDict, PyIterator, PyString, PyType}; +use crate::type_marker::Tuple; use crate::{ ffi, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, Py, PyNativeType, PyObject, PyTryFrom, Python, ToBorrowedObject, ToPyObject, @@ -12,7 +13,7 @@ use std::cmp::Ordering; use std::os::raw::c_int; /// Python object model helper methods -pub trait ObjectProtocol { +pub trait ObjectProtocol<'py> { /// Determines whether this object has the given attribute. /// /// This is equivalent to the Python expression `hasattr(self, attr_name)`. @@ -23,7 +24,7 @@ pub trait ObjectProtocol { /// Retrieves an attribute value. /// /// This is equivalent to the Python expression `self.attr_name`. - fn getattr(&self, attr_name: N) -> PyResult<&PyAny> + fn getattr(&self, attr_name: N) -> PyResult> where N: ToPyObject; @@ -76,12 +77,12 @@ pub trait ObjectProtocol { /// Computes the "repr" representation of self. /// /// This is equivalent to the Python expression `repr(self)`. - fn repr(&self) -> PyResult<&PyString>; + fn repr(&self) -> PyResult>; /// Computes the "str" representation of self. /// /// This is equivalent to the Python expression `str(self)`. - fn str(&self) -> PyResult<&PyString>; + fn str(&self) -> PyResult>; /// Determines whether this object is callable. fn is_callable(&self) -> bool; @@ -89,17 +90,17 @@ pub trait ObjectProtocol { /// Calls the object. /// /// This is equivalent to the Python expression `self(*args, **kwargs)`. - fn call(&self, args: impl IntoPy>, kwargs: Option<&PyDict>) -> PyResult<&PyAny>; + fn call(&self, args: impl IntoPy>, kwargs: Option<&PyDict>) -> PyResult>; /// Calls the object with only positional arguments. /// /// This is equivalent to the Python expression `self(*args)`. - fn call1(&self, args: impl IntoPy>) -> PyResult<&PyAny>; + fn call1(&self, args: impl IntoPy>) -> PyResult>; /// Calls the object without arguments. /// /// This is equivalent to the Python expression `self()`. - fn call0(&self) -> PyResult<&PyAny>; + fn call0(&self) -> PyResult>; /// Calls a method on the object. /// @@ -120,19 +121,19 @@ pub trait ObjectProtocol { fn call_method( &self, name: &str, - args: impl IntoPy>, + args: impl IntoPy>, kwargs: Option<&PyDict>, - ) -> PyResult<&PyAny>; + ) -> PyResult>; /// Calls a method on the object with only positional arguments. /// /// This is equivalent to the Python expression `self.name(*args)`. - fn call_method1(&self, name: &str, args: impl IntoPy>) -> PyResult<&PyAny>; + fn call_method1(&self, name: &str, args: impl IntoPy>) -> PyResult>; /// Calls a method on the object without arguments. /// /// This is equivalent to the Python expression `self.name()`. - fn call_method0(&self, name: &str) -> PyResult<&PyAny>; + fn call_method0(&self, name: &str) -> PyResult>; /// Retrieves the hash code of the object. /// @@ -162,7 +163,7 @@ pub trait ObjectProtocol { /// Gets an item from the collections. /// /// This is equivalent to the Python expression `self[key]`. - fn get_item(&self, key: K) -> PyResult<&PyAny> + fn get_item(&self, key: K) -> PyResult> where K: ToBorrowedObject; @@ -185,10 +186,10 @@ pub trait ObjectProtocol { /// /// This is typically a new iterator but if the argument is an iterator, /// this returns itself. - fn iter(&self) -> PyResult; + fn iter(&self) -> PyResult>; /// Returns the Python type object for this object's type. - fn get_type(&self) -> &PyType; + fn get_type(&self) -> &PyType<'py>; /// Returns the Python type pointer for this object. fn get_type_ptr(&self) -> *mut ffi::PyTypeObject; @@ -198,16 +199,18 @@ pub trait ObjectProtocol { /// This can cast only to native Python types, not types implemented in Rust. fn cast_as<'a, D>(&'a self) -> Result<&'a D, PyDowncastError> where - D: PyTryFrom<'a>, - &'a PyAny: std::convert::From<&'a Self>; + 'py: 'a, + D: PyTryFrom<'py>, + Self: AsRef>; /// Extracts some type from the Python object. /// /// This is a wrapper function around `FromPyObject::extract()`. fn extract<'a, D>(&'a self) -> PyResult where - D: FromPyObject<'a>, - &'a PyAny: std::convert::From<&'a Self>; + 'py: 'a, + D: FromPyObject<'a, 'py>, + Self: AsRef>; /// Returns the reference count for the Python object. fn get_refcnt(&self) -> isize; @@ -217,9 +220,9 @@ pub trait ObjectProtocol { fn None(&self) -> PyObject; } -impl ObjectProtocol for T +impl<'py, T> ObjectProtocol<'py> for T where - T: PyNativeType + AsPyPointer, + T: PyNativeType<'py> + AsPyPointer, { fn hasattr(&self, attr_name: N) -> PyResult where @@ -230,7 +233,7 @@ where }) } - fn getattr(&self, attr_name: N) -> PyResult<&PyAny> + fn getattr(&self, attr_name: N) -> PyResult> where N: ToPyObject, { @@ -315,14 +318,14 @@ where } } - fn repr(&self) -> PyResult<&PyString> { + fn repr(&self) -> PyResult> { unsafe { self.py() .from_owned_ptr_or_err(ffi::PyObject_Repr(self.as_ptr())) } } - fn str(&self) -> PyResult<&PyString> { + fn str(&self) -> PyResult> { unsafe { self.py() .from_owned_ptr_or_err(ffi::PyObject_Str(self.as_ptr())) @@ -333,7 +336,7 @@ where unsafe { ffi::PyCallable_Check(self.as_ptr()) != 0 } } - fn call(&self, args: impl IntoPy>, kwargs: Option<&PyDict>) -> PyResult<&PyAny> { + fn call(&self, args: impl IntoPy>, kwargs: Option<&PyDict>) -> PyResult> { let args = args.into_py(self.py()).into_ptr(); let kwargs = kwargs.into_ptr(); let result = unsafe { @@ -347,20 +350,20 @@ where result } - fn call0(&self) -> PyResult<&PyAny> { + fn call0(&self) -> PyResult> { self.call((), None) } - fn call1(&self, args: impl IntoPy>) -> PyResult<&PyAny> { + fn call1(&self, args: impl IntoPy>) -> PyResult> { self.call(args, None) } fn call_method( &self, name: &str, - args: impl IntoPy>, + args: impl IntoPy>, kwargs: Option<&PyDict>, - ) -> PyResult<&PyAny> { + ) -> PyResult> { name.with_borrowed_ptr(self.py(), |name| unsafe { let py = self.py(); let ptr = ffi::PyObject_GetAttr(self.as_ptr(), name); @@ -378,11 +381,11 @@ where }) } - fn call_method0(&self, name: &str) -> PyResult<&PyAny> { + fn call_method0(&self, name: &str) -> PyResult> { self.call_method(name, (), None) } - fn call_method1(&self, name: &str, args: impl IntoPy>) -> PyResult<&PyAny> { + fn call_method1(&self, name: &str, args: impl IntoPy>) -> PyResult> { self.call_method(name, args, None) } @@ -421,7 +424,7 @@ where self.len().map(|l| l == 0) } - fn get_item(&self, key: K) -> PyResult<&PyAny> + fn get_item(&self, key: K) -> PyResult> where K: ToBorrowedObject, { @@ -452,11 +455,11 @@ where }) } - fn iter(&self) -> PyResult { + fn iter(&self) -> PyResult> { Ok(PyIterator::from_object(self.py(), self)?) } - fn get_type(&self) -> &PyType { + fn get_type(&self) -> &PyType<'py> { unsafe { PyType::from_type_ptr(self.py(), (*self.as_ptr()).ob_type) } } @@ -467,18 +470,20 @@ where fn cast_as<'a, D>(&'a self) -> Result<&'a D, PyDowncastError> where - D: PyTryFrom<'a>, - &'a PyAny: std::convert::From<&'a Self>, + 'py: 'a, + D: PyTryFrom<'py>, + Self: AsRef> { - D::try_from(self) + D::try_from(self.as_ref()) } fn extract<'a, D>(&'a self) -> PyResult where - D: FromPyObject<'a>, - &'a PyAny: std::convert::From<&'a T>, + 'py: 'a, + D: FromPyObject<'a, 'py>, + Self: AsRef>, { - FromPyObject::extract(self.into()) + FromPyObject::extract(self.as_ref()) } fn get_refcnt(&self) -> isize { @@ -534,7 +539,7 @@ mod test { let py = gil.python(); let list = vec![3, 6, 5, 4, 7].to_object(py); let dict = vec![("reverse", true)].into_py_dict(py); - list.call_method(py, "sort", (), Some(dict)).unwrap(); + list.call_method(py, "sort", (), Some(&dict)).unwrap(); assert_eq!(list.extract::>(py).unwrap(), vec![7, 6, 5, 4, 3]); } diff --git a/src/pycell.rs b/src/pycell.rs index 82dcf9bae18..6ffe647a794 100644 --- a/src/pycell.rs +++ b/src/pycell.rs @@ -1,43 +1,46 @@ //! Includes `PyCell` implementation. -use crate::conversion::{AsPyPointer, FromPyPointer, ToPyObject}; +use crate::conversion::{AsPyPointer, FromPyPointer}; use crate::pyclass_init::PyClassInitializer; use crate::pyclass_slots::{PyClassDict, PyClassWeakRef}; -use crate::type_object::{PyBorrowFlagLayout, PyDowncastImpl, PyLayout, PySizedLayout, PyTypeInfo}; -use crate::{ffi, FromPy, PyAny, PyClass, PyErr, PyNativeType, PyObject, PyResult, Python}; -use std::cell::{Cell, UnsafeCell}; +use crate::type_marker::TypeMarker; +use crate::type_object::{PyBorrowFlagLayout, PyDowncastImpl, PyLayout, PySizedLayout}; +use crate::{gil, ffi, FromPy, PyAny, PyClass, PyErr, PyObject, PyResult, Python}; +use std::cell::{Cell, UnsafeCell, RefCell}; use std::fmt; +use std::marker::PhantomData; use std::mem::ManuallyDrop; use std::ops::{Deref, DerefMut}; +use std::ptr::NonNull; /// Base layout of PyCell. /// This is necessary for sharing BorrowFlag between parents and children. #[doc(hidden)] #[repr(C)] -pub struct PyCellBase { +pub struct PyCellBase<'py, T: TypeMarker<'py>> { ob_base: T::Layout, borrow_flag: Cell, } -unsafe impl PyLayout for PyCellBase +unsafe impl<'py, T> PyLayout<'py, T> for PyCellBase<'py, T> where - T: PyTypeInfo + PyNativeType, - T::Layout: PySizedLayout, + T: TypeMarker<'py>, + T::Layout: PySizedLayout<'py, T>, { const IS_NATIVE_TYPE: bool = true; } // Thes impls ensures `PyCellBase` can be a base type. -impl PySizedLayout for PyCellBase +impl<'py, T> PySizedLayout<'py, T> for PyCellBase<'py, T> where - T: PyTypeInfo + PyNativeType, - T::Layout: PySizedLayout, + T: TypeMarker<'py>, + T::Layout: PySizedLayout<'py, T>, { } -unsafe impl PyBorrowFlagLayout for PyCellBase +unsafe impl<'py, T> PyBorrowFlagLayout<'py, T> for PyCellBase<'py, T> where - T: PyTypeInfo + PyNativeType, - T::Layout: PySizedLayout, + T: TypeMarker<'py>, + T::Layout: PySizedLayout<'py, T>, { } @@ -47,18 +50,18 @@ where /// 2. When `#[pyclass(extends=Base)]` is specified, `PyCellInner` is used as a base layout. #[doc(hidden)] #[repr(C)] -pub struct PyCellInner { +pub struct PyCellInner<'py, T: PyClass<'py>> { ob_base: T::BaseLayout, value: ManuallyDrop>, } -impl AsPyPointer for PyCellInner { +impl<'py, T: PyClass<'py>> AsPyPointer for PyCellInner<'py, T> { fn as_ptr(&self) -> *mut ffi::PyObject { (self as *const _) as *mut _ } } -unsafe impl PyLayout for PyCellInner { +unsafe impl<'py, T: PyClass<'py>> PyLayout<'py, T> for PyCellInner<'py, T> { const IS_NATIVE_TYPE: bool = false; fn get_super(&mut self) -> Option<&mut T::BaseLayout> { Some(&mut self.ob_base) @@ -73,22 +76,65 @@ unsafe impl PyLayout for PyCellInner { } // These impls ensures `PyCellInner` can be a base type. -impl PySizedLayout for PyCellInner {} -unsafe impl PyBorrowFlagLayout for PyCellInner {} +impl<'py, T: PyClass<'py>> PySizedLayout<'py, T> for PyCellInner<'py, T> {} +unsafe impl<'py, T: PyClass<'py>> PyBorrowFlagLayout<'py, T> for PyCellInner<'py, T> {} -impl PyCellInner { +impl<'py, T: PyClass<'py>> PyCellInner<'py, T> { unsafe fn get_ptr(&self) -> *mut T { self.value.get() } fn get_borrow_flag(&self) -> BorrowFlag { - let base = (&self.ob_base) as *const _ as *const PyCellBase; + let base = (&self.ob_base) as *const _ as *const PyCellBase; unsafe { (*base).borrow_flag.get() } } fn set_borrow_flag(&self, flag: BorrowFlag) { - let base = (&self.ob_base) as *const _ as *const PyCellBase; + let base = (&self.ob_base) as *const _ as *const PyCellBase; unsafe { (*base).borrow_flag.set(flag) } } } +#[repr(C)] +pub struct PyCellLayout<'py, T: PyClass<'py>> { + inner: PyCellInner<'py, T>, + dict: T::Dict, + weakref: T::WeakRef, +} + +impl<'py, T: PyClass<'py>> PyCellLayout<'py, T> { + /// Allocates new PyCell without initilizing value. + /// Requires `T::BaseLayout: PyBorrowFlagLayout` to ensure `self` has a borrow flag. + pub(crate) unsafe fn new(py: Python<'py>) -> PyResult<*mut Self> + where + T::BaseLayout: PyBorrowFlagLayout<'py, T::BaseType>, + { + let base = T::alloc(py); + if base.is_null() { + return Err(PyErr::fetch(py)); + } + let base = base as *mut PyCellBase; + (*base).borrow_flag = Cell::new(BorrowFlag::UNUSED); + let self_ = base as *mut Self; + (*self_).dict = T::Dict::new(); + (*self_).weakref = T::WeakRef::new(); + Ok(self_) + } +} + +unsafe impl<'py, T: PyClass<'py>> PyLayout<'py, T> for PyCellLayout<'py, T> { + const IS_NATIVE_TYPE: bool = false; + fn get_super(&mut self) -> Option<&mut T::BaseLayout> { + Some(&mut self.inner.ob_base) + } + unsafe fn py_init(&mut self, value: T) { + self.inner.value = ManuallyDrop::new(UnsafeCell::new(value)); + } + unsafe fn py_drop(&mut self, py: Python) { + ManuallyDrop::drop(&mut self.inner.value); + self.dict.clear_dict(py); + let ptr = self as *mut _ as _; + self.weakref.clear_weakrefs(ptr, py); + self.inner.ob_base.py_drop(py); + } +} /// `PyCell` is the container type for [`PyClass`](../pyclass/trait.PyClass.html). /// @@ -152,19 +198,18 @@ impl PyCellInner { /// # let counter = PyCell::new(py, Counter::default()).unwrap(); /// # pyo3::py_run!(py, counter, "assert counter.increment('cat') == 1"); /// ``` -#[repr(C)] -pub struct PyCell { - inner: PyCellInner, - dict: T::Dict, - weakref: T::WeakRef, -} +#[repr(transparent)] +pub struct PyCell<'py, T: PyClass<'py>>(PyAny<'py>, PhantomData>); + +crate::pyobject_native_type_common!(PyCell<'py, T: PyClass<'py>>); +crate::pyobject_native_type_extract!(PyCell<'py, T: PyClass<'py>>); -impl PyCell { +impl<'py, T: PyClass<'py>> PyCell<'py, T> { /// Make new `PyCell` on the Python heap and returns the reference of it. /// - pub fn new(py: Python, value: impl Into>) -> PyResult<&Self> + pub fn new(py: Python<'py>, value: impl Into>) -> PyResult where - T::BaseLayout: PyBorrowFlagLayout, + T::BaseLayout: PyBorrowFlagLayout<'py, T::BaseType>, { unsafe { let initializer = value.into(); @@ -179,7 +224,7 @@ impl PyCell { /// /// Panics if the value is currently mutably borrowed. For a non-panicking variant, use /// [`try_borrow`](#method.try_borrow). - pub fn borrow(&self) -> PyRef<'_, T> { + pub fn borrow(&self) -> PyRef<'_, 'py, T> { self.try_borrow().expect("Already mutably borrowed") } @@ -189,7 +234,7 @@ impl PyCell { /// /// Panics if the value is currently mutably borrowed. For a non-panicking variant, use /// [`try_borrow_mut`](#method.try_borrow_mut). - pub fn borrow_mut(&self) -> PyRefMut<'_, T> { + pub fn borrow_mut(&self) -> PyRefMut<'_, 'py, T> { self.try_borrow_mut().expect("Already borrowed") } @@ -217,13 +262,14 @@ impl PyCell { /// assert!(c.try_borrow().is_ok()); /// } /// ``` - pub fn try_borrow(&self) -> Result, PyBorrowError> { - let flag = self.inner.get_borrow_flag(); + pub fn try_borrow(&self) -> Result, PyBorrowError> { + let inner = self.inner(); + let flag = inner.get_borrow_flag(); if flag == BorrowFlag::HAS_MUTABLE_BORROW { Err(PyBorrowError { _private: () }) } else { - self.inner.set_borrow_flag(flag.increment()); - Ok(PyRef { inner: &self.inner }) + inner.set_borrow_flag(flag.increment()); + Ok(PyRef { inner: &inner }) } } @@ -248,12 +294,13 @@ impl PyCell { /// /// assert!(c.try_borrow_mut().is_ok()); /// ``` - pub fn try_borrow_mut(&self) -> Result, PyBorrowMutError> { - if self.inner.get_borrow_flag() != BorrowFlag::UNUSED { + pub fn try_borrow_mut(&self) -> Result, PyBorrowMutError> { + let inner = self.inner(); + if inner.get_borrow_flag() != BorrowFlag::UNUSED { Err(PyBorrowMutError { _private: () }) } else { - self.inner.set_borrow_flag(BorrowFlag::HAS_MUTABLE_BORROW); - Ok(PyRefMut { inner: &self.inner }) + inner.set_borrow_flag(BorrowFlag::HAS_MUTABLE_BORROW); + Ok(PyRefMut { inner: &inner }) } } @@ -287,10 +334,11 @@ impl PyCell { /// } /// ``` pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, PyBorrowError> { - if self.inner.get_borrow_flag() == BorrowFlag::HAS_MUTABLE_BORROW { + let inner = self.inner(); + if inner.get_borrow_flag() == BorrowFlag::HAS_MUTABLE_BORROW { Err(PyBorrowError { _private: () }) } else { - Ok(&*self.inner.value.get()) + Ok(&*inner.value.get()) } } @@ -325,64 +373,45 @@ impl PyCell { std::mem::swap(&mut *self.borrow_mut(), &mut *other.borrow_mut()) } - /// Allocates new PyCell without initilizing value. - /// Requires `T::BaseLayout: PyBorrowFlagLayout` to ensure `self` has a borrow flag. - pub(crate) unsafe fn internal_new(py: Python) -> PyResult<*mut Self> - where - T::BaseLayout: PyBorrowFlagLayout, - { - let base = T::alloc(py); - if base.is_null() { - return Err(PyErr::fetch(py)); - } - let base = base as *mut PyCellBase; - (*base).borrow_flag = Cell::new(BorrowFlag::UNUSED); - let self_ = base as *mut Self; - (*self_).dict = T::Dict::new(); - (*self_).weakref = T::WeakRef::new(); - Ok(self_) + #[inline] + fn inner(&self) -> &PyCellInner<'py, T> { + unsafe { &*(self.as_ptr() as *const PyCellInner) } } } -unsafe impl PyLayout for PyCell { - const IS_NATIVE_TYPE: bool = false; - fn get_super(&mut self) -> Option<&mut T::BaseLayout> { - Some(&mut self.inner.ob_base) - } - unsafe fn py_init(&mut self, value: T) { - self.inner.value = ManuallyDrop::new(UnsafeCell::new(value)); - } - unsafe fn py_drop(&mut self, py: Python) { - ManuallyDrop::drop(&mut self.inner.value); - self.dict.clear_dict(py); - self.weakref.clear_weakrefs(self.as_ptr(), py); - self.inner.ob_base.py_drop(py); +impl<'py, T: PyClass<'py>> ::std::convert::AsRef> for PyCell<'py, T> { + #[inline] + fn as_ref(&self) -> &PyAny<'py> { + &self.0 } } -unsafe impl PyDowncastImpl for PyCell { - unsafe fn unchecked_downcast(obj: &PyAny) -> &Self { - &*(obj.as_ptr() as *const Self) - } - private_impl! {} -} +impl<'py, T: PyClass<'py>> ::std::ops::Deref for PyCell<'py, T> { + type Target = PyAny<'py>; -impl AsPyPointer for PyCell { - fn as_ptr(&self) -> *mut ffi::PyObject { - self.inner.as_ptr() + #[inline] + fn deref(&self) -> &PyAny<'py> { + &self.0 } } -impl ToPyObject for &PyCell { - fn to_object(&self, py: Python<'_>) -> PyObject { - unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) } +unsafe impl<'py, T: PyClass<'py>> FromPyPointer<'py> for PyCell<'py, T> +{ + unsafe fn from_owned_ptr_or_opt(py: Python<'py>, ptr: *mut ffi::PyObject) -> Option { + NonNull::new(ptr).map(|p| Self(PyAny::from_non_null(py, p), PhantomData)) + } + unsafe fn from_borrowed_ptr_or_opt( + py: Python<'py>, + ptr: *mut ffi::PyObject, + ) -> Option<&'py Self> { + NonNull::new(ptr).map(|p| Self::unchecked_downcast(gil::register_borrowed(py, p))) } } -impl fmt::Debug for PyCell { +impl<'py, T: PyClass<'py> + fmt::Debug> fmt::Debug for PyCell<'py, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.try_borrow() { - Ok(borrow) => f.debug_struct("RefCell").field("value", &borrow).finish(), + Ok(borrow) => f.debug_struct("PyCell").field("value", &borrow).finish(), Err(_) => { struct BorrowedPlaceholder; impl fmt::Debug for BorrowedPlaceholder { @@ -390,7 +419,7 @@ impl fmt::Debug for PyCell { f.write_str("") } } - f.debug_struct("RefCell") + f.debug_struct("PyCell") .field("value", &BorrowedPlaceholder) .finish() } @@ -398,6 +427,12 @@ impl fmt::Debug for PyCell { } } +impl<'py, T: PyClass<'py>> Clone for PyCell<'py, T> { + fn clone(&self) -> Self { + Self(self.0.clone(), PhantomData) + } +} + /// Wraps a borrowed reference to a value in a `PyCell`. /// /// See the [`PyCell`](struct.PyCell.html) documentation for more. @@ -435,32 +470,32 @@ impl fmt::Debug for PyCell { /// # let sub = PyCell::new(py, Child::new()).unwrap(); /// # pyo3::py_run!(py, sub, "assert sub.format() == 'Caterpillar(base: Butterfly, cnt: 3)'"); /// ``` -pub struct PyRef<'p, T: PyClass> { - inner: &'p PyCellInner, +pub struct PyRef<'a, 'py, T: PyClass<'py>> { + inner: &'a PyCellInner<'py, T>, } -impl<'p, T: PyClass> PyRef<'p, T> { +impl<'py, T: PyClass<'py>> PyRef<'_, 'py, T> { /// Returns `Python` token. /// This function is safe since PyRef has the same lifetime as a `GILGuard`. - pub fn py(&self) -> Python { + pub fn py(&self) -> Python<'py> { unsafe { Python::assume_gil_acquired() } } } -impl<'p, T, U> AsRef for PyRef<'p, T> +impl<'py, T, U> AsRef for PyRef<'_, 'py, T> where - T: PyClass + PyTypeInfo>, - U: PyClass, + T: PyClass<'py, BaseType = U, BaseLayout = PyCellInner<'py, U>, BaseInitializer = U::Initializer>, + U: PyClass<'py>, { - fn as_ref(&self) -> &T::BaseType { + fn as_ref(&self) -> &U { unsafe { &*self.inner.ob_base.get_ptr() } } } -impl<'p, T, U> PyRef<'p, T> +impl<'a, 'py, T, U> PyRef<'a, 'py, T> where - T: PyClass + PyTypeInfo>, - U: PyClass, + T: PyClass<'py, BaseType = U, BaseLayout = PyCellInner<'py, U>, BaseInitializer = U::Initializer>, + U: PyClass<'py>, { /// Get `PyRef`. /// You can use this method to get super class of super class. @@ -499,7 +534,7 @@ where /// # let sub = PyCell::new(py, Sub::new()).unwrap(); /// # pyo3::py_run!(py, sub, "assert sub.name() == 'base1 base2 sub'") /// ``` - pub fn into_super(self) -> PyRef<'p, U> { + pub fn into_super(self) -> PyRef<'a, 'py, U> { let PyRef { inner } = self; std::mem::forget(self); PyRef { @@ -508,7 +543,7 @@ where } } -impl<'p, T: PyClass> Deref for PyRef<'p, T> { +impl<'py, T: PyClass<'py>> Deref for PyRef<'_, 'py, T> { type Target = T; #[inline] @@ -517,33 +552,33 @@ impl<'p, T: PyClass> Deref for PyRef<'p, T> { } } -impl<'p, T: PyClass> Drop for PyRef<'p, T> { +impl<'py, T: PyClass<'py>> Drop for PyRef<'_, 'py, T> { fn drop(&mut self) { let flag = self.inner.get_borrow_flag(); self.inner.set_borrow_flag(flag.decrement()) } } -impl<'p, T: PyClass> FromPy> for PyObject { - fn from_py(pyref: PyRef<'p, T>, py: Python<'_>) -> PyObject { +impl<'py, T: PyClass<'py>> FromPy> for PyObject { + fn from_py(pyref: PyRef<'_, 'py, T>, py: Python<'_>) -> PyObject { unsafe { PyObject::from_borrowed_ptr(py, pyref.inner.as_ptr()) } } } -impl<'a, T: PyClass> std::convert::TryFrom<&'a PyCell> for crate::PyRef<'a, T> { +impl<'a, 'py, T: PyClass<'py>> std::convert::TryFrom<&'a PyCell<'py, T>> for PyRef<'a, 'py, T> { type Error = PyBorrowError; - fn try_from(cell: &'a crate::PyCell) -> Result { + fn try_from(cell: &'a PyCell<'py, T>) -> Result { cell.try_borrow() } } -impl<'a, T: PyClass> AsPyPointer for PyRef<'a, T> { +impl<'a, 'py, T: PyClass<'py>> AsPyPointer for PyRef<'a, 'py, T> { fn as_ptr(&self) -> *mut ffi::PyObject { self.inner.as_ptr() } } -impl fmt::Debug for PyRef<'_, T> { +impl<'py, T: PyClass<'py> + fmt::Debug> fmt::Debug for PyRef<'_, 'py, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } @@ -552,46 +587,46 @@ impl fmt::Debug for PyRef<'_, T> { /// Wraps a mutable borrowed reference to a value in a `PyCell`. /// /// See the [`PyCell`](struct.PyCell.html) and [`PyRef`](struct.PyRef.html) documentations for more. -pub struct PyRefMut<'p, T: PyClass> { - inner: &'p PyCellInner, +pub struct PyRefMut<'a, 'py, T: PyClass<'py>> { + inner: &'a PyCellInner<'py, T>, } -impl<'p, T: PyClass> PyRefMut<'p, T> { +impl<'py, T: PyClass<'py>> PyRefMut<'_, 'py, T> { /// Returns `Python` token. /// This function is safe since PyRefMut has the same lifetime as a `GILGuard`. - pub fn py(&self) -> Python { + pub fn py(&self) -> Python<'py> { unsafe { Python::assume_gil_acquired() } } } -impl<'p, T, U> AsRef for PyRefMut<'p, T> +impl<'py, T, U> AsRef for PyRefMut<'_, 'py, T> where - T: PyClass + PyTypeInfo>, - U: PyClass, + T: PyClass<'py, BaseType = U, BaseLayout = PyCellInner<'py, U>, BaseInitializer = U::Initializer>, + U: PyClass<'py>, { fn as_ref(&self) -> &T::BaseType { unsafe { &*self.inner.ob_base.get_ptr() } } } -impl<'p, T, U> AsMut for PyRefMut<'p, T> +impl<'py, T, U> AsMut for PyRefMut<'_, 'py, T> where - T: PyClass + PyTypeInfo>, - U: PyClass, +T: PyClass<'py, BaseType = U, BaseLayout = PyCellInner<'py, U>, BaseInitializer = U::Initializer>, +U: PyClass<'py>, { fn as_mut(&mut self) -> &mut T::BaseType { unsafe { &mut *self.inner.ob_base.get_ptr() } } } -impl<'p, T, U> PyRefMut<'p, T> +impl<'a, 'py, T, U> PyRefMut<'a, 'py, T> where - T: PyClass + PyTypeInfo>, - U: PyClass, + T: PyClass<'py, BaseType = U, BaseLayout = PyCellInner<'py, U>, BaseInitializer = U::Initializer>, + U: PyClass<'py>, { /// Get `PyRef`. /// See [`PyRef::into_super`](struct.PyRef.html#method.into_super) for more. - pub fn into_super(self) -> PyRefMut<'p, U> { + pub fn into_super(self) -> PyRefMut<'a, 'py, U> { let PyRefMut { inner } = self; std::mem::forget(self); PyRefMut { @@ -600,7 +635,7 @@ where } } -impl<'p, T: PyClass> Deref for PyRefMut<'p, T> { +impl<'py, T: PyClass<'py>> Deref for PyRefMut<'_, 'py, T> { type Target = T; #[inline] @@ -609,39 +644,39 @@ impl<'p, T: PyClass> Deref for PyRefMut<'p, T> { } } -impl<'p, T: PyClass> DerefMut for PyRefMut<'p, T> { +impl<'py, T: PyClass<'py>> DerefMut for PyRefMut<'_, 'py, T> { #[inline] fn deref_mut(&mut self) -> &mut T { unsafe { &mut *self.inner.get_ptr() } } } -impl<'p, T: PyClass> Drop for PyRefMut<'p, T> { +impl<'py, T: PyClass<'py>> Drop for PyRefMut<'_, 'py, T> { fn drop(&mut self) { self.inner.set_borrow_flag(BorrowFlag::UNUSED) } } -impl<'p, T: PyClass> FromPy> for PyObject { - fn from_py(pyref: PyRefMut<'p, T>, py: Python<'_>) -> PyObject { +impl<'py, T: PyClass<'py>> FromPy> for PyObject { + fn from_py(pyref: PyRefMut<'_, 'py, T>, py: Python<'_>) -> PyObject { unsafe { PyObject::from_borrowed_ptr(py, pyref.inner.as_ptr()) } } } -impl<'a, T: PyClass> AsPyPointer for PyRefMut<'a, T> { +impl<'py, T: PyClass<'py>> AsPyPointer for PyRefMut<'_, 'py, T> { fn as_ptr(&self) -> *mut ffi::PyObject { self.inner.as_ptr() } } -impl<'a, T: PyClass> std::convert::TryFrom<&'a PyCell> for crate::PyRefMut<'a, T> { +impl<'a, 'py, T: PyClass<'py>> std::convert::TryFrom<&'a PyCell<'py, T>> for PyRefMut<'a, 'py, T> { type Error = PyBorrowMutError; - fn try_from(cell: &'a crate::PyCell) -> Result { + fn try_from(cell: &'a PyCell<'py, T>) -> Result { cell.try_borrow_mut() } } -impl fmt::Debug for PyRefMut<'_, T> { +impl<'py, T: PyClass<'py> + fmt::Debug> fmt::Debug for PyRefMut<'_, 'py, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&*(self.deref()), f) } diff --git a/src/pyclass.rs b/src/pyclass.rs index 4f0f9ec194e..77e0d3f033c 100644 --- a/src/pyclass.rs +++ b/src/pyclass.rs @@ -1,18 +1,22 @@ //! `PyClass` trait use crate::class::methods::{PyMethodDefType, PyMethodsProtocol}; use crate::pyclass_slots::{PyClassDict, PyClassWeakRef}; +use crate::type_marker::{TypeMarker, TypeWithBase}; use crate::type_object::{type_flags, PyLayout}; -use crate::{class, ffi, PyCell, PyErr, PyNativeType, PyResult, PyTypeInfo, Python}; +use crate::pycell::PyCellLayout; +use crate::pyclass_init::PyNativeTypeInitializer; +use crate::{class, ffi, PyErr, PyResult, PyTypeInfo, Python}; use std::ffi::CString; use std::os::raw::c_void; use std::ptr; #[inline] -pub(crate) unsafe fn default_alloc() -> *mut ffi::PyObject { +pub(crate) unsafe fn default_alloc<'py, T: TypeWithBase<'py>>() -> *mut ffi::PyObject +{ let type_obj = T::type_object(); // if the class derives native types(e.g., PyDict), call special new if T::FLAGS & type_flags::EXTENDED != 0 && T::BaseLayout::IS_NATIVE_TYPE { - let base_tp = ::type_object(); + let base_tp = T::base_type_object(); if let Some(base_new) = base_tp.tp_new { return base_new(type_obj as *const _ as _, ptr::null_mut(), ptr::null_mut()); } @@ -22,12 +26,12 @@ pub(crate) unsafe fn default_alloc() -> *mut ffi::PyObject { } /// This trait enables custom alloc/dealloc implementations for `T: PyClass`. -pub trait PyClassAlloc: PyTypeInfo + Sized { +pub trait PyClassAlloc<'py>: TypeWithBase<'py> + Sized { /// Allocate the actual field for `#[pyclass]`. /// /// # Safety /// This function must return a valid pointer to the Python heap. - unsafe fn alloc(_py: Python) -> *mut Self::Layout { + unsafe fn alloc(_py: Python<'py>) -> *mut Self::Layout { default_alloc::() as _ } @@ -35,7 +39,7 @@ pub trait PyClassAlloc: PyTypeInfo + Sized { /// /// # Safety /// `self_` must be a valid pointer to the Python heap. - unsafe fn dealloc(py: Python, self_: *mut Self::Layout) { + unsafe fn dealloc(py: Python<'py>, self_: *mut Self::Layout) { (*self_).py_drop(py); let obj = self_ as _; if ffi::PyObject_CallFinalizerFromDealloc(obj) < 0 { @@ -70,16 +74,16 @@ pub unsafe fn tp_free_fallback(obj: *mut ffi::PyObject) { /// /// The `#[pyclass]` attribute automatically implements this trait for your Rust struct, /// so you don't have to use this trait directly. -pub trait PyClass: - PyTypeInfo> + Sized + PyClassAlloc + PyMethodsProtocol +pub trait PyClass<'py>: 'static + + PyTypeInfo<'py> + TypeWithBase<'py, Layout = PyCellLayout<'py, Self>> + Sized + PyClassAlloc<'py> + PyMethodsProtocol { /// Specify this class has `#[pyclass(dict)]` or not. type Dict: PyClassDict; /// Specify this class has `#[pyclass(weakref)]` or not. type WeakRef: PyClassWeakRef; - /// The closest native ancestor. This is `PyAny` by default, and when you declare - /// `#[pyclass(extends=PyDict)]`, it's `PyDict`. - type BaseNativeType: PyTypeInfo + PyNativeType; + /// The closest native ancestor. This is `Any` by default, and when you declare + /// `#[pyclass(extends=Dict)]`, it's `Dict`. + type RootType: TypeMarker<'py, Initializer = PyNativeTypeInitializer<'py, Self::RootType>>; } #[cfg(not(Py_LIMITED_API))] @@ -89,7 +93,7 @@ pub(crate) fn initialize_type_object( type_object: &mut ffi::PyTypeObject, ) -> PyResult<()> where - T: PyClass, + T: for<'py> PyClass<'py> { type_object.tp_doc = match T::DESCRIPTION { // PyPy will segfault if passed only a nul terminator as `tp_doc`, ptr::null() is OK though. @@ -99,7 +103,7 @@ where s => CString::new(s)?.into_raw(), }; - type_object.tp_base = ::type_object() as *const _ as _; + type_object.tp_base = T::base_type_object() as *const _ as _; type_object.tp_name = match module_name { Some(module_name) => CString::new(format!("{}.{}", module_name, T::NAME))?.into_raw(), @@ -109,7 +113,7 @@ where // dealloc unsafe extern "C" fn tp_dealloc_callback(obj: *mut ffi::PyObject) where - T: PyClassAlloc, + T: for<'py> PyClassAlloc<'py>, { let pool = crate::GILPool::new(); let py = pool.python(); @@ -201,7 +205,7 @@ where } } -fn py_class_flags(type_object: &mut ffi::PyTypeObject) { +fn py_class_flags<'py, T: TypeMarker<'py>>(type_object: &mut ffi::PyTypeObject) { if type_object.tp_traverse != None || type_object.tp_clear != None || T::FLAGS & type_flags::GC != 0 diff --git a/src/pyclass_init.rs b/src/pyclass_init.rs index 3be018f241c..0c49031ee2d 100644 --- a/src/pyclass_init.rs +++ b/src/pyclass_init.rs @@ -1,22 +1,24 @@ //! Initialization utilities for `#[pyclass]`. -use crate::type_object::{PyBorrowFlagLayout, PyLayout, PySizedLayout, PyTypeInfo}; -use crate::{PyCell, PyClass, PyResult, Python}; +use crate::pycell::PyCellLayout; +use crate::type_object::{PyBorrowFlagLayout, PyLayout, PySizedLayout}; +use crate::type_marker::TypeMarker; +use crate::{PyClass, PyResult, Python}; use std::marker::PhantomData; /// Initializer for Python types. /// /// This trait is intended to use internally for distinguishing `#[pyclass]` and /// Python native types. -pub trait PyObjectInit: Sized { - fn init_class>(self, layout: &mut L); +pub trait PyObjectInit<'py, T: TypeMarker<'py>>: Sized { + fn init_class>(self, layout: &mut L); private_decl! {} } /// Initializer for Python native type, like `PyDict`. -pub struct PyNativeTypeInitializer(PhantomData); +pub struct PyNativeTypeInitializer<'py, T: TypeMarker<'py>>(PhantomData, PhantomData>); -impl PyObjectInit for PyNativeTypeInitializer { - fn init_class>(self, _layout: &mut L) {} +impl<'py, T: TypeMarker<'py>> PyObjectInit<'py, T> for PyNativeTypeInitializer<'py, T> { + fn init_class>(self, _layout: &mut L) {} private_impl! {} } @@ -63,16 +65,16 @@ impl PyObjectInit for PyNativeTypeInitializer { /// assert inst.subname == 'sub' /// assert inst.subsubname == 'subsub'"#); /// ``` -pub struct PyClassInitializer { +pub struct PyClassInitializer<'py, T: PyClass<'py>> { init: T, - super_init: ::Initializer, + super_init: >::Initializer, } -impl PyClassInitializer { +impl<'py, T: PyClass<'py>> PyClassInitializer<'py, T> { /// Constract new initialzer from value `T` and base class' initializer. /// /// We recommend to mainly use `add_subclass`, instead of directly call `new`. - pub fn new(init: T, super_init: ::Initializer) -> Self { + pub fn new(init: T, super_init: >::Initializer) -> Self { Self { init, super_init } } @@ -105,30 +107,30 @@ impl PyClassInitializer { /// } /// } /// ``` - pub fn add_subclass(self, subclass_value: S) -> PyClassInitializer + pub fn add_subclass(self, subclass_value: S) -> PyClassInitializer<'py, S> where - S: PyClass + PyTypeInfo, - S::BaseLayout: PySizedLayout, - S::BaseType: PyTypeInfo, + T: PyClass<'py, Initializer = Self>, + S: PyClass<'py, BaseType = T, BaseInitializer = Self>, + S::BaseLayout: PySizedLayout<'py, T>, { PyClassInitializer::new(subclass_value, self) } // Create a new PyCell + initialize it #[doc(hidden)] - pub unsafe fn create_cell(self, py: Python) -> PyResult<*mut PyCell> + pub unsafe fn create_cell(self, py: Python<'py>) -> PyResult<*mut PyCellLayout<'py, T>> where - T: PyClass, - T::BaseLayout: PyBorrowFlagLayout, + T: PyClass<'py>, + T::BaseLayout: PyBorrowFlagLayout<'py, T::BaseType>, { - let cell = PyCell::internal_new(py)?; + let cell = PyCellLayout::new(py)?; self.init_class(&mut *cell); Ok(cell) } } -impl PyObjectInit for PyClassInitializer { - fn init_class>(self, layout: &mut L) { +impl<'py, T: PyClass<'py>> PyObjectInit<'py, T> for PyClassInitializer<'py, T> { + fn init_class>(self, layout: &mut L) { let Self { init, super_init } = self; unsafe { layout.py_init(init); @@ -140,24 +142,24 @@ impl PyObjectInit for PyClassInitializer { private_impl! {} } -impl From for PyClassInitializer +impl<'py, T> From for PyClassInitializer<'py, T> where - T: PyClass, - T::BaseType: PyTypeInfo>, + T: PyClass<'py>, + T::BaseType: TypeMarker<'py, Initializer = PyNativeTypeInitializer<'py, T::BaseType>>, { - fn from(value: T) -> PyClassInitializer { - Self::new(value, PyNativeTypeInitializer(PhantomData)) + fn from(value: T) -> PyClassInitializer<'py, T> { + Self::new(value, PyNativeTypeInitializer(PhantomData, PhantomData)) } } -impl From<(S, B)> for PyClassInitializer +impl<'py, S, B> From<(S, B)> for PyClassInitializer<'py, S> where - S: PyClass + PyTypeInfo, - S::BaseLayout: PySizedLayout, - B: PyClass + PyTypeInfo>, - B::BaseType: PyTypeInfo>, + S: PyClass<'py, BaseType = B, BaseInitializer = PyClassInitializer<'py, B>>, + S::BaseLayout: PySizedLayout<'py, B>, + B: PyClass<'py, Initializer = PyClassInitializer<'py, B>>, + B::BaseType: TypeMarker<'py, Initializer = PyNativeTypeInitializer<'py, B::BaseType>>, { - fn from(sub_and_base: (S, B)) -> PyClassInitializer { + fn from(sub_and_base: (S, B)) -> PyClassInitializer<'py, S> { let (sub, base) = sub_and_base; PyClassInitializer::from(base).add_subclass(sub) } diff --git a/src/python.rs b/src/python.rs index 67cf22eab88..06ee5c10132 100644 --- a/src/python.rs +++ b/src/python.rs @@ -5,11 +5,10 @@ use crate::err::{PyDowncastError, PyErr, PyResult}; use crate::ffi; use crate::gil::{self, GILGuard}; -use crate::instance::AsPyRef; use crate::object::PyObject; use crate::type_object::{PyDowncastImpl, PyTypeInfo, PyTypeObject}; use crate::types::{PyAny, PyDict, PyModule, PyType}; -use crate::{AsPyPointer, FromPyPointer, IntoPyPointer, PyTryFrom}; +use crate::{AsPyPointer, FromPyPointer, IntoPyPointer, PyTryFrom, AsPyRef}; use std::ffi::CString; use std::marker::PhantomData; use std::os::raw::c_int; @@ -163,7 +162,7 @@ impl<'p> Python<'p> { code: &str, globals: Option<&PyDict>, locals: Option<&PyDict>, - ) -> PyResult<&'p PyAny> { + ) -> PyResult> { self.run_code(code, ffi::Py_eval_input, globals, locals) } @@ -199,7 +198,7 @@ impl<'p> Python<'p> { ) -> PyResult<()> { let res = self.run_code(code, ffi::Py_file_input, globals, locals); res.map(|obj| { - debug_assert!(crate::ObjectProtocol::is_none(obj)); + debug_assert!(crate::ObjectProtocol::is_none(&obj)); }) } @@ -216,7 +215,7 @@ impl<'p> Python<'p> { start: c_int, globals: Option<&PyDict>, locals: Option<&PyDict>, - ) -> PyResult<&'p PyAny> { + ) -> PyResult> { let code = CString::new(code)?; unsafe { let mptr = ffi::PyImport_AddModule("__main__\0".as_ptr() as *const _); @@ -242,7 +241,7 @@ impl<'p> Python<'p> { } /// Gets the Python type object for type `T`. - pub fn get_type(self) -> &'p PyType + pub fn get_type(self) -> &'p PyType<'p> where T: PyTypeObject, { @@ -250,7 +249,7 @@ impl<'p> Python<'p> { } /// Imports the Python module with the specified name. - pub fn import(self, name: &str) -> PyResult<&'p PyModule> { + pub fn import(self, name: &str) -> PyResult> { PyModule::import(self, name) } @@ -266,10 +265,10 @@ impl<'p> Python<'p> { /// This is equivalent to the Python `issubclass` function. pub fn is_subclass(self) -> PyResult where - T: PyTypeObject, - U: PyTypeObject, + T: PyTypeInfo<'p>, + U: PyTypeInfo<'p>, { - T::type_object().as_ref(self).is_subclass::() + PyType::new::(self).is_subclass::() } /// Gets the Python builtin value `None`. @@ -293,7 +292,7 @@ impl<'p> Python<'p> { where T: PyTryFrom<'p>, { - let obj = unsafe { gil::register_owned(self, obj.into_nonnull()) }; + let obj = unsafe { gil::register_owned(self, obj.into_non_null()) }; ::try_from(obj) } @@ -301,15 +300,15 @@ impl<'p> Python<'p> { /// to the specific type. pub unsafe fn cast_as(self, obj: PyObject) -> &'p T where - T: PyDowncastImpl + PyTypeInfo, + T: PyDowncastImpl<'p> + PyTypeInfo<'p>, { - let obj = gil::register_owned(self, obj.into_nonnull()); + let obj = gil::register_owned(self, obj.into_non_null()); T::unchecked_downcast(obj) } /// Registers the object pointer in the release pool. #[allow(clippy::wrong_self_convention)] - pub unsafe fn from_borrowed_ptr_to_obj(self, ptr: *mut ffi::PyObject) -> &'p PyAny { + pub unsafe fn from_borrowed_ptr_to_obj(self, ptr: *mut ffi::PyObject) -> &'p PyAny<'p> { match NonNull::new(ptr) { Some(p) => gil::register_borrowed(self, p), None => crate::err::panic_after_error(), @@ -319,7 +318,7 @@ impl<'p> Python<'p> { /// Registers the object pointer in the release pool, /// and does an unchecked downcast to the specific type. #[allow(clippy::wrong_self_convention)] - pub unsafe fn from_owned_ptr(self, ptr: *mut ffi::PyObject) -> &'p T + pub unsafe fn from_owned_ptr(self, ptr: *mut ffi::PyObject) -> T where T: FromPyPointer<'p>, { @@ -331,7 +330,7 @@ impl<'p> Python<'p> { /// Returns `Err(PyErr)` if the pointer is NULL. /// Does an unchecked downcast to the specific type. #[allow(clippy::wrong_self_convention)] - pub unsafe fn from_owned_ptr_or_err(self, ptr: *mut ffi::PyObject) -> PyResult<&'p T> + pub unsafe fn from_owned_ptr_or_err(self, ptr: *mut ffi::PyObject) -> PyResult where T: FromPyPointer<'p>, { @@ -343,7 +342,7 @@ impl<'p> Python<'p> { /// Returns `None` if the pointer is NULL. /// Does an unchecked downcast to the specific type. #[allow(clippy::wrong_self_convention)] - pub unsafe fn from_owned_ptr_or_opt(self, ptr: *mut ffi::PyObject) -> Option<&'p T> + pub unsafe fn from_owned_ptr_or_opt(self, ptr: *mut ffi::PyObject) -> Option where T: FromPyPointer<'p>, { @@ -438,7 +437,7 @@ mod test { // Inject our own global namespace let v: i32 = py - .eval("foo + 29", Some(d), None) + .eval("foo + 29", Some(&d), None) .unwrap() .extract() .unwrap(); @@ -446,7 +445,7 @@ mod test { // Inject our own local namespace let v: i32 = py - .eval("foo + 29", None, Some(d)) + .eval("foo + 29", None, Some(&d)) .unwrap() .extract() .unwrap(); @@ -454,7 +453,7 @@ mod test { // Make sure builtin names are still accessible when using a local namespace let v: i32 = py - .eval("min(foo, 2)", None, Some(d)) + .eval("min(foo, 2)", None, Some(&d)) .unwrap() .extract() .unwrap(); diff --git a/src/type_marker.rs b/src/type_marker.rs new file mode 100644 index 00000000000..5aa5b0f3669 --- /dev/null +++ b/src/type_marker.rs @@ -0,0 +1,110 @@ +use crate::conversion::IntoPyPointer; +use crate::ffi; +use crate::pyclass_init::PyObjectInit; +use crate::type_object::{PyLayout, PySizedLayout, PyTypeInfo}; +use crate::types::*; +use crate::{AsPyPointer, PyNativeType}; + +pub trait TypeMarker<'py>: Sized { + type NativeType: PyNativeType<'py>; + type Layout: PyLayout<'py, Self>; + type Initializer: PyObjectInit<'py, Self>; + + /// Type flags (ie PY_TYPE_FLAG_GC, PY_TYPE_FLAG_WEAKREF) + const FLAGS: usize = 0; + + /// PyTypeObject instance for this type. + fn type_object() -> &'static ffi::PyTypeObject; + + /// Check if `*mut ffi::PyObject` is instance of this type + fn is_instance(object: &PyAny) -> bool { + unsafe { + ffi::PyObject_TypeCheck(object.as_ptr(), Self::type_object() as *const _ as _) != 0 + } + } + + /// Check if `*mut ffi::PyObject` is exact instance of this type + fn is_exact_instance(object: &PyAny) -> bool { + unsafe { (*object.as_ptr()).ob_type == Self::type_object() as *const _ as _ } + } +} + +pub trait TypeWithBase<'py>: TypeMarker<'py> { + type BaseType: TypeMarker<'py>; + type BaseNativeType: PyNativeType<'py>; + type BaseLayout: PySizedLayout<'py, Self::BaseType>; + type BaseInitializer: PyObjectInit<'py, Self::BaseType>; + + /// PyTypeObject instance for base type. + fn base_type_object() -> &'static ffi::PyTypeObject { + Self::BaseType::type_object() + } +} + + +#[macro_export] +macro_rules! py_type_marker { + ($name: ident, $native_ty: ident, $layout: path) => { + #[derive(Debug)] + pub struct $name; + + unsafe impl<'py> $crate::type_object::PyLayout<'py, $name> for $layout {} + unsafe impl<'py> $crate::type_object::PyLayout<'py, $crate::types::$native_ty<'py>> for $layout {} + + impl<'py> TypeMarker<'py> for $name { + type NativeType = $crate::types::$native_ty<'py>; + type Layout = $layout; + type Initializer = $crate::pyclass_init::PyNativeTypeInitializer<'py, Self>; + + /// PyTypeObject instance for this type. + fn type_object() -> &'static ffi::PyTypeObject { + <$native_ty<'py> as PyTypeInfo<'py>>::type_object() + } + } + + impl<'py> TypeMarker<'py> for $crate::types::$native_ty<'py> { + type NativeType = $crate::types::$native_ty<'py>; + type Layout = $layout; + type Initializer = $crate::pyclass_init::PyNativeTypeInitializer<'py, Self>; + + /// PyTypeObject instance for this type. + fn type_object() -> &'static ffi::PyTypeObject { + <$native_ty<'py> as PyTypeInfo<'py>>::type_object() + } + } + + impl From<$native_ty<'_>> for $crate::Py<$name> { + fn from(other: $native_ty<'_>) -> Self { + unsafe { $crate::Py::from_owned_ptr(other.into_ptr()) } + } + } + }; + ($name: ident, $native_ty: ident) => { + py_type_marker!($name, $native_ty, ffi::PyObject); + } +} + +py_type_marker!(Any, PyAny); +py_type_marker!(Bool, PyBool); +py_type_marker!(ByteArray, PyByteArray); +py_type_marker!(Bytes, PyBytes); +// py_type_marker!(Iterator, PyIterator); +py_type_marker!(List, PyList); +py_type_marker!(Long, PyLong); +py_type_marker!(Module, PyModule); +py_type_marker!(String, PyString); +py_type_marker!(Tuple, PyTuple); +py_type_marker!(Type, PyType); +py_type_marker!(TzInfo, PyTzInfo); +// py_type_marker!(Sequence, PySequence); + +py_type_marker!(Complex, PyComplex, ffi::PyComplexObject); +py_type_marker!(Date, PyDate, ffi::PyDateTime_Date); +py_type_marker!(DateTime, PyDateTime, ffi::PyDateTime_DateTime); +py_type_marker!(Delta, PyDelta, ffi::PyDateTime_Delta); +py_type_marker!(Dict, PyDict, ffi::PyDictObject); +py_type_marker!(Float, PyFloat, ffi::PyFloatObject); +py_type_marker!(FrozenSet, PyFrozenSet, ffi::PySetObject); +py_type_marker!(Set, PySet, ffi::PySetObject); +py_type_marker!(Slice, PySlice, ffi::PySliceObject); +py_type_marker!(Time, PyTime, ffi::PyDateTime_Time); diff --git a/src/type_object.rs b/src/type_object.rs index 5069de176e0..a47db03ae54 100644 --- a/src/type_object.rs +++ b/src/type_object.rs @@ -2,8 +2,8 @@ //! Python type object information use crate::pyclass::{initialize_type_object, PyClass}; -use crate::pyclass_init::PyObjectInit; -use crate::types::{PyAny, PyType}; +use crate::types::PyAny; +use crate::type_marker::{TypeMarker, Type, TypeWithBase}; use crate::{ffi, AsPyPointer, Py, Python}; use std::cell::UnsafeCell; use std::ptr::NonNull; @@ -14,9 +14,12 @@ use std::sync::atomic::{AtomicBool, Ordering}; /// is of `PyAny`. /// /// This trait is intended to be used internally. -pub unsafe trait PyLayout { +pub unsafe trait PyLayout<'py, T: TypeMarker<'py> + Sized> { const IS_NATIVE_TYPE: bool = true; - fn get_super(&mut self) -> Option<&mut T::BaseLayout> { + fn get_super(&mut self) -> Option<&mut T::BaseLayout> + where + T: TypeWithBase<'py> + { None } unsafe fn py_init(&mut self, _value: T) {} @@ -25,8 +28,8 @@ pub unsafe trait PyLayout { /// `T: PySizedLayout` represents `T` is not a instance of /// [`PyVarObject`](https://docs.python.org/3.8/c-api/structures.html?highlight=pyvarobject#c.PyVarObject). -/// , in addition that `T` is a concrete representaion of `U`. -pub trait PySizedLayout: PyLayout + Sized {} +/// , in addition that `T` is a concrete representation of `U`. +pub trait PySizedLayout<'py, T: TypeMarker<'py>>: PyLayout<'py, T> + Sized {} /// Marker type indicates that `Self` can be a base layout of `PyClass`. /// @@ -42,7 +45,7 @@ pub trait PySizedLayout: PyLayout + Sized {} /// } /// ``` /// Otherwise, implementing this trait is undefined behavior. -pub unsafe trait PyBorrowFlagLayout: PyLayout + Sized {} +pub unsafe trait PyBorrowFlagLayout<'py, T: TypeMarker<'py>>: PyLayout<'py, T> + Sized {} /// Our custom type flags #[doc(hidden)] @@ -68,22 +71,22 @@ pub mod type_flags { // `&PyCell` is a pointer of `ffi::PyObject` but `&PyAny` is a pointer of a pointer, // so we need abstraction. // This mismatch eventually should be fixed(e.g., https://github.com/PyO3/pyo3/issues/679). -pub unsafe trait PyDowncastImpl { +pub unsafe trait PyDowncastImpl<'py> { /// Cast `&PyAny` to `&Self` without no type checking. /// /// # Safety /// /// Unless obj is not an instance of a type corresponding to Self, /// this method causes undefined behavior. - unsafe fn unchecked_downcast(obj: &PyAny) -> &Self; + unsafe fn unchecked_downcast<'a>(obj: &'a PyAny<'py>) -> &'a Self; private_decl! {} } -unsafe impl<'py, T> PyDowncastImpl for T +unsafe impl<'py, T> PyDowncastImpl<'py> for T where - T: 'py + crate::PyNativeType, + T: crate::PyNativeType<'py>, { - unsafe fn unchecked_downcast(obj: &PyAny) -> &Self { + unsafe fn unchecked_downcast<'a>(obj: &'a PyAny<'py>) -> &'a Self { &*(obj as *const _ as *const Self) } private_impl! {} @@ -95,9 +98,9 @@ where /// This trait is marked unsafe because: /// - specifying the incorrect layout can lead to memory errors /// - the return value of type_object must always point to the same PyTypeObject instance -pub unsafe trait PyTypeInfo: Sized { +pub unsafe trait PyTypeInfo<'py>: Sized { /// Type of objects to store in PyObject struct - type Type; + type Type: TypeMarker<'py>; /// Class name const NAME: &'static str; @@ -108,24 +111,6 @@ pub unsafe trait PyTypeInfo: Sized { /// Class doc string const DESCRIPTION: &'static str = "\0"; - /// Type flags (ie PY_TYPE_FLAG_GC, PY_TYPE_FLAG_WEAKREF) - const FLAGS: usize = 0; - - /// Base class - type BaseType: PyTypeInfo + PyTypeObject; - - /// Layout - type Layout: PyLayout; - - /// Layout of Basetype. - type BaseLayout: PySizedLayout; - - /// Initializer for layout - type Initializer: PyObjectInit; - - /// Utility type to make AsPyRef work - type AsRefTarget: PyDowncastImpl; - /// PyTypeObject instance for this type. fn type_object() -> &'static ffi::PyTypeObject; @@ -150,14 +135,14 @@ pub unsafe trait PyTypeInfo: Sized { /// See [PyTypeInfo::type_object] pub unsafe trait PyTypeObject { /// Returns the safe abstraction over the type object. - fn type_object() -> Py; + fn type_object() -> Py; } -unsafe impl PyTypeObject for T +unsafe impl<'py, T> PyTypeObject for T where - T: PyTypeInfo, + T: PyTypeInfo<'py>, { - fn type_object() -> Py { + fn type_object() -> Py { unsafe { Py::from_borrowed_ptr(::type_object() as *const _ as _) } } } @@ -216,7 +201,7 @@ impl LazyStaticType { } } - pub fn get_or_init(&self) -> &ffi::PyTypeObject { + pub fn get_or_init PyClass<'py>>(&self) -> &ffi::PyTypeObject { if !self .initialized .compare_and_swap(false, true, Ordering::Acquire) diff --git a/src/types/any.rs b/src/types/any.rs index ee9f47b472d..5c98066074c 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -1,7 +1,11 @@ -use crate::conversion::PyTryFrom; +use crate::conversion::{FromPyPointer, PyTryFrom}; use crate::err::PyDowncastError; -use crate::internal_tricks::Unsendable; -use crate::{ffi, PyObject}; +use crate::ffi; +use crate::gil; +use crate::python::Python; +use crate::type_marker; +use std::marker::PhantomData; +use std::ptr::NonNull; /// A Python object with GIL lifetime /// @@ -28,24 +32,78 @@ use crate::{ffi, PyObject}; /// assert!(any.downcast::().is_err()); /// ``` #[repr(transparent)] -pub struct PyAny(PyObject, Unsendable); -unsafe impl crate::type_object::PyLayout for ffi::PyObject {} -impl crate::type_object::PySizedLayout for ffi::PyObject {} -pyobject_native_type_named!(PyAny); -pyobject_native_type_convert!( - PyAny, +pub struct PyAny<'a>(NonNull, PhantomData>); + +impl<'py> crate::type_object::PySizedLayout<'py, type_marker::Any> for ffi::PyObject {} +pyobject_native_type_named!(PyAny<'py>); +pyobject_native_type_common!(PyAny<'py>); +pyobject_native_type_info!( + PyAny<'py>, ffi::PyObject, ffi::PyBaseObject_Type, - Some("builtins"), - ffi::PyObject_Check + ffi::PyObject_Check, + type_marker::Any ); -pyobject_native_type_extract!(PyAny); +pyobject_native_type_extract!(PyAny<'py>); -impl PyAny { +impl<'py> PyAny<'py> { pub fn downcast(&self) -> Result<&T, PyDowncastError> where - for<'py> T: PyTryFrom<'py>, + T: PyTryFrom<'py>, { ::try_from(self) } + + /// Create a PyAny from an owned non-null raw PyObject pointer. + /// + /// # Safety + /// + /// It must be ensured that the pointer is an owned reference. + pub unsafe fn from_non_null(_py: Python<'py>, ptr: NonNull) -> Self { + Self(ptr, PhantomData) + } + + /// Create an owned non-null raw PyObject pointer from this PyAny. + pub fn into_non_null(self) -> NonNull { + // Destructure self so that Drop(self) is not called. + // (Alternative would be to call std::mem::forget(self).) + let PyAny(ptr, _) = self; + ptr + } + + pub fn raw_borrowed<'a>(_py: Python<'py>, ptr_ref: &'a *mut ffi::PyObject) -> &'a Self { + unsafe { std::mem::transmute(ptr_ref) } + } +} + +impl Clone for PyAny<'_> { + fn clone(&self) -> Self { + unsafe { ffi::Py_INCREF(self.0.as_ptr()); } + Self(self.0, PhantomData) + } +} + +impl std::convert::AsRef for PyAny<'_> { + fn as_ref(&self) -> &Self { + self + } +} + +impl Drop for PyAny<'_> { + fn drop(&mut self) { + unsafe { ffi::Py_DECREF(self.0.as_ptr()); }; + } +} + +unsafe impl<'py> FromPyPointer<'py> for PyAny<'py> +{ + unsafe fn from_owned_ptr_or_opt(py: Python<'py>, ptr: *mut ffi::PyObject) -> Option { + Some(Self::from_non_null(py, NonNull::new(ptr)?)) + } + unsafe fn from_borrowed_ptr_or_opt( + py: Python<'py>, + ptr: *mut ffi::PyObject, + ) -> Option<&'py Self> { + Some(gil::register_borrowed(py, NonNull::new(ptr)?)) + } } diff --git a/src/types/boolobject.rs b/src/types/boolobject.rs index 0702b995c7f..443112c4076 100644 --- a/src/types/boolobject.rs +++ b/src/types/boolobject.rs @@ -1,20 +1,19 @@ // Copyright (c) 2017-present PyO3 Project and Contributors -use crate::internal_tricks::Unsendable; use crate::{ ffi, AsPyPointer, FromPy, FromPyObject, PyAny, PyObject, PyResult, PyTryFrom, Python, - ToPyObject, + ToPyObject, type_marker }; /// Represents a Python `bool`. #[repr(transparent)] -pub struct PyBool(PyObject, Unsendable); +pub struct PyBool<'py>(PyAny<'py>); -pyobject_native_type!(PyBool, ffi::PyObject, ffi::PyBool_Type, ffi::PyBool_Check); +pyobject_native_type!(PyBool<'py>, ffi::PyObject, ffi::PyBool_Type, ffi::PyBool_Check, type_marker::Bool); -impl PyBool { +impl<'py> PyBool<'py> { /// Depending on `val`, returns `true` or `false`. #[inline] - pub fn new(py: Python, val: bool) -> &PyBool { + pub fn new(py: Python<'py>, val: bool) -> &'py Self { unsafe { py.from_borrowed_ptr(if val { ffi::Py_True() } else { ffi::Py_False() }) } } @@ -45,15 +44,15 @@ impl ToPyObject for bool { impl FromPy for PyObject { #[inline] fn from_py(other: bool, py: Python) -> Self { - PyBool::new(py, other).into() + PyBool::new(py, other).clone().into() } } /// Converts a Python `bool` to a Rust `bool`. /// /// Fails with `TypeError` if the input is not a Python `bool`. -impl<'source> FromPyObject<'source> for bool { - fn extract(obj: &'source PyAny) -> PyResult { +impl FromPyObject<'_, '_> for bool { + fn extract(obj: &PyAny) -> PyResult { Ok(::try_from(obj)?.is_true()) } } @@ -72,7 +71,7 @@ mod test { assert!(PyBool::new(py, true).is_true()); let t: &PyAny = PyBool::new(py, true).into(); assert_eq!(true, t.extract().unwrap()); - assert_eq!(true.to_object(py), PyBool::new(py, true).into()); + assert_eq!(true.to_object(py), PyBool::new(py, true).clone().into()); } #[test] @@ -82,6 +81,6 @@ mod test { assert!(!PyBool::new(py, false).is_true()); let t: &PyAny = PyBool::new(py, false).into(); assert_eq!(false, t.extract().unwrap()); - assert_eq!(false.to_object(py), PyBool::new(py, false).into()); + assert_eq!(false.to_object(py), PyBool::new(py, false).clone().into()); } } diff --git a/src/types/bytearray.rs b/src/types/bytearray.rs index 4f8faf2b3a8..510d451e346 100644 --- a/src/types/bytearray.rs +++ b/src/types/bytearray.rs @@ -2,8 +2,8 @@ use crate::err::{PyErr, PyResult}; use crate::ffi; use crate::instance::PyNativeType; -use crate::internal_tricks::Unsendable; -use crate::object::PyObject; +use crate::types::PyAny; +use crate::type_marker; use crate::AsPyPointer; use crate::Python; use std::os::raw::c_char; @@ -11,15 +11,15 @@ use std::slice; /// Represents a Python `bytearray`. #[repr(transparent)] -pub struct PyByteArray(PyObject, Unsendable); +pub struct PyByteArray<'py>(PyAny<'py>); -pyobject_native_var_type!(PyByteArray, ffi::PyByteArray_Type, ffi::PyByteArray_Check); +pyobject_native_var_type!(PyByteArray<'py>, ffi::PyByteArray_Type, ffi::PyByteArray_Check, type_marker::ByteArray); -impl PyByteArray { +impl<'py> PyByteArray<'py> { /// Creates a new Python bytearray object. /// /// The byte string is initialized by copying the data from the `&[u8]`. - pub fn new<'p>(py: Python<'p>, src: &[u8]) -> &'p PyByteArray { + pub fn new(py: Python<'py>, src: &[u8]) -> Self { let ptr = src.as_ptr() as *const c_char; let len = src.len() as ffi::Py_ssize_t; unsafe { py.from_owned_ptr::(ffi::PyByteArray_FromStringAndSize(ptr, len)) } @@ -27,7 +27,7 @@ impl PyByteArray { /// Creates a new Python bytearray object from another PyObject that /// implements the buffer protocol. - pub fn from<'p, I>(py: Python<'p>, src: &'p I) -> PyResult<&'p PyByteArray> + pub fn from(py: Python<'py>, src: &I) -> PyResult where I: AsPyPointer, { diff --git a/src/types/bytes.rs b/src/types/bytes.rs index 50603270d2c..fba42cb2caf 100644 --- a/src/types/bytes.rs +++ b/src/types/bytes.rs @@ -1,7 +1,6 @@ -use crate::internal_tricks::Unsendable; use crate::{ ffi, AsPyPointer, FromPy, FromPyObject, PyAny, PyObject, PyResult, PyTryFrom, Python, - ToPyObject, + ToPyObject, type_marker }; use std::ops::Index; use std::os::raw::c_char; @@ -12,16 +11,16 @@ use std::str; /// /// This type is immutable. #[repr(transparent)] -pub struct PyBytes(PyObject, Unsendable); +pub struct PyBytes<'py>(PyAny<'py>); -pyobject_native_var_type!(PyBytes, ffi::PyBytes_Type, ffi::PyBytes_Check); +pyobject_native_var_type!(PyBytes<'py>, ffi::PyBytes_Type, ffi::PyBytes_Check, type_marker::Bytes); -impl PyBytes { +impl<'py> PyBytes<'py> { /// Creates a new Python bytestring object. /// The bytestring is initialized by copying the data from the `&[u8]`. /// /// Panics if out of memory. - pub fn new<'p>(py: Python<'p>, s: &[u8]) -> &'p PyBytes { + pub fn new(py: Python<'py>, s: &[u8]) -> Self { let ptr = s.as_ptr() as *const c_char; let len = s.len() as ffi::Py_ssize_t; unsafe { py.from_owned_ptr(ffi::PyBytes_FromStringAndSize(ptr, len)) } @@ -30,7 +29,7 @@ impl PyBytes { /// Creates a new Python byte string object from a raw pointer and length. /// /// Panics if out of memory. - pub unsafe fn from_ptr(py: Python<'_>, ptr: *const u8, len: usize) -> &PyBytes { + pub unsafe fn from_ptr(py: Python<'py>, ptr: *const u8, len: usize) -> Self { py.from_owned_ptr(ffi::PyBytes_FromStringAndSize( ptr as *const _, len as isize, @@ -50,7 +49,7 @@ impl PyBytes { } /// This is the same way [Vec] is indexed. -impl> Index for PyBytes { +impl> Index for PyBytes<'_> { type Output = I::Output; fn index(&self, index: I) -> &Self::Output { @@ -64,7 +63,7 @@ impl<'a> FromPy<&'a [u8]> for PyObject { } } -impl<'a> FromPyObject<'a> for &'a [u8] { +impl<'a> FromPyObject<'a, '_> for &'a [u8] { fn extract(obj: &'a PyAny) -> PyResult { Ok(::try_from(obj)?.as_bytes()) } @@ -81,7 +80,7 @@ mod test { let py = gil.python(); let py_bytes = py.eval("b'Hello Python'", None, None).unwrap(); - let bytes: &[u8] = FromPyObject::extract(py_bytes).unwrap(); + let bytes: &[u8] = FromPyObject::extract(&py_bytes).unwrap(); assert_eq!(bytes, b"Hello Python"); } diff --git a/src/types/complex.rs b/src/types/complex.rs index 86ac6f4388b..74b7a76bdb7 100644 --- a/src/types/complex.rs +++ b/src/types/complex.rs @@ -1,9 +1,9 @@ use crate::ffi; #[cfg(not(PyPy))] use crate::instance::PyNativeType; -use crate::internal_tricks::Unsendable; +use crate::types::PyAny; +use crate::type_marker; use crate::AsPyPointer; -use crate::PyObject; use crate::Python; #[cfg(not(PyPy))] use std::ops::*; @@ -11,18 +11,19 @@ use std::os::raw::c_double; /// Represents a Python `complex`. #[repr(transparent)] -pub struct PyComplex(PyObject, Unsendable); +pub struct PyComplex<'py>(PyAny<'py>); pyobject_native_type!( - PyComplex, + PyComplex<'py>, ffi::PyComplexObject, ffi::PyComplex_Type, - ffi::PyComplex_Check + ffi::PyComplex_Check, + type_marker::Complex ); -impl PyComplex { +impl<'py> PyComplex<'py> { /// Creates a new Python `complex` object, from its real and imaginary values. - pub fn from_doubles(py: Python, real: c_double, imag: c_double) -> &PyComplex { + pub fn from_doubles(py: Python<'py>, real: c_double, imag: c_double) -> Self { unsafe { let ptr = ffi::PyComplex_FromDoubles(real, imag); py.from_owned_ptr(ptr) @@ -48,7 +49,7 @@ impl PyComplex { /// Returns `self ** other` #[cfg(not(Py_LIMITED_API))] #[cfg(not(PyPy))] - pub fn pow(&self, other: &PyComplex) -> &PyComplex { + pub fn pow(&self, other: &PyComplex) -> Self { unsafe { self.py() .from_owned_ptr(complex_operation(self, other, ffi::_Py_c_pow)) @@ -71,9 +72,9 @@ unsafe fn complex_operation( #[cfg(not(Py_LIMITED_API))] #[cfg(not(PyPy))] -impl<'py> Add for &'py PyComplex { - type Output = &'py PyComplex; - fn add(self, other: &'py PyComplex) -> &'py PyComplex { +impl<'py> Add<&'_ PyComplex<'_>> for &'_ PyComplex<'py> { + type Output = PyComplex<'py>; + fn add(self, other: &PyComplex) -> PyComplex<'py> { unsafe { self.py() .from_owned_ptr(complex_operation(self, other, ffi::_Py_c_sum)) @@ -83,9 +84,9 @@ impl<'py> Add for &'py PyComplex { #[cfg(not(Py_LIMITED_API))] #[cfg(not(PyPy))] -impl<'py> Sub for &'py PyComplex { - type Output = &'py PyComplex; - fn sub(self, other: &'py PyComplex) -> &'py PyComplex { +impl<'py> Sub<&'_ PyComplex<'_>> for &'_ PyComplex<'py> { + type Output = PyComplex<'py>; + fn sub(self, other: &PyComplex) -> PyComplex<'py> { unsafe { self.py() .from_owned_ptr(complex_operation(self, other, ffi::_Py_c_diff)) @@ -95,9 +96,9 @@ impl<'py> Sub for &'py PyComplex { #[cfg(not(Py_LIMITED_API))] #[cfg(not(PyPy))] -impl<'py> Mul for &'py PyComplex { - type Output = &'py PyComplex; - fn mul(self, other: &'py PyComplex) -> &'py PyComplex { +impl<'py> Mul<&'_ PyComplex<'_>> for &'_ PyComplex<'py> { + type Output = PyComplex<'py>; + fn mul(self, other: &PyComplex) -> PyComplex<'py> { unsafe { self.py() .from_owned_ptr(complex_operation(self, other, ffi::_Py_c_prod)) @@ -107,9 +108,9 @@ impl<'py> Mul for &'py PyComplex { #[cfg(not(Py_LIMITED_API))] #[cfg(not(PyPy))] -impl<'py> Div for &'py PyComplex { - type Output = &'py PyComplex; - fn div(self, other: &'py PyComplex) -> &'py PyComplex { +impl<'py> Div<&'_ PyComplex<'_>> for &'_ PyComplex<'py> { + type Output = PyComplex<'py>; + fn div(self, other: &PyComplex) -> PyComplex<'py> { unsafe { self.py() .from_owned_ptr(complex_operation(self, other, ffi::_Py_c_quot)) @@ -119,9 +120,9 @@ impl<'py> Div for &'py PyComplex { #[cfg(not(Py_LIMITED_API))] #[cfg(not(PyPy))] -impl<'py> Neg for &'py PyComplex { - type Output = &'py PyComplex; - fn neg(self) -> &'py PyComplex { +impl<'py> Neg for &'_ PyComplex<'py> { + type Output = PyComplex<'py>; + fn neg(self) -> PyComplex<'py> { unsafe { let val = (*(self.as_ptr() as *mut ffi::PyComplexObject)).cval; self.py() @@ -250,7 +251,7 @@ mod test { let py = gil.python(); let l = PyComplex::from_doubles(py, 3.0, 1.2); let r = PyComplex::from_doubles(py, 1.0, 2.6); - let res = l + r; + let res = &l + &r; assert_approx_eq!(res.real(), 4.0); assert_approx_eq!(res.imag(), 3.8); } @@ -262,7 +263,7 @@ mod test { let py = gil.python(); let l = PyComplex::from_doubles(py, 3.0, 1.2); let r = PyComplex::from_doubles(py, 1.0, 2.6); - let res = l - r; + let res = &l - &r; assert_approx_eq!(res.real(), 2.0); assert_approx_eq!(res.imag(), -1.4); } @@ -274,7 +275,7 @@ mod test { let py = gil.python(); let l = PyComplex::from_doubles(py, 3.0, 1.2); let r = PyComplex::from_doubles(py, 1.0, 2.6); - let res = l * r; + let res = &l * &r; assert_approx_eq!(res.real(), -0.12); assert_approx_eq!(res.imag(), 9.0); } @@ -286,7 +287,7 @@ mod test { let py = gil.python(); let l = PyComplex::from_doubles(py, 3.0, 1.2); let r = PyComplex::from_doubles(py, 1.0, 2.6); - let res = l / r; + let res = &l / &r; assert_approx_eq!(res.real(), 0.788_659_793_814_432_9); assert_approx_eq!(res.imag(), -0.850_515_463_917_525_7); } @@ -297,7 +298,7 @@ mod test { let gil = Python::acquire_gil(); let py = gil.python(); let val = PyComplex::from_doubles(py, 3.0, 1.2); - let res = -val; + let res = -&val; assert_approx_eq!(res.real(), -3.0); assert_approx_eq!(res.imag(), -1.2); } @@ -318,7 +319,7 @@ mod test { let py = gil.python(); let l = PyComplex::from_doubles(py, 3.0, 1.2); let r = PyComplex::from_doubles(py, 1.2, 2.6); - let val = l.pow(r); + let val = l.pow(&r); assert_approx_eq!(val.real(), -1.419_309_997_016_603_7); assert_approx_eq!(val.imag(), -0.541_297_466_033_544_6); } diff --git a/src/types/datetime.rs b/src/types/datetime.rs index 293eabff09b..74d3756a005 100644 --- a/src/types/datetime.rs +++ b/src/types/datetime.rs @@ -25,12 +25,12 @@ use crate::ffi::{ PyDateTime_TIME_GET_HOUR, PyDateTime_TIME_GET_MICROSECOND, PyDateTime_TIME_GET_MINUTE, PyDateTime_TIME_GET_SECOND, }; -use crate::internal_tricks::Unsendable; use crate::object::PyObject; -use crate::types::PyTuple; +use crate::types::{PyAny, PyTuple}; use crate::AsPyPointer; use crate::Python; use crate::ToPyObject; +use crate::type_marker; use std::os::raw::c_int; #[cfg(not(PyPy))] use std::ptr; @@ -66,17 +66,18 @@ pub trait PyTimeAccess { } /// Bindings around `datetime.date` -pub struct PyDate(PyObject, Unsendable); +pub struct PyDate<'py>(PyAny<'py>); pyobject_native_type!( - PyDate, + PyDate<'py>, crate::ffi::PyDateTime_Date, *PyDateTimeAPI.DateType, Some("datetime"), - PyDate_Check + PyDate_Check, + type_marker::Date ); -impl PyDate { - pub fn new<'p>(py: Python<'p>, year: i32, month: u8, day: u8) -> PyResult<&'p PyDate> { +impl<'py> PyDate<'py> { + pub fn new(py: Python<'py>, year: i32, month: u8, day: u8) -> PyResult { unsafe { let ptr = (PyDateTimeAPI.Date_FromDate)( year, @@ -91,7 +92,7 @@ impl PyDate { /// Construct a `datetime.date` from a POSIX timestamp /// /// This is equivalent to `datetime.date.fromtimestamp` - pub fn from_timestamp<'p>(py: Python<'p>, timestamp: i64) -> PyResult<&'p PyDate> { + pub fn from_timestamp(py: Python<'py>, timestamp: i64) -> PyResult { let time_tuple = PyTuple::new(py, &[timestamp]); unsafe { @@ -107,7 +108,7 @@ impl PyDate { } } -impl PyDateAccess for PyDate { +impl PyDateAccess for PyDate<'_> { fn get_year(&self) -> i32 { unsafe { PyDateTime_GET_YEAR(self.as_ptr()) as i32 } } @@ -122,18 +123,19 @@ impl PyDateAccess for PyDate { } /// Bindings for `datetime.datetime` -pub struct PyDateTime(PyObject, Unsendable); +pub struct PyDateTime<'py>(PyAny<'py>); pyobject_native_type!( - PyDateTime, + PyDateTime<'py>, crate::ffi::PyDateTime_DateTime, *PyDateTimeAPI.DateTimeType, Some("datetime"), - PyDateTime_Check + PyDateTime_Check, + type_marker::DateTime ); -impl PyDateTime { - pub fn new<'p>( - py: Python<'p>, +impl<'py> PyDateTime<'py> { + pub fn new( + py: Python<'py>, year: i32, month: u8, day: u8, @@ -142,7 +144,7 @@ impl PyDateTime { second: u8, microsecond: u32, tzinfo: Option<&PyObject>, - ) -> PyResult<&'p PyDateTime> { + ) -> PyResult { unsafe { let ptr = (PyDateTimeAPI.DateTime_FromDateAndTime)( year, @@ -162,11 +164,11 @@ impl PyDateTime { /// Construct a `datetime` object from a POSIX timestamp /// /// This is equivalent to `datetime.datetime.from_timestamp` - pub fn from_timestamp<'p>( - py: Python<'p>, + pub fn from_timestamp( + py: Python<'py>, timestamp: f64, time_zone_info: Option<&PyTzInfo>, - ) -> PyResult<&'p PyDateTime> { + ) -> PyResult { let timestamp: PyObject = timestamp.to_object(py); let time_zone_info: PyObject = match time_zone_info { @@ -194,7 +196,7 @@ impl PyDateTime { } } -impl PyDateAccess for PyDateTime { +impl PyDateAccess for PyDateTime<'_> { fn get_year(&self) -> i32 { unsafe { PyDateTime_GET_YEAR(self.as_ptr()) as i32 } } @@ -208,7 +210,7 @@ impl PyDateAccess for PyDateTime { } } -impl PyTimeAccess for PyDateTime { +impl PyTimeAccess for PyDateTime<'_> { fn get_hour(&self) -> u8 { unsafe { PyDateTime_DATE_GET_HOUR(self.as_ptr()) as u8 } } @@ -232,24 +234,25 @@ impl PyTimeAccess for PyDateTime { } /// Bindings for `datetime.time` -pub struct PyTime(PyObject, Unsendable); +pub struct PyTime<'py>(PyAny<'py>); pyobject_native_type!( - PyTime, + PyTime<'py>, crate::ffi::PyDateTime_Time, *PyDateTimeAPI.TimeType, Some("datetime"), - PyTime_Check + PyTime_Check, + type_marker::Time ); -impl PyTime { - pub fn new<'p>( - py: Python<'p>, +impl<'py> PyTime<'py> { + pub fn new( + py: Python<'py>, hour: u8, minute: u8, second: u8, microsecond: u32, tzinfo: Option<&PyObject>, - ) -> PyResult<&'p PyTime> { + ) -> PyResult { unsafe { let ptr = (PyDateTimeAPI.Time_FromTime)( c_int::from(hour), @@ -267,15 +270,15 @@ impl PyTime { /// Alternate constructor that takes a `fold` argument /// /// First available in Python 3.6. - pub fn new_with_fold<'p>( - py: Python<'p>, + pub fn new_with_fold( + py: Python<'py>, hour: u8, minute: u8, second: u8, microsecond: u32, tzinfo: Option<&PyObject>, fold: bool, - ) -> PyResult<&'p PyTime> { + ) -> PyResult { unsafe { let ptr = (PyDateTimeAPI.Time_FromTimeAndFold)( c_int::from(hour), @@ -291,7 +294,7 @@ impl PyTime { } } -impl PyTimeAccess for PyTime { +impl PyTimeAccess for PyTime<'_> { fn get_hour(&self) -> u8 { unsafe { PyDateTime_TIME_GET_HOUR(self.as_ptr()) as u8 } } @@ -317,33 +320,35 @@ impl PyTimeAccess for PyTime { /// Bindings for `datetime.tzinfo` /// /// This is an abstract base class and should not be constructed directly. -pub struct PyTzInfo(PyObject, Unsendable); +pub struct PyTzInfo<'py>(PyAny<'py>); pyobject_native_type!( - PyTzInfo, + PyTzInfo<'py>, crate::ffi::PyObject, *PyDateTimeAPI.TZInfoType, Some("datetime"), - PyTZInfo_Check + PyTZInfo_Check, + type_marker::TzInfo ); /// Bindings for `datetime.timedelta` -pub struct PyDelta(PyObject, Unsendable); +pub struct PyDelta<'py>(PyAny<'py>); pyobject_native_type!( - PyDelta, + PyDelta<'py>, crate::ffi::PyDateTime_Delta, *PyDateTimeAPI.DeltaType, Some("datetime"), - PyDelta_Check + PyDelta_Check, + type_marker::Delta ); -impl PyDelta { - pub fn new<'p>( - py: Python<'p>, +impl<'py> PyDelta<'py> { + pub fn new( + py: Python<'py>, days: i32, seconds: i32, microseconds: i32, normalize: bool, - ) -> PyResult<&'p PyDelta> { + ) -> PyResult { unsafe { let ptr = (PyDateTimeAPI.Delta_FromDelta)( days as c_int, @@ -357,7 +362,7 @@ impl PyDelta { } } -impl PyDeltaAccess for PyDelta { +impl PyDeltaAccess for PyDelta<'_> { fn get_days(&self) -> i32 { unsafe { PyDateTime_DELTA_GET_DAYS(self.as_ptr()) as i32 } } diff --git a/src/types/dict.rs b/src/types/dict.rs index caee04eca77..63126067bfc 100644 --- a/src/types/dict.rs +++ b/src/types/dict.rs @@ -2,9 +2,9 @@ use crate::err::{self, PyErr, PyResult}; use crate::instance::PyNativeType; -use crate::internal_tricks::Unsendable; use crate::object::PyObject; use crate::types::{PyAny, PyList}; +use crate::type_marker; use crate::AsPyPointer; #[cfg(not(PyPy))] use crate::IntoPyPointer; @@ -17,19 +17,20 @@ use std::{cmp, collections, hash}; /// Represents a Python `dict`. #[repr(transparent)] -pub struct PyDict(PyObject, Unsendable); +pub struct PyDict<'py>(PyAny<'py>); pyobject_native_type!( - PyDict, + PyDict<'py>, ffi::PyDictObject, ffi::PyDict_Type, - ffi::PyDict_Check + ffi::PyDict_Check, + type_marker::Dict ); -impl PyDict { +impl<'py> PyDict<'py> { /// Creates a new empty dictionary. - pub fn new(py: Python) -> &PyDict { - unsafe { py.from_owned_ptr::(ffi::PyDict_New()) } + pub fn new(py: Python<'py>) -> Self { + unsafe { py.from_owned_ptr(ffi::PyDict_New()) } } /// Creates a new dictionary from the sequence given. @@ -40,10 +41,10 @@ impl PyDict { /// Returns an error on invalid input. In the case of key collisions, /// this keeps the last entry seen. #[cfg(not(PyPy))] - pub fn from_sequence(py: Python, seq: PyObject) -> PyResult<&PyDict> { + pub fn from_sequence(py: Python<'py>, seq: &PyAny) -> PyResult { unsafe { let dict = py.from_owned_ptr::(ffi::PyDict_New()); - match ffi::PyDict_MergeFromSeq2(dict.into_ptr(), seq.into_ptr(), 1i32) { + match ffi::PyDict_MergeFromSeq2(dict.as_ptr(), seq.into_ptr(), 1i32) { 0 => Ok(dict), -1 => Err(PyErr::fetch(py)), _ => unreachable!(), @@ -54,7 +55,7 @@ impl PyDict { /// Returns a new dictionary that contains the same key-value pairs as self. /// /// This is equivalent to the Python expression `dict(self)`. - pub fn copy(&self) -> PyResult<&PyDict> { + pub fn copy(&self) -> PyResult { unsafe { self.py() .from_owned_ptr_or_err::(ffi::PyDict_Copy(self.as_ptr())) @@ -139,30 +140,30 @@ impl PyDict { /// Returns a list of dict keys. /// /// This is equivalent to the Python expression `list(dict.keys())`. - pub fn keys(&self) -> &PyList { + pub fn keys(&self) -> PyList<'py> { unsafe { self.py() - .from_owned_ptr::(ffi::PyDict_Keys(self.as_ptr())) + .from_owned_ptr(ffi::PyDict_Keys(self.as_ptr())) } } /// Returns a list of dict values. /// /// This is equivalent to the Python expression `list(dict.values())`. - pub fn values(&self) -> &PyList { + pub fn values(&self) -> PyList<'py> { unsafe { self.py() - .from_owned_ptr::(ffi::PyDict_Values(self.as_ptr())) + .from_owned_ptr(ffi::PyDict_Values(self.as_ptr())) } } /// Returns a list of dict items. /// /// This is equivalent to the Python expression `list(dict.items())`. - pub fn items(&self) -> &PyList { + pub fn items(&self) -> PyList<'py> { unsafe { self.py() - .from_owned_ptr::(ffi::PyDict_Items(self.as_ptr())) + .from_owned_ptr(ffi::PyDict_Items(self.as_ptr())) } } @@ -170,21 +171,21 @@ impl PyDict { /// /// Note that it's unsafe to use when the dictionary might be changed by /// other code. - pub fn iter(&self) -> PyDictIterator { + pub fn iter(&self) -> PyDictIterator<'_, 'py> { PyDictIterator { - dict: self.as_ref(), + dict: self, pos: 0, } } } -pub struct PyDictIterator<'py> { - dict: &'py PyAny, +pub struct PyDictIterator<'a, 'py> { + dict: &'a PyDict<'py>, pos: isize, } -impl<'py> Iterator for PyDictIterator<'py> { - type Item = (&'py PyAny, &'py PyAny); +impl<'a, 'py> Iterator for PyDictIterator<'a, 'py> { + type Item = (&'a PyAny<'py>, &'a PyAny<'py>); #[inline] fn next(&mut self) -> Option { @@ -201,9 +202,9 @@ impl<'py> Iterator for PyDictIterator<'py> { } } -impl<'a> std::iter::IntoIterator for &'a PyDict { - type Item = (&'a PyAny, &'a PyAny); - type IntoIter = PyDictIterator<'a>; +impl<'a, 'py> std::iter::IntoIterator for &'a PyDict<'py> { + type Item = (&'a PyAny<'py>, &'a PyAny<'py>); + type IntoIter = PyDictIterator<'a, 'py>; fn into_iter(self) -> Self::IntoIter { self.iter() @@ -263,7 +264,7 @@ where pub trait IntoPyDict { /// Converts self into a `PyDict` object pointer. Whether pointer owned or borrowed /// depends on implementation. - fn into_py_dict(self, py: Python) -> &PyDict; + fn into_py_dict(self, py: Python) -> PyDict; } impl IntoPyDict for I @@ -271,7 +272,7 @@ where T: PyDictItem, I: IntoIterator, { - fn into_py_dict(self, py: Python) -> &PyDict { + fn into_py_dict(self, py: Python) -> PyDict { let dict = PyDict::new(py); for item in self { dict.set_item(item.key(), item.value()) @@ -319,13 +320,13 @@ where } } -impl<'source, K, V, S> FromPyObject<'source> for HashMap +impl<'a, 'py, K, V, S> FromPyObject<'a, 'py> for HashMap where - K: FromPyObject<'source> + cmp::Eq + hash::Hash, - V: FromPyObject<'source>, + K: FromPyObject<'a, 'py> + cmp::Eq + hash::Hash, + V: FromPyObject<'a, 'py>, S: hash::BuildHasher + Default, { - fn extract(ob: &'source PyAny) -> Result { + fn extract(ob: &'a PyAny<'py>) -> Result { let dict = ::try_from(ob)?; let mut ret = HashMap::default(); for (k, v) in dict.iter() { @@ -335,12 +336,12 @@ where } } -impl<'source, K, V> FromPyObject<'source> for BTreeMap +impl<'a, 'py, K, V> FromPyObject<'a, 'py> for BTreeMap where - K: FromPyObject<'source> + cmp::Ord, - V: FromPyObject<'source>, + K: FromPyObject<'a, 'py> + cmp::Ord, + V: FromPyObject<'a, 'py>, { - fn extract(ob: &'source PyAny) -> Result { + fn extract(ob: &'a PyAny<'py>) -> Result { let dict = ::try_from(ob)?; let mut ret = BTreeMap::new(); for (k, v) in dict.iter() { @@ -379,7 +380,7 @@ mod test { let gil = Python::acquire_gil(); let py = gil.python(); let items = PyList::new(py, &vec![("a", 1), ("b", 2)]); - let dict = PyDict::from_sequence(py, items.to_object(py)).unwrap(); + let dict = PyDict::from_sequence(py, &items).unwrap(); assert_eq!(1, dict.get_item("a").unwrap().extract::().unwrap()); assert_eq!(2, dict.get_item("b").unwrap().extract::().unwrap()); let map: HashMap<&str, i32> = [("a", 1), ("b", 2)].iter().cloned().collect(); @@ -393,7 +394,7 @@ mod test { let gil = Python::acquire_gil(); let py = gil.python(); let items = PyList::new(py, &vec!["a", "b"]); - assert!(PyDict::from_sequence(py, items.to_object(py)).is_err()); + assert!(PyDict::from_sequence(py, &items).is_err()); } #[test] diff --git a/src/types/floatob.rs b/src/types/floatob.rs index 7629d562774..771c3a2ee30 100644 --- a/src/types/floatob.rs +++ b/src/types/floatob.rs @@ -1,10 +1,9 @@ // Copyright (c) 2017-present PyO3 Project and Contributors // // based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython -use crate::internal_tricks::Unsendable; use crate::{ ffi, AsPyPointer, FromPy, FromPyObject, ObjectProtocol, PyAny, PyErr, PyNativeType, PyObject, - PyResult, Python, ToPyObject, + PyResult, Python, ToPyObject, type_marker, }; use std::os::raw::c_double; @@ -15,18 +14,19 @@ use std::os::raw::c_double; /// and [extract](struct.PyObject.html#method.extract) /// with `f32`/`f64`. #[repr(transparent)] -pub struct PyFloat(PyObject, Unsendable); +pub struct PyFloat<'py>(PyAny<'py>); pyobject_native_type!( - PyFloat, + PyFloat<'py>, ffi::PyFloatObject, ffi::PyFloat_Type, - ffi::PyFloat_Check + ffi::PyFloat_Check, + type_marker::Float ); -impl PyFloat { +impl<'py> PyFloat<'py> { /// Creates a new Python `float` object. - pub fn new(py: Python<'_>, val: c_double) -> &PyFloat { + pub fn new(py: Python<'py>, val: c_double) -> Self { unsafe { py.from_owned_ptr(ffi::PyFloat_FromDouble(val)) } } @@ -48,10 +48,10 @@ impl FromPy for PyObject { } } -impl<'source> FromPyObject<'source> for f64 { +impl FromPyObject<'_, '_> for f64 { // PyFloat_AsDouble returns -1.0 upon failure #![cfg_attr(feature = "cargo-clippy", allow(clippy::float_cmp))] - fn extract(obj: &'source PyAny) -> PyResult { + fn extract(obj: &PyAny) -> PyResult { let v = unsafe { ffi::PyFloat_AsDouble(obj.as_ptr()) }; if v == -1.0 && PyErr::occurred(obj.py()) { @@ -74,8 +74,8 @@ impl FromPy for PyObject { } } -impl<'source> FromPyObject<'source> for f32 { - fn extract(obj: &'source PyAny) -> PyResult { +impl FromPyObject<'_, '_> for f32 { + fn extract(obj: &PyAny) -> PyResult { Ok(obj.extract::()? as f32) } } diff --git a/src/types/iterator.rs b/src/types/iterator.rs index 88f5fc78814..b37b78bdd78 100644 --- a/src/types/iterator.rs +++ b/src/types/iterator.rs @@ -2,11 +2,12 @@ // // based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython +use crate::conversion::PyTryFrom; use crate::{ffi, AsPyPointer, PyAny, PyDowncastError, PyErr, PyNativeType, PyResult, Python}; /// A Python iterator object. /// -/// Unlike other Python objects, this class includes a `Python<'p>` token +/// Unlike other Python objects, this class includes a `Python<'py>` token /// so that `PyIterator` can implement the Rust `Iterator` trait. /// /// # Example @@ -25,11 +26,15 @@ use crate::{ffi, AsPyPointer, PyAny, PyDowncastError, PyErr, PyNativeType, PyRes /// # Ok(()) /// # } /// ``` -pub struct PyIterator<'p>(&'p PyAny); +pub struct PyIterator<'py>(PyAny<'py>); -impl<'p> PyIterator<'p> { +pyobject_native_type_named!(PyIterator<'py>); +pyobject_native_type_extract!(PyIterator<'py>); +pyobject_native_newtype!(PyIterator<'py>); + +impl<'py> PyIterator<'py> { /// Constructs a `PyIterator` from a Python iterator object. - pub fn from_object(py: Python<'p>, obj: &T) -> Result, PyDowncastError> + pub fn from_object(py: Python<'py>, obj: &T) -> Result, PyDowncastError> where T: AsPyPointer, { @@ -42,8 +47,7 @@ impl<'p> PyIterator<'p> { } if ffi::PyIter_Check(ptr) != 0 { - // this is not right, but this cause of segfault check #71 - Ok(PyIterator(py.from_borrowed_ptr(ptr))) + Ok(py.from_owned_ptr(ptr)) } else { Err(PyDowncastError) } @@ -51,8 +55,8 @@ impl<'p> PyIterator<'p> { } } -impl<'p> Iterator for PyIterator<'p> { - type Item = PyResult<&'p PyAny>; +impl<'py> Iterator for PyIterator<'py> { + type Item = PyResult>; /// Retrieves the next item from an iterator. /// @@ -76,10 +80,25 @@ impl<'p> Iterator for PyIterator<'p> { } } -/// Dropping a `PyIterator` instance decrements the reference count on the object by 1. -impl<'p> Drop for PyIterator<'p> { - fn drop(&mut self) { - unsafe { ffi::Py_DECREF(self.0.as_ptr()) } +impl<'py> PyTryFrom<'py> for PyIterator<'py> { + fn try_from<'a>(value: &'a PyAny<'py>) -> Result<&'a PyIterator<'py>, PyDowncastError> { + unsafe { + if ffi::PyIter_Check(value.as_ptr()) != 0 { + Ok(::try_from_unchecked(value)) + } else { + Err(PyDowncastError) + } + } + } + + fn try_from_exact<'a>(value: &'a PyAny<'py>) -> Result<&'a PyIterator<'py>, PyDowncastError> { + ::try_from(value) + } + + #[inline] + unsafe fn try_from_unchecked<'a>(value: &'a PyAny<'py>) -> &'a PyIterator<'py> { + let ptr = value as *const _ as *const PyIterator; + &*ptr } } @@ -174,9 +193,9 @@ mod tests { let py = gil.python(); let context = PyDict::new(py); - py.run(fibonacci_generator, None, Some(context)).unwrap(); + py.run(fibonacci_generator, None, Some(&context)).unwrap(); - let generator = py.eval("fibonacci(5)", None, Some(context)).unwrap(); + let generator = py.eval("fibonacci(5)", None, Some(&context)).unwrap(); for (actual, expected) in generator.iter().unwrap().zip(&[1, 1, 2, 3, 5]) { let actual = actual.unwrap().extract::().unwrap(); assert_eq!(actual, *expected) diff --git a/src/types/list.rs b/src/types/list.rs index 1ecfa1ff8ff..ca2b2e8a4ec 100644 --- a/src/types/list.rs +++ b/src/types/list.rs @@ -4,21 +4,20 @@ use crate::err::{self, PyResult}; use crate::ffi::{self, Py_ssize_t}; -use crate::internal_tricks::Unsendable; use crate::{ AsPyPointer, IntoPy, IntoPyPointer, PyAny, PyNativeType, PyObject, Python, ToBorrowedObject, - ToPyObject, + ToPyObject, type_marker }; /// Represents a Python `list`. #[repr(transparent)] -pub struct PyList(PyObject, Unsendable); +pub struct PyList<'py>(PyAny<'py>); -pyobject_native_var_type!(PyList, ffi::PyList_Type, ffi::PyList_Check); +pyobject_native_var_type!(PyList<'py>, ffi::PyList_Type, ffi::PyList_Check, type_marker::List); -impl PyList { +impl<'py> PyList<'py> { /// Constructs a new list with the given elements. - pub fn new(py: Python<'_>, elements: impl IntoIterator) -> &PyList + pub fn new(py: Python<'py>, elements: impl IntoIterator) -> Self where T: ToPyObject, U: ExactSizeIterator, @@ -36,7 +35,7 @@ impl PyList { } /// Constructs a new empty list. - pub fn empty(py: Python) -> &PyList { + pub fn empty(py: Python<'py>) -> Self { unsafe { py.from_owned_ptr::(ffi::PyList_New(0)) } } @@ -54,7 +53,7 @@ impl PyList { /// Gets the item at the specified index. /// /// Panics if the index is out of range. - pub fn get_item(&self, index: isize) -> &PyAny { + pub fn get_item(&self, index: isize) -> &PyAny<'py> { unsafe { self.py() .from_borrowed_ptr(ffi::PyList_GetItem(self.as_ptr(), index as Py_ssize_t)) @@ -111,7 +110,7 @@ impl PyList { } /// Returns an iterator over this list's items. - pub fn iter(&self) -> PyListIterator { + pub fn iter(&self) -> PyListIterator<'_, 'py> { PyListIterator { list: self, index: 0, @@ -130,16 +129,16 @@ impl PyList { } /// Used by `PyList::iter()`. -pub struct PyListIterator<'a> { - list: &'a PyList, +pub struct PyListIterator<'a, 'py> { + list: &'a PyList<'py>, index: isize, } -impl<'a> Iterator for PyListIterator<'a> { - type Item = &'a PyAny; +impl<'a, 'py> Iterator for PyListIterator<'a, 'py> { + type Item = &'a PyAny<'py>; #[inline] - fn next(&mut self) -> Option<&'a PyAny> { + fn next(&mut self) -> Option<&'a PyAny<'py>> { if self.index < self.list.len() as isize { let item = self.list.get_item(self.index); self.index += 1; @@ -150,9 +149,9 @@ impl<'a> Iterator for PyListIterator<'a> { } } -impl<'a> std::iter::IntoIterator for &'a PyList { - type Item = &'a PyAny; - type IntoIter = PyListIterator<'a>; +impl<'a, 'py> std::iter::IntoIterator for &'a PyList<'py> { + type Item = &'a PyAny<'py>; + type IntoIter = PyListIterator<'a, 'py>; fn into_iter(self) -> Self::IntoIter { self.iter() diff --git a/src/types/mod.rs b/src/types/mod.rs index a6bf3942fee..b43179144ee 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -26,92 +26,140 @@ pub use self::tuple::PyTuple; pub use self::typeobject::PyType; #[macro_export] -macro_rules! pyobject_native_type_named ( - ($name: ty $(,$type_param: ident)*) => { - impl<$($type_param,)*> ::std::convert::AsRef<$crate::PyAny> for $name { +macro_rules! pyobject_native_type_common ( + ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >) => { + unsafe impl<'py $(, $type_param $(: $bound)?)*> $crate::PyNativeType<'py> for $name<'py $(,$type_param)*> {} + + impl<'py $(, $type_param $(: $bound)?)*> $crate::AsPyPointer for $name<'py $(,$type_param)*> { + /// Gets the underlying FFI pointer, returns a borrowed pointer. #[inline] - fn as_ref(&self) -> &$crate::PyAny { - unsafe{&*(self as *const $name as *const $crate::PyAny)} + fn as_ptr(&self) -> *mut $crate::ffi::PyObject { + self.0.as_ptr() } } - unsafe impl<$($type_param,)*> $crate::PyNativeType for $name {} - - impl<$($type_param,)*> $crate::AsPyPointer for $name { + impl<'py $(, $type_param $(: $bound)?)*> $crate::IntoPyPointer for $name<'py $(,$type_param)*> { /// Gets the underlying FFI pointer, returns a borrowed pointer. #[inline] - fn as_ptr(&self) -> *mut $crate::ffi::PyObject { - self.0.as_ptr() + fn into_ptr(self) -> *mut $crate::ffi::PyObject { + use $crate::AsPyPointer; + let ptr = self.as_ptr(); + std::mem::forget(self); + ptr } } - impl<$($type_param,)*> PartialEq for $name { + impl<'py $(, $type_param $(: $bound)?)*> PartialEq for $name<'py $(,$type_param)*> { #[inline] - fn eq(&self, o: &$name) -> bool { + fn eq(&self, o: &$name<'py $(,$type_param)*>) -> bool { use $crate::AsPyPointer; self.as_ptr() == o.as_ptr() } } + + impl<'py $(, $type_param $(: $bound)?)*> $crate::ToPyObject for $name<'py $(,$type_param)*> + { + #[inline] + fn to_object(&self, py: $crate::Python) -> $crate::PyObject { + use $crate::AsPyPointer; + unsafe {$crate::PyObject::from_borrowed_ptr(py, self.as_ptr())} + } + } + + impl<'py $(, $type_param $(: $bound)?)*> $crate::IntoPy<$crate::PyObject> for $name<'py $(,$type_param)*> { + fn into_py(self, py: $crate::Python) -> $crate::PyObject { + use $crate::IntoPyPointer; + unsafe { $crate::PyObject::from_owned_ptr(py, self.into_ptr()) } + } + } + + impl<'a, 'py $(, $type_param $(: $bound)?)*> $crate::FromPyObject<'a, 'py> for $name<'py $(,$type_param)*> { + fn extract(any: &'a $crate::PyAny<'py>) -> $crate::PyResult<$name<'py $(,$type_param)*>> { + use $crate::{AsPyPointer, PyNativeType}; + unsafe { $crate::FromPyPointer::from_borrowed_ptr_or_err(any.py(), any.as_ptr()).map(Clone::clone) } + } + } + } +); + +#[macro_export] +macro_rules! pyobject_native_type_named ( + ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >) => { + impl<'py $(, $type_param $(: $bound)?)*> ::std::fmt::Debug for $name<'py $(,$type_param)*> { + fn fmt(&self, f: &mut ::std::fmt::Formatter) + -> Result<(), ::std::fmt::Error> + { + use $crate::ObjectProtocol; + let s = self.repr().map_err(|_| ::std::fmt::Error)?; + f.write_str(&s.to_string_lossy()) + } + } + + impl<'py $(, $type_param $(: $bound)?)*> ::std::fmt::Display for $name<'py $(,$type_param)*> { + fn fmt(&self, f: &mut ::std::fmt::Formatter) + -> Result<(), ::std::fmt::Error> + { + use $crate::ObjectProtocol; + let s = self.str().map_err(|_| ::std::fmt::Error)?; + f.write_str(&s.to_string_lossy()) + } + } }; ); #[macro_export] macro_rules! pyobject_native_type { - ($name: ty, $layout: path, $typeobject: expr, $module: expr, $checkfunction: path $(,$type_param: ident)*) => { - unsafe impl $crate::type_object::PyLayout<$name> for $layout {} - impl $crate::type_object::PySizedLayout<$name> for $layout {} - impl $crate::derive_utils::PyBaseTypeUtils for $name { + ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >, $layout: path, $typeobject: expr, $module: expr, $checkfunction: path, $typemarker: path) => { + impl<'py $(, $type_param $(: $bound)?)*> $crate::type_object::PySizedLayout<'py, $typemarker> for $layout {} + impl<'py $(, $type_param $(: $bound)?)*> $crate::derive_utils::PyBaseTypeUtils<'py> for $name<'py $(,$type_param)*> { type Dict = $crate::pyclass_slots::PyClassDummySlot; type WeakRef = $crate::pyclass_slots::PyClassDummySlot; - type LayoutAsBase = $crate::pycell::PyCellBase<$name>; - type BaseNativeType = $name; + type LayoutAsBase = $crate::pycell::PyCellBase<'py, $typemarker>; + type RootType = Self; } - pyobject_native_type_named!($name $(,$type_param)*); - pyobject_native_type_convert!($name, $layout, $typeobject, $module, $checkfunction $(,$type_param)*); - pyobject_native_type_extract!($name $(,$type_param)*); - - impl<'a, $($type_param,)*> ::std::convert::From<&'a $name> for &'a $crate::PyAny { - fn from(ob: &'a $name) -> Self { - unsafe{&*(ob as *const $name as *const $crate::PyAny)} - } + impl<'py $(, $type_param $(: $bound)?)*> $crate::derive_utils::PyBaseTypeUtils<'py> for $typemarker { + type Dict = $crate::pyclass_slots::PyClassDummySlot; + type WeakRef = $crate::pyclass_slots::PyClassDummySlot; + type LayoutAsBase = $crate::pycell::PyCellBase<'py, $typemarker>; + type RootType = Self; } + + pyobject_native_type_named!($name<'py $(, $type_param $(: $bound)?)*>); + pyobject_native_newtype!($name<'py $(, $type_param $(: $bound)?)*>); + pyobject_native_type_info!($name<'py $(, $type_param $(: $bound)?)*>, $layout, $typeobject, $module, $checkfunction, $typemarker); + pyobject_native_type_extract!($name<'py $(, $type_param $(: $bound)?)*>); }; - ($name: ty, $layout: path, $typeobject: expr, $checkfunction: path $(,$type_param: ident)*) => { + ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >, $layout: path, $typeobject: expr, $checkfunction: path, $typemarker: path) => { pyobject_native_type! { - $name, $layout, $typeobject, Some("builtins"), $checkfunction $(,$type_param)* + $name<'py $(, $type_param $(: $bound)?)*>, $layout, $typeobject, Some("builtins"), $checkfunction, $typemarker } }; } #[macro_export] macro_rules! pyobject_native_var_type { - ($name: ty, $typeobject: expr, $module: expr, $checkfunction: path $(,$type_param: ident)*) => { - unsafe impl $crate::type_object::PyLayout<$name> for $crate::ffi::PyObject {} - pyobject_native_type_named!($name $(,$type_param)*); - pyobject_native_type_convert!($name, $crate::ffi::PyObject, - $typeobject, $module, $checkfunction $(,$type_param)*); - pyobject_native_type_extract!($name $(,$type_param)*); - - impl<'a, $($type_param,)*> ::std::convert::From<&'a $name> for &'a $crate::PyAny { - fn from(ob: &'a $name) -> Self { - unsafe{&*(ob as *const $name as *const $crate::PyAny)} - } - } + ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >, $typeobject: expr, $module: expr, $checkfunction: path, $typemarker: path) => { + pyobject_native_newtype!($name<'py $(, $type_param $(: $bound)?)*>); + pyobject_native_type_named!($name<'py $(, $type_param $(: $bound)?)*>); + pyobject_native_type_info!($name<'py $(, $type_param $(: $bound)?)*>, $crate::ffi::PyObject, + $typeobject, $module, $checkfunction, $typemarker); + pyobject_native_type_extract!($name<'py $(, $type_param $(: $bound)?)*>); }; - ($name: ty, $typeobject: expr, $checkfunction: path $(,$type_param: ident)*) => { + ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >, $typeobject: expr, $checkfunction: path, $typemarker: path) => { pyobject_native_var_type! { - $name, $typeobject, Some("builtins"), $checkfunction $(,$type_param)* + $name<'py $(, $type_param $(: $bound)?)*>, $typeobject, Some("builtins"), $checkfunction, $typemarker } }; } -// NOTE: This macro is not included in pyobject_native_type_convert! +// NOTE: This macro is not included in pyobject_native_newtype! // because rust-numpy has a special implementation. +#[macro_export] macro_rules! pyobject_native_type_extract { - ($name: ty $(,$type_param: ident)*) => { - impl<'py, $($type_param,)*> $crate::FromPyObject<'py> for &'py $name { - fn extract(obj: &'py $crate::PyAny) -> $crate::PyResult { + ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >) => { + impl<'a, 'py $(, $type_param $(: $bound)?)*> $crate::FromPyObject<'a, 'py> for &'a $name<'py $(,$type_param)*> { + fn extract(obj: &'a $crate::PyAny<'py>) -> $crate::PyResult { $crate::PyTryFrom::try_from(obj).map_err(Into::into) } } @@ -119,16 +167,12 @@ macro_rules! pyobject_native_type_extract { } #[macro_export] -macro_rules! pyobject_native_type_convert( - ($name: ty, $layout: path, $typeobject: expr, - $module: expr, $checkfunction: path $(,$type_param: ident)*) => { - unsafe impl<$($type_param,)*> $crate::type_object::PyTypeInfo for $name { - type Type = (); - type BaseType = $crate::PyAny; - type Layout = $layout; - type BaseLayout = ffi::PyObject; - type Initializer = $crate::pyclass_init::PyNativeTypeInitializer; - type AsRefTarget = Self; +macro_rules! pyobject_native_type_info( + ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >, $layout: path, $typeobject: expr, + $module: expr, $checkfunction: path, $typemarker: path) => { + + unsafe impl<'py $(, $type_param $(: $bound)?)*> $crate::type_object::PyTypeInfo<'py> for $name<'py $(,$type_param)*> { + type Type = $typemarker; const NAME: &'static str = stringify!($name); const MODULE: Option<&'static str> = $module; @@ -144,33 +188,59 @@ macro_rules! pyobject_native_type_convert( unsafe { $checkfunction(ptr.as_ptr()) > 0 } } } + }; - impl<$($type_param,)*> $crate::ToPyObject for $name - { + ($name: ident < 'py $( ,$type_param: ident $(: $bound: path)? )* >, $layout: path, $typeobject: expr, $checkfunction: path, $typemarker: path) => { + pyobject_native_type_info! { + $name<'py $(, $type_param $(: $bound)?)*>, $layout, $typeobject, Some("builtins"), $checkfunction, $typemarker + } + }; +); + +#[macro_export] +macro_rules! pyobject_native_newtype( + ($name: ident < 'py $( ,$type_param: ident)* > ) => { + pyobject_native_type_common!($name<'py $(,$type_param)*>); + + impl<'a, 'py, $($type_param,)*> ::std::convert::From<&'a $name<'py $(,$type_param)*>> for &'a $crate::PyAny<'a> { + fn from(ob: &'a $name<'py $(,$type_param)*>) -> Self { + unsafe{&*(ob as *const _ as *const $crate::PyAny)} + } + } + + impl<'py, $($type_param,)*> ::std::convert::AsRef<$crate::PyAny<'py>> for $name<'py $(,$type_param)*> { #[inline] - fn to_object(&self, py: $crate::Python) -> $crate::PyObject { - use $crate::AsPyPointer; - unsafe {$crate::PyObject::from_borrowed_ptr(py, self.0.as_ptr())} + fn as_ref(&self) -> &$crate::PyAny<'py> { + &self.0 } } - impl<$($type_param,)*> ::std::fmt::Debug for $name { - fn fmt(&self, f: &mut ::std::fmt::Formatter) - -> Result<(), ::std::fmt::Error> - { - use $crate::ObjectProtocol; - let s = self.repr().map_err(|_| ::std::fmt::Error)?; - f.write_str(&s.to_string_lossy()) + impl<'py, $($type_param,)*> ::std::ops::Deref for $name<'py $(,$type_param)*> { + type Target = $crate::PyAny<'py>; + + #[inline] + fn deref(&self) -> &$crate::PyAny<'py> { + &self.0 } } - impl<$($type_param,)*> ::std::fmt::Display for $name { - fn fmt(&self, f: &mut ::std::fmt::Formatter) - -> Result<(), ::std::fmt::Error> - { - use $crate::ObjectProtocol; - let s = self.str().map_err(|_| ::std::fmt::Error)?; - f.write_str(&s.to_string_lossy()) + unsafe impl<'py $(,$type_param)*> $crate::FromPyPointer<'py> for $name<'py $(,$type_param)*> + { + unsafe fn from_owned_ptr_or_opt(py: $crate::Python<'py>, ptr: *mut $crate::ffi::PyObject) -> Option { + ::std::ptr::NonNull::new(ptr).map(|p| Self(PyAny::from_non_null(py, p))) + } + unsafe fn from_borrowed_ptr_or_opt( + py: $crate::Python<'py>, + ptr: *mut $crate::ffi::PyObject, + ) -> Option<&'py Self> { + use $crate::type_object::PyDowncastImpl; + ::std::ptr::NonNull::new(ptr).map(|p| Self::unchecked_downcast($crate::gil::register_borrowed(py, p))) + } + } + + impl<'py $(,$type_param)*> Clone for $name<'py $(,$type_param)*> { + fn clone(&self) -> Self { + Self(self.0.clone()) } } }; diff --git a/src/types/module.rs b/src/types/module.rs index 77532d9801f..944ce2524ec 100644 --- a/src/types/module.rs +++ b/src/types/module.rs @@ -6,13 +6,13 @@ use crate::err::{PyErr, PyResult}; use crate::exceptions; use crate::ffi; use crate::instance::PyNativeType; -use crate::internal_tricks::Unsendable; use crate::object::PyObject; use crate::objectprotocol::ObjectProtocol; use crate::pyclass::PyClass; use crate::type_object::PyTypeObject; -use crate::types::PyTuple; use crate::types::{PyAny, PyDict, PyList}; +use crate::type_marker; +use crate::type_marker::Tuple; use crate::{AsPyPointer, IntoPy, Py, Python, ToPyObject}; use std::ffi::{CStr, CString}; use std::os::raw::c_char; @@ -20,19 +20,19 @@ use std::str; /// Represents a Python `module` object. #[repr(transparent)] -pub struct PyModule(PyObject, Unsendable); +pub struct PyModule<'py>(PyAny<'py>); -pyobject_native_var_type!(PyModule, ffi::PyModule_Type, ffi::PyModule_Check); +pyobject_native_var_type!(PyModule<'py>, ffi::PyModule_Type, ffi::PyModule_Check, type_marker::Module); -impl PyModule { +impl<'py> PyModule<'py> { /// Creates a new module object with the `__name__` attribute set to name. - pub fn new<'p>(py: Python<'p>, name: &str) -> PyResult<&'p PyModule> { + pub fn new(py: Python<'py>, name: &str) -> PyResult { let name = CString::new(name)?; unsafe { py.from_owned_ptr_or_err(ffi::PyModule_New(name.as_ptr())) } } /// Imports the Python module with the specified name. - pub fn import<'p>(py: Python<'p>, name: &str) -> PyResult<&'p PyModule> { + pub fn import(py: Python<'py>, name: &str) -> PyResult { let name = CString::new(name)?; unsafe { py.from_owned_ptr_or_err(ffi::PyImport_ImportModule(name.as_ptr())) } } @@ -43,12 +43,12 @@ impl PyModule { /// `file_name` is the file name to associate with the module /// (this is used when Python reports errors, for example). /// `module_name` is the name to give the module. - pub fn from_code<'p>( - py: Python<'p>, + pub fn from_code( + py: Python<'py>, code: &str, file_name: &str, module_name: &str, - ) -> PyResult<&'p PyModule> { + ) -> PyResult { let data = CString::new(code)?; let filename = CString::new(file_name)?; let module = CString::new(module_name)?; @@ -64,7 +64,7 @@ impl PyModule { return Err(PyErr::fetch(py)); } - <&PyModule as crate::FromPyObject>::extract(py.from_owned_ptr_or_err(mptr)?) + py.from_owned_ptr_or_err(mptr) } } @@ -78,13 +78,13 @@ impl PyModule { } /// Return the index (`__all__`) of the module, creating one if needed. - pub fn index(&self) -> PyResult<&PyList> { + pub fn index(&self) -> PyResult> { match self.getattr("__all__") { - Ok(idx) => idx.downcast().map_err(PyErr::from), + Ok(idx) => idx.downcast().map(Clone::clone).map_err(PyErr::from), Err(err) => { if err.is_instance::(self.py()) { let l = PyList::empty(self.py()); - self.setattr("__all__", l).map_err(PyErr::from)?; + self.setattr("__all__", &l).map_err(PyErr::from)?; Ok(l) } else { Err(err) @@ -101,7 +101,7 @@ impl PyModule { match str::from_utf8(slice) { Ok(s) => Ok(s), Err(e) => Err(PyErr::from_instance( - exceptions::UnicodeDecodeError::new_utf8(self.py(), slice, e)?, + &exceptions::UnicodeDecodeError::new_utf8(self.py(), slice, e)?, )), } } @@ -127,30 +127,30 @@ impl PyModule { pub fn call( &self, name: &str, - args: impl IntoPy>, + args: impl IntoPy>, kwargs: Option<&PyDict>, - ) -> PyResult<&PyAny> { + ) -> PyResult> { self.getattr(name)?.call(args, kwargs) } /// Calls a function in the module with only positional arguments. /// /// This is equivalent to the Python expression `module.name(*args)`. - pub fn call1(&self, name: &str, args: impl IntoPy>) -> PyResult<&PyAny> { + pub fn call1(&self, name: &str, args: impl IntoPy>) -> PyResult> { self.getattr(name)?.call1(args) } /// Calls a function in the module without arguments. /// /// This is equivalent to the Python expression `module.name()`. - pub fn call0(&self, name: &str) -> PyResult<&PyAny> { + pub fn call0(&self, name: &str) -> PyResult> { self.getattr(name)?.call0() } /// Gets a member from the module. /// /// This is equivalent to the Python expression `module.name`. - pub fn get(&self, name: &str) -> PyResult<&PyAny> { + pub fn get(&self, name: &str) -> PyResult> { self.getattr(name) } @@ -174,7 +174,7 @@ impl PyModule { /// and adds the type to this module. pub fn add_class(&self) -> PyResult<()> where - T: PyClass, + T: PyClass<'py>, { self.add(T::NAME, ::type_object()) } diff --git a/src/types/num.rs b/src/types/num.rs index 10396f37683..583b901d746 100644 --- a/src/types/num.rs +++ b/src/types/num.rs @@ -2,10 +2,9 @@ // // based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython -use crate::internal_tricks::Unsendable; use crate::{ exceptions, ffi, AsPyPointer, FromPyObject, IntoPy, PyAny, PyErr, PyNativeType, PyObject, - PyResult, Python, ToPyObject, + PyResult, Python, ToPyObject, type_marker }; use num_traits::cast::cast; use std::i64; @@ -37,8 +36,8 @@ macro_rules! int_fits_larger_int { } } - impl<'source> FromPyObject<'source> for $rust_type { - fn extract(obj: &'source PyAny) -> PyResult { + impl FromPyObject<'_, '_> for $rust_type { + fn extract(obj: &PyAny) -> PyResult { let val = $crate::objectprotocol::ObjectProtocol::extract::<$larger_type>(obj)?; match cast::<$larger_type, $rust_type>(val) { Some(v) => Ok(v), @@ -78,8 +77,8 @@ macro_rules! int_convert_128 { } } } - impl<'source> FromPyObject<'source> for $rust_type { - fn extract(ob: &'source PyAny) -> PyResult<$rust_type> { + impl FromPyObject<'_, '_> for $rust_type { + fn extract(ob: &PyAny) -> PyResult<$rust_type> { unsafe { let num = ffi::PyNumber_Index(ob.as_ptr()); if num.is_null() { @@ -111,9 +110,9 @@ macro_rules! int_convert_128 { /// and [extract](struct.PyObject.html#method.extract) /// with the primitive Rust integer types. #[repr(transparent)] -pub struct PyLong(PyObject, Unsendable); +pub struct PyLong<'py>(PyAny<'py>); -pyobject_native_var_type!(PyLong, ffi::PyLong_Type, ffi::PyLong_Check); +pyobject_native_var_type!(PyLong<'py>, ffi::PyLong_Type, ffi::PyLong_Check, type_marker::Long); macro_rules! int_fits_c_long { ($rust_type:ty) => { @@ -134,8 +133,8 @@ macro_rules! int_fits_c_long { } } - impl<'source> FromPyObject<'source> for $rust_type { - fn extract(obj: &'source PyAny) -> PyResult { + impl FromPyObject<'_, '_> for $rust_type { + fn extract(obj: &PyAny) -> PyResult { let ptr = obj.as_ptr(); let val = unsafe { let num = ffi::PyNumber_Index(ptr); @@ -170,8 +169,8 @@ macro_rules! int_convert_u64_or_i64 { unsafe { PyObject::from_owned_ptr_or_panic(py, $pylong_from_ll_or_ull(self)) } } } - impl<'source> FromPyObject<'source> for $rust_type { - fn extract(ob: &'source PyAny) -> PyResult<$rust_type> { + impl FromPyObject<'_, '_> for $rust_type { + fn extract(ob: &PyAny) -> PyResult<$rust_type> { let ptr = ob.as_ptr(); unsafe { let num = ffi::PyNumber_Index(ptr); diff --git a/src/types/sequence.rs b/src/types/sequence.rs index 71f9200089d..69167104418 100644 --- a/src/types/sequence.rs +++ b/src/types/sequence.rs @@ -5,8 +5,6 @@ use crate::err::{self, PyDowncastError, PyErr, PyResult}; use crate::exceptions; use crate::ffi::{self, Py_ssize_t}; use crate::instance::PyNativeType; -use crate::internal_tricks::Unsendable; -use crate::object::PyObject; use crate::objectprotocol::ObjectProtocol; use crate::types::{PyAny, PyList, PyTuple}; use crate::AsPyPointer; @@ -14,11 +12,12 @@ use crate::{FromPyObject, PyTryFrom, ToBorrowedObject}; /// Represents a reference to a Python object supporting the sequence protocol. #[repr(transparent)] -pub struct PySequence(PyObject, Unsendable); -pyobject_native_type_named!(PySequence); -pyobject_native_type_extract!(PySequence); +pub struct PySequence<'py>(PyAny<'py>); +pyobject_native_type_named!(PySequence<'py>); +pyobject_native_type_extract!(PySequence<'py>); +pyobject_native_newtype!(PySequence<'py>); -impl PySequence { +impl<'py> PySequence<'py> { /// Returns the number of objects in sequence. /// /// This is equivalent to the Python expression `len(self)`. @@ -41,15 +40,14 @@ impl PySequence { /// /// This is equivalent to the Python expression `self + other`. #[inline] - pub fn concat(&self, other: &PySequence) -> PyResult<&PySequence> { + pub fn concat(&self, other: &PySequence) -> PyResult { unsafe { - let ptr = self + self .py() - .from_owned_ptr_or_err::(ffi::PySequence_Concat( + .from_owned_ptr_or_err(ffi::PySequence_Concat( self.as_ptr(), other.as_ptr(), - ))?; - Ok(&*(ptr as *const PyAny as *const PySequence)) + )) } } @@ -58,15 +56,14 @@ impl PySequence { /// This is equivalent to the Python expression `self * count`. /// NB: Python accepts negative counts; it returns an empty Sequence. #[inline] - pub fn repeat(&self, count: isize) -> PyResult<&PySequence> { + pub fn repeat(&self, count: isize) -> PyResult { unsafe { - let ptr = self + self .py() - .from_owned_ptr_or_err::(ffi::PySequence_Repeat( + .from_owned_ptr_or_err(ffi::PySequence_Repeat( self.as_ptr(), count as Py_ssize_t, - ))?; - Ok(&*(ptr as *const PyAny as *const PySequence)) + )) } } @@ -105,7 +102,7 @@ impl PySequence { /// /// This is equivalent to the Python expression `self[index]`. #[inline] - pub fn get_item(&self, index: isize) -> PyResult<&PyAny> { + pub fn get_item(&self, index: isize) -> PyResult> { unsafe { self.py() .from_owned_ptr_or_err(ffi::PySequence_GetItem(self.as_ptr(), index as Py_ssize_t)) @@ -116,7 +113,7 @@ impl PySequence { /// /// This is equivalent to the Python expression `self[begin:end]`. #[inline] - pub fn get_slice(&self, begin: isize, end: isize) -> PyResult<&PyAny> { + pub fn get_slice(&self, begin: isize, end: isize) -> PyResult> { unsafe { self.py().from_owned_ptr_or_err(ffi::PySequence_GetSlice( self.as_ptr(), @@ -244,7 +241,7 @@ impl PySequence { /// Returns a fresh list based on the Sequence. #[inline] - pub fn list(&self) -> PyResult<&PyList> { + pub fn list(&self) -> PyResult> { unsafe { self.py() .from_owned_ptr_or_err(ffi::PySequence_List(self.as_ptr())) @@ -253,7 +250,7 @@ impl PySequence { /// Returns a fresh tuple based on the Sequence. #[inline] - pub fn tuple(&self) -> PyResult<&PyTuple> { + pub fn tuple(&self) -> PyResult> { unsafe { self.py() .from_owned_ptr_or_err(ffi::PySequence_Tuple(self.as_ptr())) @@ -264,22 +261,22 @@ impl PySequence { macro_rules! array_impls { ($($N:expr),+) => { $( - impl<'a, T> FromPyObject<'a> for [T; $N] + impl<'py, T> FromPyObject<'_, 'py> for [T; $N] where - T: Copy + Default + FromPyObject<'a>, + T: Copy + Default + for<'a> FromPyObject<'a, 'py>, { - default fn extract(obj: &'a PyAny) -> PyResult { + default fn extract(obj: &PyAny<'py>) -> PyResult { let mut array = [T::default(); $N]; extract_sequence_into_slice(obj, &mut array)?; Ok(array) } } - impl<'source, T> FromPyObject<'source> for [T; $N] + impl<'py, T> FromPyObject<'_, 'py> for [T; $N] where - for<'a> T: Copy + Default + FromPyObject<'a> + buffer::Element, + T: Copy + Default + for<'a> FromPyObject<'a, 'py> + buffer::Element, { - fn extract(obj: &'source PyAny) -> PyResult { + fn extract(obj: &PyAny<'py>) -> PyResult { let mut array = [T::default(); $N]; // first try buffer protocol if let Ok(buf) = buffer::PyBuffer::get(obj.py(), obj) { @@ -303,20 +300,20 @@ array_impls!( 26, 27, 28, 29, 30, 31, 32 ); -impl<'a, T> FromPyObject<'a> for Vec +impl<'py, T> FromPyObject<'_, 'py> for Vec where - T: FromPyObject<'a>, + T: for<'a> FromPyObject<'a, 'py>, { - default fn extract(obj: &'a PyAny) -> PyResult { + default fn extract(obj: &PyAny<'py>) -> PyResult { extract_sequence(obj) } } -impl<'source, T> FromPyObject<'source> for Vec +impl<'py, T> FromPyObject<'_, 'py> for Vec where - for<'a> T: FromPyObject<'a> + buffer::Element + Copy, + T: for<'a> FromPyObject<'a, 'py> + buffer::Element + Copy, { - fn extract(obj: &'source PyAny) -> PyResult { + fn extract(obj: &PyAny<'py>) -> PyResult { // first try buffer protocol if let Ok(buf) = buffer::PyBuffer::get(obj.py(), obj) { if buf.dimensions() == 1 { @@ -332,9 +329,9 @@ where } } -fn extract_sequence<'s, T>(obj: &'s PyAny) -> PyResult> +fn extract_sequence<'py, T>(obj: &PyAny<'py>) -> PyResult> where - T: FromPyObject<'s>, + T: for<'a> FromPyObject<'a, 'py>, { let seq = ::try_from(obj)?; let mut v = Vec::with_capacity(seq.len().unwrap_or(0) as usize); @@ -344,9 +341,9 @@ where Ok(v) } -fn extract_sequence_into_slice<'s, T>(obj: &'s PyAny, slice: &mut [T]) -> PyResult<()> +fn extract_sequence_into_slice<'py, T>(obj: &PyAny<'py>, slice: &mut [T]) -> PyResult<()> where - T: FromPyObject<'s>, + T: for<'a> FromPyObject<'a, 'py>, { let seq = ::try_from(obj)?; if seq.len()? as usize != slice.len() { @@ -360,9 +357,8 @@ where Ok(()) } -impl<'v> PyTryFrom<'v> for PySequence { - fn try_from>(value: V) -> Result<&'v PySequence, PyDowncastError> { - let value = value.into(); +impl<'py> PyTryFrom<'py> for PySequence<'py> { + fn try_from<'a>(value: &'a PyAny<'py>) -> Result<&'a PySequence<'py>, PyDowncastError> { unsafe { if ffi::PySequence_Check(value.as_ptr()) != 0 { Ok(::try_from_unchecked(value)) @@ -372,13 +368,13 @@ impl<'v> PyTryFrom<'v> for PySequence { } } - fn try_from_exact>(value: V) -> Result<&'v PySequence, PyDowncastError> { + fn try_from_exact<'a>(value: &'a PyAny<'py>) -> Result<&'a PySequence<'py>, PyDowncastError> { ::try_from(value) } #[inline] - unsafe fn try_from_unchecked>(value: V) -> &'v PySequence { - let ptr = value.into() as *const _ as *const PySequence; + unsafe fn try_from_unchecked<'a>(value: &'a PyAny<'py>) -> &'a PySequence<'py> { + let ptr = value as *const _ as *const PySequence; &*ptr } } diff --git a/src/types/set.rs b/src/types/set.rs index 40f8dadd3be..c0e3326575c 100644 --- a/src/types/set.rs +++ b/src/types/set.rs @@ -2,10 +2,9 @@ // use crate::err::{self, PyErr, PyResult}; -use crate::internal_tricks::Unsendable; use crate::{ ffi, AsPyPointer, FromPy, FromPyObject, IntoPy, PyAny, PyNativeType, PyObject, Python, - ToBorrowedObject, ToPyObject, + ToBorrowedObject, ToPyObject, type_marker }; use std::cmp; use std::collections::{BTreeSet, HashSet}; @@ -13,31 +12,32 @@ use std::{collections, hash, ptr}; /// Represents a Python `set` #[repr(transparent)] -pub struct PySet(PyObject, Unsendable); +pub struct PySet<'py>(PyAny<'py>); -/// Represents a Python `frozenset` +/// Represents a Python `frozenset` #[repr(transparent)] -pub struct PyFrozenSet(PyObject, Unsendable); +pub struct PyFrozenSet<'py>(PyAny<'py>); -pyobject_native_type!(PySet, ffi::PySetObject, ffi::PySet_Type, ffi::PySet_Check); +pyobject_native_type!(PySet<'py>, ffi::PySetObject, ffi::PySet_Type, ffi::PySet_Check, type_marker::Set); pyobject_native_type!( - PyFrozenSet, + PyFrozenSet<'py>, ffi::PySetObject, ffi::PyFrozenSet_Type, - ffi::PyFrozenSet_Check + ffi::PyFrozenSet_Check, + type_marker::FrozenSet ); -impl PySet { +impl<'py> PySet<'py> { /// Creates a new set with elements from the given slice. /// /// Returns an error if some element is not hashable. - pub fn new<'p, T: ToPyObject>(py: Python<'p>, elements: &[T]) -> PyResult<&'p PySet> { + pub fn new(py: Python<'py>, elements: &[T]) -> PyResult { let list = elements.to_object(py); unsafe { py.from_owned_ptr_or_err(ffi::PySet_New(list.as_ptr())) } } /// Creates a new empty set. - pub fn empty<'p>(py: Python<'p>) -> PyResult<&'p PySet> { + pub fn empty(py: Python<'py>) -> PyResult { unsafe { py.from_owned_ptr_or_err(ffi::PySet_New(ptr::null_mut())) } } @@ -112,7 +112,7 @@ impl PySet { /// /// Note that it can be unsafe to use when the set might be changed by other code. #[cfg(not(Py_LIMITED_API))] - pub fn iter(&self) -> PySetIterator { + pub fn iter<'a>(&'a self) -> PySetIterator<'a, 'py> { PySetIterator { set: self.as_ref(), pos: 0, @@ -121,14 +121,14 @@ impl PySet { } #[cfg(not(Py_LIMITED_API))] -pub struct PySetIterator<'py> { - set: &'py super::PyAny, +pub struct PySetIterator<'a, 'py> { + set: &'a PyAny<'py>, pos: isize, } #[cfg(not(Py_LIMITED_API))] -impl<'py> Iterator for PySetIterator<'py> { - type Item = &'py super::PyAny; +impl<'a, 'py> Iterator for PySetIterator<'a, 'py> { + type Item = &'a PyAny<'py>; #[inline] fn next(&mut self) -> Option { @@ -145,9 +145,9 @@ impl<'py> Iterator for PySetIterator<'py> { } #[cfg(not(Py_LIMITED_API))] -impl<'a> std::iter::IntoIterator for &'a PySet { - type Item = &'a PyAny; - type IntoIter = PySetIterator<'a>; +impl<'a, 'py> std::iter::IntoIterator for &'a PySet<'py> { + type Item = &'a PyAny<'py>; + type IntoIter = PySetIterator<'a, 'py>; fn into_iter(self) -> Self::IntoIter { self.iter() @@ -200,12 +200,12 @@ where } } -impl<'source, K, S> FromPyObject<'source> for HashSet +impl<'a, 'py, K, S> FromPyObject<'a, 'py> for HashSet where - K: FromPyObject<'source> + cmp::Eq + hash::Hash, + K: FromPyObject<'a, 'py> + cmp::Eq + hash::Hash, S: hash::BuildHasher + Default, { - fn extract(ob: &'source PyAny) -> PyResult { + fn extract(ob: &'a PyAny<'py>) -> PyResult { let set: &PySet = ob.downcast()?; set.iter().map(K::extract).collect() } @@ -226,27 +226,27 @@ where } } -impl<'source, K> FromPyObject<'source> for BTreeSet +impl<'a, 'py, K> FromPyObject<'a, 'py> for BTreeSet where - K: FromPyObject<'source> + cmp::Ord, + K: FromPyObject<'a, 'py> + cmp::Ord, { - fn extract(ob: &'source PyAny) -> PyResult { + fn extract(ob: &'a PyAny<'py>) -> PyResult { let set: &PySet = ob.downcast()?; set.iter().map(K::extract).collect() } } -impl PyFrozenSet { +impl<'py> PyFrozenSet<'py> { /// Creates a new frozenset. /// /// May panic when running out of memory. - pub fn new<'p, T: ToPyObject>(py: Python<'p>, elements: &[T]) -> PyResult<&'p PyFrozenSet> { + pub fn new(py: Python<'py>, elements: &[T]) -> PyResult { let list = elements.to_object(py); unsafe { py.from_owned_ptr_or_err(ffi::PyFrozenSet_New(list.as_ptr())) } } /// Creates a new empty frozen set - pub fn empty<'p>(py: Python<'p>) -> PyResult<&'p PySet> { + pub fn empty(py: Python<'py>) -> PyResult { unsafe { py.from_owned_ptr_or_err(ffi::PyFrozenSet_New(ptr::null_mut())) } } @@ -287,9 +287,9 @@ impl PyFrozenSet { } #[cfg(not(Py_LIMITED_API))] -impl<'a> std::iter::IntoIterator for &'a PyFrozenSet { - type Item = &'a PyAny; - type IntoIter = PySetIterator<'a>; +impl<'a, 'py> std::iter::IntoIterator for &'a PyFrozenSet<'py> { + type Item = &'a PyAny<'py>; + type IntoIter = PySetIterator<'a, 'py>; fn into_iter(self) -> Self::IntoIter { PySetIterator { @@ -406,7 +406,7 @@ mod test { } // intoiterator iteration - for el in set { + for el in &set { assert_eq!(1i32, el.extract().unwrap()); } } @@ -452,7 +452,7 @@ mod test { } // intoiterator iteration - for el in set { + for el in &set { assert_eq!(1i32, el.extract::().unwrap()); } } diff --git a/src/types/slice.rs b/src/types/slice.rs index 7a0cdf71c23..727e6c6ee0e 100644 --- a/src/types/slice.rs +++ b/src/types/slice.rs @@ -3,8 +3,9 @@ use crate::err::{PyErr, PyResult}; use crate::ffi::{self, Py_ssize_t}; use crate::instance::PyNativeType; -use crate::internal_tricks::Unsendable; use crate::object::PyObject; +use crate::types::PyAny; +use crate::type_marker; use crate::Python; use crate::{AsPyPointer, ToPyObject}; use std::os::raw::c_long; @@ -13,13 +14,14 @@ use std::os::raw::c_long; /// /// Only `c_long` indices supported at the moment by the `PySlice` object. #[repr(transparent)] -pub struct PySlice(PyObject, Unsendable); +pub struct PySlice<'py>(PyAny<'py>); pyobject_native_type!( - PySlice, + PySlice<'py>, ffi::PySliceObject, ffi::PySlice_Type, - ffi::PySlice_Check + ffi::PySlice_Check, + type_marker::Slice ); /// Represents Python `slice` indices. @@ -41,9 +43,9 @@ impl PySliceIndices { } } -impl PySlice { +impl<'py> PySlice<'py> { /// Constructs a new slice with the given elements. - pub fn new(py: Python, start: isize, stop: isize, step: isize) -> &PySlice { + pub fn new(py: Python<'py>, start: isize, stop: isize, step: isize) -> Self { unsafe { let ptr = ffi::PySlice_New( ffi::PyLong_FromLong(start as c_long), diff --git a/src/types/string.rs b/src/types/string.rs index 51d519ff0a0..b6cb0c2550b 100644 --- a/src/types/string.rs +++ b/src/types/string.rs @@ -1,9 +1,8 @@ // Copyright (c) 2017-present PyO3 Project and Contributors -use crate::internal_tricks::Unsendable; use crate::{ ffi, gil, AsPyPointer, FromPy, FromPyObject, IntoPy, PyAny, PyErr, PyNativeType, PyObject, - PyResult, PyTryFrom, Python, ToPyObject, + PyResult, PyTryFrom, Python, ToPyObject, type_marker }; use std::borrow::Cow; use std::ffi::CStr; @@ -15,21 +14,21 @@ use std::str; /// /// This type is immutable. #[repr(transparent)] -pub struct PyString(PyObject, Unsendable); +pub struct PyString<'py>(PyAny<'py>); -pyobject_native_var_type!(PyString, ffi::PyUnicode_Type, ffi::PyUnicode_Check); +pyobject_native_var_type!(PyString<'py>, ffi::PyUnicode_Type, ffi::PyUnicode_Check, type_marker::String); -impl PyString { +impl<'py> PyString<'py> { /// Creates a new Python string object. /// /// Panics if out of memory. - pub fn new<'p>(py: Python<'p>, s: &str) -> &'p PyString { + pub fn new(py: Python<'py>, s: &str) -> Self { let ptr = s.as_ptr() as *const c_char; let len = s.len() as ffi::Py_ssize_t; unsafe { py.from_owned_ptr(ffi::PyUnicode_FromStringAndSize(ptr, len)) } } - pub fn from_object<'p>(src: &'p PyAny, encoding: &str, errors: &str) -> PyResult<&'p PyString> { + pub fn from_object(src: &'_ PyAny<'py>, encoding: &str, errors: &str) -> PyResult { unsafe { src.py() .from_owned_ptr_or_err::(ffi::PyUnicode_FromEncodedObject( @@ -144,15 +143,15 @@ impl<'a> IntoPy for &'a String { /// Allows extracting strings from Python objects. /// Accepts Python `str` and `unicode` objects. -impl<'source> crate::FromPyObject<'source> for Cow<'source, str> { - fn extract(ob: &'source PyAny) -> PyResult { +impl<'a> crate::FromPyObject<'a, '_> for Cow<'a, str> { + fn extract(ob: &'a PyAny) -> PyResult { ::try_from(ob)?.to_string() } } /// Allows extracting strings from Python objects. /// Accepts Python `str` and `unicode` objects. -impl<'a> crate::FromPyObject<'a> for &'a str { +impl<'a> crate::FromPyObject<'a, '_> for &'a str { fn extract(ob: &'a PyAny) -> PyResult { let s: Cow<'a, str> = crate::FromPyObject::extract(ob)?; match s { @@ -167,8 +166,8 @@ impl<'a> crate::FromPyObject<'a> for &'a str { /// Allows extracting strings from Python objects. /// Accepts Python `str` and `unicode` objects. -impl<'source> FromPyObject<'source> for String { - fn extract(obj: &'source PyAny) -> PyResult { +impl FromPyObject<'_, '_> for String { + fn extract(obj: &PyAny) -> PyResult { ::try_from(obj)? .to_string() .map(Cow::into_owned) diff --git a/src/types/tuple.rs b/src/types/tuple.rs index 3466b39a056..207b9b1219a 100644 --- a/src/types/tuple.rs +++ b/src/types/tuple.rs @@ -1,7 +1,7 @@ // Copyright (c) 2017-present PyO3 Project and Contributors use crate::ffi::{self, Py_ssize_t}; -use crate::internal_tricks::Unsendable; +use crate::type_marker::Tuple; use crate::{ exceptions, AsPyPointer, AsPyRef, FromPy, FromPyObject, IntoPy, IntoPyPointer, Py, PyAny, PyErr, PyNativeType, PyObject, PyResult, PyTryFrom, Python, ToPyObject, @@ -12,13 +12,13 @@ use std::slice; /// /// This type is immutable. #[repr(transparent)] -pub struct PyTuple(PyObject, Unsendable); +pub struct PyTuple<'py>(PyAny<'py>); -pyobject_native_var_type!(PyTuple, ffi::PyTuple_Type, ffi::PyTuple_Check); +pyobject_native_var_type!(PyTuple<'py>, ffi::PyTuple_Type, ffi::PyTuple_Check, Tuple); -impl PyTuple { +impl<'py> PyTuple<'py> { /// Constructs a new tuple with the given elements. - pub fn new(py: Python, elements: impl IntoIterator) -> &PyTuple + pub fn new(py: Python<'py>, elements: impl IntoIterator) -> Self where T: ToPyObject, U: ExactSizeIterator, @@ -35,7 +35,7 @@ impl PyTuple { } /// Constructs an empty tuple (on the Python side, a singleton object). - pub fn empty(py: Python) -> &PyTuple { + pub fn empty(py: Python<'py>) -> Self { unsafe { py.from_owned_ptr(ffi::PyTuple_New(0)) } } @@ -53,23 +53,23 @@ impl PyTuple { } /// Takes a slice of the tuple pointed from `low` to `high` and returns it as a new tuple. - pub fn slice(&self, low: isize, high: isize) -> Py { - unsafe { Py::from_owned_ptr_or_panic(ffi::PyTuple_GetSlice(self.as_ptr(), low, high)) } + pub fn slice(&self, low: isize, high: isize) -> Self { + unsafe { self.py().from_owned_ptr(ffi::PyTuple_GetSlice(self.as_ptr(), low, high)) } } /// Takes a slice of the tuple from `low` to the end and returns it as a new tuple. - pub fn split_from(&self, low: isize) -> Py { + pub fn split_from(&self, low: isize) -> Self { unsafe { let ptr = ffi::PyTuple_GetSlice(self.as_ptr(), low, ffi::PyTuple_GET_SIZE(self.as_ptr())); - Py::from_owned_ptr_or_panic(ptr) + self.py().from_owned_ptr(ptr) } } /// Gets the tuple item at the specified index. /// /// Panics if the index is out of range. - pub fn get_item(&self, index: usize) -> &PyAny { + pub fn get_item(&self, index: usize) -> &PyAny<'py> { // TODO: reconsider whether we should panic // It's quite inconsistent that this method takes `Python` when `len()` does not. assert!(index < self.len()); @@ -109,10 +109,10 @@ pub struct PyTupleIterator<'a> { } impl<'a> Iterator for PyTupleIterator<'a> { - type Item = &'a PyAny; + type Item = &'a PyAny<'a>; #[inline] - fn next(&mut self) -> Option<&'a PyAny> { + fn next(&mut self) -> Option<&'a PyAny<'a>> { if self.index < self.slice.len() { let item = self.slice[self.index].as_ref(self.py); self.index += 1; @@ -123,17 +123,17 @@ impl<'a> Iterator for PyTupleIterator<'a> { } } -impl<'a> IntoIterator for &'a PyTuple { - type Item = &'a PyAny; - type IntoIter = PyTupleIterator<'a>; +impl<'py> IntoIterator for &'py PyTuple<'py> { + type Item = &'py PyAny<'py>; + type IntoIter = PyTupleIterator<'py>; fn into_iter(self) -> Self::IntoIter { self.iter() } } -impl<'a> FromPy<&'a PyTuple> for Py { - fn from_py(tuple: &'a PyTuple, _py: Python) -> Py { +impl<'py> FromPy<&'_ PyTuple<'py>> for Py { + fn from_py(tuple: &PyTuple<'py>, _py: Python) -> Py { unsafe { Py::from_borrowed_ptr(tuple.as_ptr()) } } } @@ -167,8 +167,8 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+ } } - impl <$($T: IntoPy),+> IntoPy> for ($($T,)+) { - fn into_py(self, py: Python) -> Py { + impl <$($T: IntoPy),+> IntoPy> for ($($T,)+) { + fn into_py(self, py: Python) -> Py { unsafe { let ptr = ffi::PyTuple_New($length); $(ffi::PyTuple_SetItem(ptr, $n, self.$n.into_py(py).into_ptr());)+ @@ -177,8 +177,8 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+ } } - impl<'s, $($T: FromPyObject<'s>),+> FromPyObject<'s> for ($($T,)+) { - fn extract(obj: &'s PyAny) -> PyResult + impl<'a, 'py, $($T: FromPyObject<'a, 'py>),+> FromPyObject<'a, 'py> for ($($T,)+) { + fn extract(obj: &'a PyAny<'py>) -> PyResult { let t = ::try_from(obj)?; let slice = t.as_slice(); @@ -260,7 +260,6 @@ mod test { let py = gil.python(); let ob = PyTuple::new(py, &[1, 2, 3]); assert_eq!(3, ob.len()); - let ob: &PyAny = ob.into(); assert_eq!((1, 2, 3), ob.extract().unwrap()); let mut map = HashSet::new(); diff --git a/src/types/typeobject.rs b/src/types/typeobject.rs index 5525bec3c3b..11b4f079254 100644 --- a/src/types/typeobject.rs +++ b/src/types/typeobject.rs @@ -2,12 +2,13 @@ // // based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython +use crate::conversion::IntoPyPointer; use crate::err::{PyErr, PyResult}; use crate::ffi; -use crate::instance::{Py, PyNativeType}; -use crate::internal_tricks::Unsendable; -use crate::object::PyObject; -use crate::type_object::PyTypeObject; +use crate::instance::PyNativeType; +use crate::type_object::{PyTypeInfo, PyTypeObject}; +use crate::type_marker; +use crate::types::PyAny; use crate::AsPyPointer; use crate::Python; use std::borrow::Cow; @@ -15,15 +16,15 @@ use std::ffi::CStr; /// Represents a reference to a Python `type object`. #[repr(transparent)] -pub struct PyType(PyObject, Unsendable); +pub struct PyType<'a>(PyAny<'a>); -pyobject_native_var_type!(PyType, ffi::PyType_Type, ffi::PyType_Check); +pyobject_native_var_type!(PyType<'py>, ffi::PyType_Type, ffi::PyType_Check, type_marker::Type); -impl PyType { +impl<'py> PyType<'py> { /// Creates a new type object. #[inline] - pub fn new() -> Py { - T::type_object() + pub fn new>(py: Python<'py>) -> Self { + unsafe { py.from_owned_ptr(::type_object().into_ptr()) } } /// Retrieves the underlying FFI pointer associated with this Python object. @@ -36,7 +37,7 @@ impl PyType { /// This increments the reference count on the type object. /// Undefined behavior if the pointer is NULL or invalid. #[inline] - pub unsafe fn from_type_ptr(py: Python, p: *mut ffi::PyTypeObject) -> &PyType { + pub unsafe fn from_type_ptr(py: Python<'py>, p: *mut ffi::PyTypeObject) -> &Self { py.from_borrowed_ptr(p as *mut ffi::PyObject) } @@ -50,9 +51,9 @@ impl PyType { /// Equivalent to Python's `issubclass` function. pub fn is_subclass(&self) -> PyResult where - T: PyTypeObject, + T: PyTypeInfo<'py>, { - let result = unsafe { ffi::PyObject_IsSubclass(self.as_ptr(), T::type_object().as_ptr()) }; + let result = unsafe { ffi::PyObject_IsSubclass(self.as_ptr(), T::type_object() as *const _ as *mut ffi::PyTypeObject as _)}; if result == -1 { Err(PyErr::fetch(self.py())) } else if result == 1 { diff --git a/tests/common.rs b/tests/common.rs index 4cd3c084f9f..de000afc54f 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -15,7 +15,7 @@ macro_rules! py_expect_exception { use pyo3::types::IntoPyDict; let d = [(stringify!($val), &$val)].into_py_dict($py); - let res = $py.run($code, None, Some(d)); + let res = $py.run($code, None, Some(&d)); let err = res.unwrap_err(); if !err.matches($py, $py.get_type::()) { panic!("Expected {} but got {:?}", stringify!($err), err) diff --git a/tests/test_arithmetics.rs b/tests/test_arithmetics.rs index 8b1260dc957..732917961a0 100644 --- a/tests/test_arithmetics.rs +++ b/tests/test_arithmetics.rs @@ -258,7 +258,7 @@ impl PyNumberProtocol for RhsArithmetic { Ok(format!("{:?} | RA", other)) } - fn __rpow__(&self, other: &PyAny, _mod: Option<&'p PyAny>) -> PyResult { + fn __rpow__(&self, other: &PyAny, _mod: Option<&'p PyAny<'p>>) -> PyResult { Ok(format!("{:?} ** RA", other)) } } @@ -302,7 +302,7 @@ impl PyNumberProtocol for LhsAndRhsArithmetic { Ok(format!("{:?} - RA", other)) } - fn __rpow__(&self, other: &PyAny, _mod: Option<&'p PyAny>) -> PyResult { + fn __rpow__(&self, other: &PyAny, _mod: Option<&'p PyAny<'p>>) -> PyResult { Ok(format!("{:?} ** RA", other)) } diff --git a/tests/test_buffer_protocol.rs b/tests/test_buffer_protocol.rs index c576e1fd00c..e4b9bb5cda4 100644 --- a/tests/test_buffer_protocol.rs +++ b/tests/test_buffer_protocol.rs @@ -93,7 +93,7 @@ fn test_buffer() { ) .unwrap(); let env = [("ob", instance)].into_py_dict(py); - py.run("assert bytes(ob) == b' 23'", None, Some(env)) + py.run("assert bytes(ob) == b' 23'", None, Some(&env)) .unwrap(); } diff --git a/tests/test_datetime.rs b/tests/test_datetime.rs index bb62401e8dc..c1071e4cb04 100644 --- a/tests/test_datetime.rs +++ b/tests/test_datetime.rs @@ -5,15 +5,15 @@ use pyo3::prelude::*; use pyo3::types::IntoPyDict; #[allow(clippy::trivially_copy_pass_by_ref)] -fn _get_subclasses<'p>( - py: &'p Python, +fn _get_subclasses<'py>( + py: Python<'py>, py_type: &str, args: &str, -) -> PyResult<(&'p PyAny, &'p PyAny, &'p PyAny)> { +) -> PyResult<(PyAny<'py>, PyAny<'py>, PyAny<'py>)> { // Import the class from Python and create some subclasses let datetime = py.import("datetime")?; - let locals = [(py_type, datetime.get(py_type)?)].into_py_dict(*py); + let locals = [(py_type, datetime.get(py_type)?)].into_py_dict(py); let make_subclass_py = format!("class Subklass({}):\n pass", py_type); @@ -54,17 +54,11 @@ macro_rules! assert_check_only { }; } -// Because of the relase pool unsoundness reported in https://github.com/PyO3/pyo3/issues/756, -// we need to stop other threads before calling `py.import()`. -// TODO(kngwyu): Remove this variable -static MUTEX: parking_lot::Mutex<()> = parking_lot::const_mutex(()); - #[test] fn test_date_check() { - let _lock = MUTEX.lock(); let gil = Python::acquire_gil(); let py = gil.python(); - let (obj, sub_obj, sub_sub_obj) = _get_subclasses(&py, "date", "2018, 1, 1").unwrap(); + let (obj, sub_obj, sub_sub_obj) = _get_subclasses(py, "date", "2018, 1, 1").unwrap(); assert_check_exact!(PyDate_Check, obj); assert_check_only!(PyDate_Check, sub_obj); @@ -73,10 +67,9 @@ fn test_date_check() { #[test] fn test_time_check() { - let _lock = MUTEX.lock(); let gil = Python::acquire_gil(); let py = gil.python(); - let (obj, sub_obj, sub_sub_obj) = _get_subclasses(&py, "time", "12, 30, 15").unwrap(); + let (obj, sub_obj, sub_sub_obj) = _get_subclasses(py, "time", "12, 30, 15").unwrap(); assert_check_exact!(PyTime_Check, obj); assert_check_only!(PyTime_Check, sub_obj); @@ -85,10 +78,9 @@ fn test_time_check() { #[test] fn test_datetime_check() { - let _lock = MUTEX.lock(); let gil = Python::acquire_gil(); let py = gil.python(); - let (obj, sub_obj, sub_sub_obj) = _get_subclasses(&py, "datetime", "2018, 1, 1, 13, 30, 15") + let (obj, sub_obj, sub_sub_obj) = _get_subclasses(py, "datetime", "2018, 1, 1, 13, 30, 15") .map_err(|e| e.print(py)) .unwrap(); @@ -100,10 +92,9 @@ fn test_datetime_check() { #[test] fn test_delta_check() { - let _lock = MUTEX.lock(); let gil = Python::acquire_gil(); let py = gil.python(); - let (obj, sub_obj, sub_sub_obj) = _get_subclasses(&py, "timedelta", "1, -3").unwrap(); + let (obj, sub_obj, sub_sub_obj) = _get_subclasses(py, "timedelta", "1, -3").unwrap(); assert_check_exact!(PyDelta_Check, obj); assert_check_only!(PyDelta_Check, sub_obj); @@ -115,7 +106,6 @@ fn test_datetime_utc() { use assert_approx_eq::assert_approx_eq; use pyo3::types::PyDateTime; - let _lock = MUTEX.lock(); let gil = Python::acquire_gil(); let py = gil.python(); let datetime = py.import("datetime").map_err(|e| e.print(py)).unwrap(); @@ -127,7 +117,7 @@ fn test_datetime_utc() { let locals = [("dt", dt)].into_py_dict(py); let offset: f32 = py - .eval("dt.utcoffset().total_seconds()", None, Some(locals)) + .eval("dt.utcoffset().total_seconds()", None, Some(&locals)) .unwrap() .extract() .unwrap(); diff --git a/tests/test_dunder.rs b/tests/test_dunder.rs index 3ae14908b52..249181515bb 100644 --- a/tests/test_dunder.rs +++ b/tests/test_dunder.rs @@ -53,11 +53,11 @@ struct Iterator { #[pyproto] impl<'p> PyIterProtocol for Iterator { - fn __iter__(slf: PyRef<'p, Self>) -> PyResult> { + fn __iter__(slf: PyRef<'p, 'p, Self>) -> PyResult> { Ok(slf.into()) } - fn __next__(mut slf: PyRefMut<'p, Self>) -> PyResult> { + fn __next__(mut slf: PyRefMut<'p, 'p, Self>) -> PyResult> { Ok(slf.iter.next()) } } @@ -375,9 +375,9 @@ impl<'p> PyContextProtocol<'p> for ContextManager { fn __exit__( &mut self, - ty: Option<&'p PyType>, - _value: Option<&'p PyAny>, - _traceback: Option<&'p PyAny>, + ty: Option<&'p PyType<'p>>, + _value: Option<&'p PyAny<'p>>, + _traceback: Option<&'p PyAny<'p>>, ) -> PyResult { let gil = GILGuard::acquire(); self.exit_called = true; @@ -459,8 +459,8 @@ fn test_cls_impl() { let ob = Py::new(py, Test {}).unwrap(); let d = [("ob", ob)].into_py_dict(py); - py.run("assert ob[1] == 'int'", None, Some(d)).unwrap(); - py.run("assert ob[100:200:1] == 'slice'", None, Some(d)) + py.run("assert ob[1] == 'int'", None, Some(&d)).unwrap(); + py.run("assert ob[100:200:1] == 'slice'", None, Some(&d)) .unwrap(); } diff --git a/tests/test_getter_setter.rs b/tests/test_getter_setter.rs index 7610e81fa5b..1d29436c2f4 100644 --- a/tests/test_getter_setter.rs +++ b/tests/test_getter_setter.rs @@ -38,7 +38,7 @@ impl ClassWithProperties { } #[getter] - fn get_data_list<'py>(&self, py: Python<'py>) -> &'py PyList { + fn get_data_list<'py>(&self, py: Python<'py>) -> PyList<'py> { PyList::new(py, &[self.num]) } } @@ -64,7 +64,7 @@ fn class_with_properties() { py.run( "assert C.DATA.__doc__ == 'a getter for data'", None, - Some(d), + Some(&d), ) .unwrap(); } diff --git a/tests/test_inheritance.rs b/tests/test_inheritance.rs index 1ec72302a49..555568709e4 100644 --- a/tests/test_inheritance.rs +++ b/tests/test_inheritance.rs @@ -3,7 +3,7 @@ use pyo3::py_run; use pyo3::types::IntoPyDict; -use pyo3::types::{PyDict, PySet}; +use pyo3::type_marker::{Dict, Set}; mod common; #[pyclass] @@ -24,7 +24,7 @@ fn subclass() { py.run( "class A(SubclassAble): pass\nassert issubclass(A, SubclassAble)", None, - Some(d), + Some(&d), ) .map_err(|e| e.print(py)) .unwrap(); @@ -98,7 +98,7 @@ fn mutation_fails() { let obj = PyCell::new(py, SubClass::new()).unwrap(); let global = Some([("obj", obj)].into_py_dict(py)); let e = py - .run("obj.base_set(lambda: obj.sub_set_and_ret(1))", global, None) + .run("obj.base_set(lambda: obj.sub_set_and_ret(1))", global.as_ref(), None) .unwrap_err(); assert!(e.is_instance::(py)) } @@ -150,7 +150,7 @@ except Exception as e: ); } -#[pyclass(extends=PySet)] +#[pyclass(extends=Set)] #[derive(Debug)] struct SetWithName { #[pyo3(get(name))] @@ -177,7 +177,7 @@ fn inherit_set() { ); } -#[pyclass(extends=PyDict)] +#[pyclass(extends=Dict)] #[derive(Debug)] struct DictWithName { #[pyo3(get(name))] diff --git a/tests/test_mapping.rs b/tests/test_mapping.rs index 17a0203bf57..3aeeeb64089 100644 --- a/tests/test_mapping.rs +++ b/tests/test_mapping.rs @@ -75,8 +75,8 @@ fn test_getitem() { let py = gil.python(); let d = [("Mapping", py.get_type::())].into_py_dict(py); - let run = |code| py.run(code, None, Some(d)).unwrap(); - let err = |code| py.run(code, None, Some(d)).unwrap_err(); + let run = |code| py.run(code, None, Some(&d)).unwrap(); + let err = |code| py.run(code, None, Some(&d)).unwrap_err(); run("m = Mapping(['1', '2', '3']); assert m['1'] == 0"); run("m = Mapping(['1', '2', '3']); assert m['2'] == 1"); @@ -90,8 +90,8 @@ fn test_setitem() { let py = gil.python(); let d = [("Mapping", py.get_type::())].into_py_dict(py); - let run = |code| py.run(code, None, Some(d)).unwrap(); - let err = |code| py.run(code, None, Some(d)).unwrap_err(); + let run = |code| py.run(code, None, Some(&d)).unwrap(); + let err = |code| py.run(code, None, Some(&d)).unwrap_err(); run("m = Mapping(['1', '2', '3']); m['1'] = 4; assert m['1'] == 4"); run("m = Mapping(['1', '2', '3']); m['0'] = 0; assert m['0'] == 0"); @@ -106,8 +106,8 @@ fn test_delitem() { let py = gil.python(); let d = [("Mapping", py.get_type::())].into_py_dict(py); - let run = |code| py.run(code, None, Some(d)).unwrap(); - let err = |code| py.run(code, None, Some(d)).unwrap_err(); + let run = |code| py.run(code, None, Some(&d)).unwrap(); + let err = |code| py.run(code, None, Some(&d)).unwrap_err(); run( "m = Mapping(['1', '2', '3']); del m['1']; assert len(m) == 2; \ @@ -123,7 +123,7 @@ fn test_reversed() { let py = gil.python(); let d = [("Mapping", py.get_type::())].into_py_dict(py); - let run = |code| py.run(code, None, Some(d)).unwrap(); + let run = |code| py.run(code, None, Some(&d)).unwrap(); run("m = Mapping(['1', '2']); assert set(reversed(m)) == {'1', '2'}"); } diff --git a/tests/test_methods.rs b/tests/test_methods.rs index da473fccc6a..b6b10d447da 100644 --- a/tests/test_methods.rs +++ b/tests/test_methods.rs @@ -26,9 +26,9 @@ fn instance_method() { let obj = PyCell::new(py, InstanceMethod { member: 42 }).unwrap(); let obj_ref = obj.borrow(); assert_eq!(obj_ref.method().unwrap(), 42); - let d = [("obj", obj)].into_py_dict(py); - py.run("assert obj.method() == 42", None, Some(d)).unwrap(); - py.run("assert obj.method.__doc__ == 'Test method'", None, Some(d)) + let d = [("obj", &obj)].into_py_dict(py); + py.run("assert obj.method() == 42", None, Some(&d)).unwrap(); + py.run("assert obj.method.__doc__ == 'Test method'", None, Some(&d)) .unwrap(); } @@ -53,9 +53,9 @@ fn instance_method_with_args() { let obj = PyCell::new(py, InstanceMethodWithArgs { member: 7 }).unwrap(); let obj_ref = obj.borrow(); assert_eq!(obj_ref.method(6).unwrap(), 42); - let d = [("obj", obj)].into_py_dict(py); - py.run("assert obj.method(3) == 21", None, Some(d)).unwrap(); - py.run("assert obj.method(multiplier=6) == 42", None, Some(d)) + let d = [("obj", &obj)].into_py_dict(py); + py.run("assert obj.method(3) == 21", None, Some(&d)).unwrap(); + py.run("assert obj.method(multiplier=6) == 42", None, Some(&d)) .unwrap(); } @@ -83,7 +83,7 @@ fn class_method() { let d = [("C", py.get_type::())].into_py_dict(py); let run = |code| { - py.run(code, None, Some(d)) + py.run(code, None, Some(&d)) .map_err(|e| e.print(py)) .unwrap() }; @@ -113,7 +113,7 @@ fn class_method_with_args() { py.run( "assert C.method('abc') == 'ClassMethodWithArgs.method(abc)'", None, - Some(d), + Some(&d), ) .unwrap(); } @@ -144,7 +144,7 @@ fn static_method() { let d = [("C", py.get_type::())].into_py_dict(py); let run = |code| { - py.run(code, None, Some(d)) + py.run(code, None, Some(&d)) .map_err(|e| e.print(py)) .unwrap() }; @@ -173,7 +173,7 @@ fn static_method_with_args() { assert_eq!(StaticMethodWithArgs::method(py, 1234).unwrap(), "0x4d2"); let d = [("C", py.get_type::())].into_py_dict(py); - py.run("assert C.method(1337) == '0x539'", None, Some(d)) + py.run("assert C.method(1337) == '0x539'", None, Some(&d)) .unwrap(); } @@ -217,7 +217,7 @@ impl MethArgs { args: &PyTuple, kwargs: Option<&PyDict>, ) -> PyResult { - Ok([args.into(), kwargs.to_object(py)].to_object(py)) + Ok([args.clone().into(), kwargs.to_object(py)].to_object(py)) } #[args(args = "*", kwargs = "**")] @@ -228,7 +228,7 @@ impl MethArgs { args: &PyTuple, kwargs: Option<&PyDict>, ) -> PyObject { - [a.to_object(py), args.into(), kwargs.to_object(py)].to_object(py) + [a.to_object(py), args.clone().into(), kwargs.to_object(py)].to_object(py) } #[args(a, b = 2, "*", c = 3)] @@ -353,7 +353,7 @@ fn meth_doc() { let py = gil.python(); let d = [("C", py.get_type::())].into_py_dict(py); let run = |code| { - py.run(code, None, Some(d)) + py.run(code, None, Some(&d)) .map_err(|e| e.print(py)) .unwrap() }; @@ -368,7 +368,7 @@ struct MethodWithLifeTime {} #[pymethods] impl MethodWithLifeTime { - fn set_to_list<'py>(&self, py: Python<'py>, set: &'py PySet) -> PyResult<&'py PyList> { + fn set_to_list<'py>(&self, py: Python<'py>, set: &PySet) -> PyResult> { let mut items = vec![]; for _ in 0..set.len() { items.push(set.pop().unwrap()); @@ -435,7 +435,7 @@ fn method_with_pyclassarg() { let obj2 = PyCell::new(py, MethodWithPyClassArg { value: 10 }).unwrap(); let objs = [("obj1", obj1), ("obj2", obj2)].into_py_dict(py); let run = |code| { - py.run(code, None, Some(objs)) + py.run(code, None, Some(&objs)) .map_err(|e| e.print(py)) .unwrap() }; @@ -513,7 +513,7 @@ impl FromSequence { fn new(seq: Option<&pyo3::types::PySequence>) -> PyResult { if let Some(seq) = seq { Ok(FromSequence { - numbers: seq.as_ref().extract::>()?, + numbers: seq.as_ref().extract()?, }) } else { Ok(FromSequence::default()) diff --git a/tests/test_module.rs b/tests/test_module.rs index 6539bdf9797..357145db1cf 100644 --- a/tests/test_module.rs +++ b/tests/test_module.rs @@ -80,7 +80,7 @@ fn test_module_with_functions() { .into_py_dict(py); let run = |code| { - py.run(code, None, Some(d)) + py.run(code, None, Some(&d)) .map_err(|e| e.print(py)) .unwrap() }; @@ -116,7 +116,7 @@ fn test_module_renaming() { py.run( "assert different_name.__name__ == 'other_name'", None, - Some(d), + Some(&d), ) .unwrap(); } @@ -258,7 +258,7 @@ fn test_module_nesting() { #[pyfunction(a = 5, vararg = "*")] fn ext_vararg_fn(py: Python, a: i32, vararg: &PyTuple) -> PyObject { - [a.to_object(py), vararg.into()].to_object(py) + [a.to_object(py), vararg.clone().into()].to_object(py) } #[pymodule] diff --git a/tests/test_pyself.rs b/tests/test_pyself.rs index aabc5d9a4b5..c77ed32e423 100644 --- a/tests/test_pyself.rs +++ b/tests/test_pyself.rs @@ -3,6 +3,7 @@ use pyo3; use pyo3::prelude::*; use pyo3::types::{PyBytes, PyString}; use pyo3::{AsPyRef, PyCell, PyIterProtocol}; +use pyo3::type_marker::Bytes; use std::collections::HashMap; mod common; @@ -17,29 +18,29 @@ struct Reader { #[pymethods] impl Reader { - fn clone_ref(slf: &PyCell) -> &PyCell { + fn clone_ref<'py>(slf: &'py PyCell<'py, Self>) -> &'py PyCell<'py, Self> { slf } - fn clone_ref_with_py<'py>(slf: &'py PyCell, _py: Python<'py>) -> &'py PyCell { + fn clone_ref_with_py<'py>(slf: &'py PyCell, _py: Python<'py>) -> &'py PyCell<'py, Self> { slf } - fn get_iter(slf: &PyCell, keys: Py) -> PyResult { + fn get_iter(slf: &PyCell, keys: PyBytes) -> PyResult { Ok(Iter { reader: slf.into(), - keys, + keys: keys.into(), idx: 0, }) } fn get_iter_and_reset( mut slf: PyRefMut, - keys: Py, + keys: PyBytes, py: Python, ) -> PyResult { let reader = Py::new(py, slf.clone())?; slf.inner.clear(); Ok(Iter { reader, - keys, + keys: keys.into(), idx: 0, }) } @@ -49,7 +50,7 @@ impl Reader { #[derive(Debug)] struct Iter { reader: Py, - keys: Py, + keys: Py, idx: usize, } diff --git a/tests/test_sequence.rs b/tests/test_sequence.rs index c0a21c94f70..64beb18a8d6 100644 --- a/tests/test_sequence.rs +++ b/tests/test_sequence.rs @@ -62,7 +62,7 @@ impl PySequenceProtocol for ByteSequence { } } - fn __concat__(&self, other: PyRef<'p, Self>) -> PyResult { + fn __concat__(&self, other: PyRef<'p, 'p, Self>) -> PyResult { let mut elements = self.elements.clone(); elements.extend_from_slice(&other.elements); Ok(Self { elements }) @@ -87,8 +87,8 @@ fn test_getitem() { let py = gil.python(); let d = [("ByteSequence", py.get_type::())].into_py_dict(py); - let run = |code| py.run(code, None, Some(d)).unwrap(); - let err = |code| py.run(code, None, Some(d)).unwrap_err(); + let run = |code| py.run(code, None, Some(&d)).unwrap(); + let err = |code| py.run(code, None, Some(&d)).unwrap_err(); run("s = ByteSequence([1, 2, 3]); assert s[0] == 1"); run("s = ByteSequence([1, 2, 3]); assert s[1] == 2"); @@ -103,8 +103,8 @@ fn test_setitem() { let py = gil.python(); let d = [("ByteSequence", py.get_type::())].into_py_dict(py); - let run = |code| py.run(code, None, Some(d)).unwrap(); - let err = |code| py.run(code, None, Some(d)).unwrap_err(); + let run = |code| py.run(code, None, Some(&d)).unwrap(); + let err = |code| py.run(code, None, Some(&d)).unwrap_err(); run("s = ByteSequence([1, 2, 3]); s[0] = 4; assert list(s) == [4, 2, 3]"); err("s = ByteSequence([1, 2, 3]); s[0] = 'hello'"); @@ -116,8 +116,8 @@ fn test_delitem() { let py = gil.python(); let d = [("ByteSequence", py.get_type::())].into_py_dict(py); - let run = |code| py.run(code, None, Some(d)).unwrap(); - let err = |code| py.run(code, None, Some(d)).unwrap_err(); + let run = |code| py.run(code, None, Some(&d)).unwrap(); + let err = |code| py.run(code, None, Some(&d)).unwrap_err(); run("s = ByteSequence([1, 2, 3]); del s[0]; assert list(s) == [2, 3]"); run("s = ByteSequence([1, 2, 3]); del s[1]; assert list(s) == [1, 3]"); @@ -133,7 +133,7 @@ fn test_contains() { let py = gil.python(); let d = [("ByteSequence", py.get_type::())].into_py_dict(py); - let run = |code| py.run(code, None, Some(d)).unwrap(); + let run = |code| py.run(code, None, Some(&d)).unwrap(); run("s = ByteSequence([1, 2, 3]); assert 1 in s"); run("s = ByteSequence([1, 2, 3]); assert 2 in s"); @@ -148,8 +148,8 @@ fn test_concat() { let py = gil.python(); let d = [("ByteSequence", py.get_type::())].into_py_dict(py); - let run = |code| py.run(code, None, Some(d)).unwrap(); - let err = |code| py.run(code, None, Some(d)).unwrap_err(); + let run = |code| py.run(code, None, Some(&d)).unwrap(); + let err = |code| py.run(code, None, Some(&d)).unwrap_err(); run("s1 = ByteSequence([1, 2]); s2 = ByteSequence([3, 4]); assert list(s1+s2) == [1, 2, 3, 4]"); err("s1 = ByteSequence([1, 2]); s2 = 'hello'; s1 + s2"); @@ -161,8 +161,8 @@ fn test_inplace_concat() { let py = gil.python(); let d = [("ByteSequence", py.get_type::())].into_py_dict(py); - let run = |code| py.run(code, None, Some(d)).unwrap(); - let err = |code| py.run(code, None, Some(d)).unwrap_err(); + let run = |code| py.run(code, None, Some(&d)).unwrap(); + let err = |code| py.run(code, None, Some(&d)).unwrap_err(); run("s = ByteSequence([1, 2]); s += ByteSequence([3, 4]); assert list(s) == [1, 2, 3, 4]"); err("s = ByteSequence([1, 2]); s += 'hello'"); @@ -174,8 +174,8 @@ fn test_repeat() { let py = gil.python(); let d = [("ByteSequence", py.get_type::())].into_py_dict(py); - let run = |code| py.run(code, None, Some(d)).unwrap(); - let err = |code| py.run(code, None, Some(d)).unwrap_err(); + let run = |code| py.run(code, None, Some(&d)).unwrap(); + let err = |code| py.run(code, None, Some(&d)).unwrap_err(); run("s1 = ByteSequence([1, 2, 3]); s2 = s1*2; assert list(s2) == [1, 2, 3, 1, 2, 3]"); err("s1 = ByteSequence([1, 2, 3]); s2 = s1*-1; assert list(s2) == [1, 2, 3, 1, 2, 3]"); @@ -187,8 +187,8 @@ fn test_inplace_repeat() { let py = gil.python(); let d = [("ByteSequence", py.get_type::())].into_py_dict(py); - let run = |code| py.run(code, None, Some(d)).unwrap(); - let err = |code| py.run(code, None, Some(d)).unwrap_err(); + let run = |code| py.run(code, None, Some(&d)).unwrap(); + let err = |code| py.run(code, None, Some(&d)).unwrap_err(); run("s = ByteSequence([1, 2]); s *= 3; assert list(s) == [1, 2, 1, 2, 1, 2]"); err("s = ByteSequence([1, 2); s *= -1"); diff --git a/tests/test_variable_arguments.rs b/tests/test_variable_arguments.rs index efaecef059b..ced7dc6f51b 100644 --- a/tests/test_variable_arguments.rs +++ b/tests/test_variable_arguments.rs @@ -10,13 +10,13 @@ struct MyClass {} impl MyClass { #[staticmethod] #[args(args = "*")] - fn test_args(args: &PyTuple) -> PyResult<&PyTuple> { - Ok(args) + fn test_args(args: PyTuple) -> PyResult { + Ok(args.clone()) } #[staticmethod] #[args(kwargs = "**")] - fn test_kwargs(kwargs: Option<&PyDict>) -> PyResult> { + fn test_kwargs<'py>(kwargs: Option<&'py PyDict>) -> PyResult>> { Ok(kwargs) } } diff --git a/tests/test_various.rs b/tests/test_various.rs index 99708e0eb95..c8bfac483f3 100644 --- a/tests/test_various.rs +++ b/tests/test_various.rs @@ -30,7 +30,7 @@ fn mut_ref_arg() { let d = [("inst1", &inst1), ("inst2", &inst2)].into_py_dict(py); - py.run("inst1.set_other(inst2)", None, Some(d)).unwrap(); + py.run("inst1.set_other(inst2)", None, Some(&d)).unwrap(); let inst2 = inst2.as_ref(py).borrow(); assert_eq!(inst2.n, 100); } @@ -128,11 +128,11 @@ impl PickleSupport { } pub fn __reduce__<'py>( - slf: &'py PyCell, + slf: &PyCell<'py, Self>, py: Python<'py>, - ) -> PyResult<(PyObject, &'py PyTuple, PyObject)> { - let cls = slf.to_object(py).getattr(py, "__class__")?; - let dict = slf.to_object(py).getattr(py, "__dict__")?; + ) -> PyResult<(PyAny<'py>, PyTuple<'py>, PyAny<'py>)> { + let cls = slf.getattr("__class__")?; + let dict = slf.getattr("__dict__")?; Ok((cls, PyTuple::empty(py), dict)) } } @@ -152,7 +152,7 @@ fn test_pickle() { let py = gil.python(); let module = PyModule::new(py, "test_module").unwrap(); module.add_class::().unwrap(); - add_module(py, module).unwrap(); + add_module(py, &module).unwrap(); let inst = PyCell::new(py, PickleSupport {}).unwrap(); py_run!( py, diff --git a/tests/ui/missing_clone.stderr b/tests/ui/missing_clone.stderr index bb243766f3d..024abf96550 100644 --- a/tests/ui/missing_clone.stderr +++ b/tests/ui/missing_clone.stderr @@ -4,4 +4,4 @@ error[E0277]: the trait bound `TestClass: std::clone::Clone` is not satisfied 15 | let t: TestClass = pyvalue.extract(py).unwrap(); | ^^^^^^^ the trait `std::clone::Clone` is not implemented for `TestClass` | - = note: required because of the requirements on the impl of `pyo3::conversion::FromPyObject<'_>` for `TestClass` + = note: required because of the requirements on the impl of `pyo3::conversion::FromPyObject<'_, '_>` for `TestClass` diff --git a/tests/ui/static_ref.rs b/tests/ui/static_ref.rs index 5202920ac03..79f1a3b2cac 100644 --- a/tests/ui/static_ref.rs +++ b/tests/ui/static_ref.rs @@ -3,7 +3,7 @@ use pyo3::types::PyList; #[pyclass] struct MyClass { - list: &'static PyList, + list: &'static PyList<'static>, } #[pymethods] diff --git a/tests/ui/wrong_aspyref_lifetimes.rs b/tests/ui/wrong_aspyref_lifetimes.rs index 20d94b2367c..9f81ce1749b 100644 --- a/tests/ui/wrong_aspyref_lifetimes.rs +++ b/tests/ui/wrong_aspyref_lifetimes.rs @@ -1,8 +1,9 @@ +use pyo3::type_marker::Dict; use pyo3::{types::PyDict, AsPyRef, Py, PyNativeType, Python}; fn main() { let gil = Python::acquire_gil(); - let dict: Py = PyDict::new(gil.python()).into(); + let dict: Py = PyDict::new(gil.python()).into(); let dict: &PyDict = dict.as_ref(gil.python()); drop(gil); diff --git a/tests/ui/wrong_aspyref_lifetimes.stderr b/tests/ui/wrong_aspyref_lifetimes.stderr index 7c3b87ce86b..e082bbf2d2c 100644 --- a/tests/ui/wrong_aspyref_lifetimes.stderr +++ b/tests/ui/wrong_aspyref_lifetimes.stderr @@ -1,10 +1,10 @@ error[E0505]: cannot move out of `gil` because it is borrowed - --> $DIR/wrong_aspyref_lifetimes.rs:7:10 - | -6 | let dict: &PyDict = dict.as_ref(gil.python()); - | --- borrow of `gil` occurs here -7 | drop(gil); - | ^^^ move out of `gil` occurs here -8 | -9 | let _py: Python = dict.py(); // Obtain a Python<'p> without GIL. - | ---- borrow later used here + --> $DIR/wrong_aspyref_lifetimes.rs:8:10 + | +7 | let dict: &PyDict = dict.as_ref(gil.python()); + | --- borrow of `gil` occurs here +8 | drop(gil); + | ^^^ move out of `gil` occurs here +9 | +10 | let _py: Python = dict.py(); // Obtain a Python<'p> without GIL. + | ---- borrow later used here