diff --git a/src/conversions/hashbrown.rs b/src/conversions/hashbrown.rs index e6ebb35232e..a3fd61a6412 100644 --- a/src/conversions/hashbrown.rs +++ b/src/conversions/hashbrown.rs @@ -147,15 +147,7 @@ where type Error = PyErr; fn into_pyobject(self, py: Python<'py>) -> Result { - try_new_from_iter( - py, - self.into_iter().map(|item| { - item.into_pyobject(py) - .map(BoundObject::into_any) - .map(BoundObject::unbind) - .map_err(Into::into) - }), - ) + try_new_from_iter(py, self) } } @@ -169,15 +161,7 @@ where type Error = PyErr; fn into_pyobject(self, py: Python<'py>) -> Result { - try_new_from_iter( - py, - self.into_iter().map(|item| { - item.into_pyobject(py) - .map(BoundObject::into_any) - .map(BoundObject::unbind) - .map_err(Into::into) - }), - ) + try_new_from_iter(py, self) } } @@ -272,11 +256,11 @@ mod tests { #[test] fn test_extract_hashbrown_hashset() { Python::with_gil(|py| { - let set = PySet::new(py, &[1, 2, 3, 4, 5]).unwrap(); + let set = PySet::new(py, [1, 2, 3, 4, 5]).unwrap(); let hash_set: hashbrown::HashSet = set.extract().unwrap(); assert_eq!(hash_set, [1, 2, 3, 4, 5].iter().copied().collect()); - let set = PyFrozenSet::new(py, &[1, 2, 3, 4, 5]).unwrap(); + let set = PyFrozenSet::new(py, [1, 2, 3, 4, 5]).unwrap(); let hash_set: hashbrown::HashSet = set.extract().unwrap(); assert_eq!(hash_set, [1, 2, 3, 4, 5].iter().copied().collect()); }); diff --git a/src/conversions/std/set.rs b/src/conversions/std/set.rs index c9738069080..cc706c43f01 100644 --- a/src/conversions/std/set.rs +++ b/src/conversions/std/set.rs @@ -11,7 +11,7 @@ use crate::{ set::{new_from_iter, try_new_from_iter, PySetMethods}, PyFrozenSet, PySet, }, - BoundObject, FromPyObject, IntoPy, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject, + FromPyObject, IntoPy, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject, }; impl ToPyObject for collections::HashSet @@ -64,15 +64,7 @@ where type Error = PyErr; fn into_pyobject(self, py: Python<'py>) -> Result { - try_new_from_iter( - py, - self.into_iter().map(|item| { - item.into_pyobject(py) - .map(BoundObject::into_any) - .map(BoundObject::unbind) - .map_err(Into::into) - }), - ) + try_new_from_iter(py, self) } } @@ -86,15 +78,7 @@ where type Error = PyErr; fn into_pyobject(self, py: Python<'py>) -> Result { - try_new_from_iter( - py, - self.iter().map(|item| { - item.into_pyobject(py) - .map(BoundObject::into_any) - .map(BoundObject::unbind) - .map_err(Into::into) - }), - ) + try_new_from_iter(py, self.iter()) } } @@ -147,15 +131,7 @@ where type Error = PyErr; fn into_pyobject(self, py: Python<'py>) -> Result { - try_new_from_iter( - py, - self.into_iter().map(|item| { - item.into_pyobject(py) - .map(BoundObject::into_any) - .map(BoundObject::unbind) - .map_err(Into::into) - }), - ) + try_new_from_iter(py, self) } } @@ -168,15 +144,7 @@ where type Error = PyErr; fn into_pyobject(self, py: Python<'py>) -> Result { - try_new_from_iter( - py, - self.iter().map(|item| { - item.into_pyobject(py) - .map(BoundObject::into_any) - .map(BoundObject::unbind) - .map_err(Into::into) - }), - ) + try_new_from_iter(py, self.iter()) } } @@ -212,11 +180,11 @@ mod tests { #[test] fn test_extract_hashset() { Python::with_gil(|py| { - let set = PySet::new(py, &[1, 2, 3, 4, 5]).unwrap(); + let set = PySet::new(py, [1, 2, 3, 4, 5]).unwrap(); let hash_set: HashSet = set.extract().unwrap(); assert_eq!(hash_set, [1, 2, 3, 4, 5].iter().copied().collect()); - let set = PyFrozenSet::new(py, &[1, 2, 3, 4, 5]).unwrap(); + let set = PyFrozenSet::new(py, [1, 2, 3, 4, 5]).unwrap(); let hash_set: HashSet = set.extract().unwrap(); assert_eq!(hash_set, [1, 2, 3, 4, 5].iter().copied().collect()); }); @@ -225,11 +193,11 @@ mod tests { #[test] fn test_extract_btreeset() { Python::with_gil(|py| { - let set = PySet::new(py, &[1, 2, 3, 4, 5]).unwrap(); + let set = PySet::new(py, [1, 2, 3, 4, 5]).unwrap(); let hash_set: BTreeSet = set.extract().unwrap(); assert_eq!(hash_set, [1, 2, 3, 4, 5].iter().copied().collect()); - let set = PyFrozenSet::new(py, &[1, 2, 3, 4, 5]).unwrap(); + let set = PyFrozenSet::new(py, [1, 2, 3, 4, 5]).unwrap(); let hash_set: BTreeSet = set.extract().unwrap(); assert_eq!(hash_set, [1, 2, 3, 4, 5].iter().copied().collect()); }); diff --git a/src/instance.rs b/src/instance.rs index 1ff18f82466..2b19fd10c43 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -30,6 +30,8 @@ pub trait BoundObject<'py, T>: bound_object_sealed::Sealed { fn into_any(self) -> Self::Any; /// Turn this smart pointer into a strong reference pointer fn into_ptr(self) -> *mut ffi::PyObject; + /// Turn this smart pointer into a borrowed reference pointer + fn as_ptr(&self) -> *mut ffi::PyObject; /// Turn this smart pointer into an owned [`Py`] fn unbind(self) -> Py; } @@ -616,6 +618,10 @@ impl<'py, T> BoundObject<'py, T> for Bound<'py, T> { self.into_ptr() } + fn as_ptr(&self) -> *mut ffi::PyObject { + self.as_ptr() + } + fn unbind(self) -> Py { self.unbind() } @@ -835,6 +841,10 @@ impl<'a, 'py, T> BoundObject<'py, T> for Borrowed<'a, 'py, T> { (*self).to_owned().into_ptr() } + fn as_ptr(&self) -> *mut ffi::PyObject { + (*self).as_ptr() + } + fn unbind(self) -> Py { (*self).to_owned().unbind() } diff --git a/src/types/frozenset.rs b/src/types/frozenset.rs index 2e41864872d..88d726b136d 100644 --- a/src/types/frozenset.rs +++ b/src/types/frozenset.rs @@ -1,3 +1,4 @@ +use crate::conversion::IntoPyObject; use crate::types::PyIterator; use crate::{ err::{self, PyErr, PyResult}, @@ -5,8 +6,9 @@ use crate::{ ffi_ptr_ext::FfiPtrExt, py_result_ext::PyResultExt, types::any::PyAnyMethods, - Bound, PyAny, PyObject, Python, ToPyObject, + Bound, PyAny, Python, ToPyObject, }; +use crate::{Borrowed, BoundObject}; use std::ptr; /// Allows building a Python `frozenset` one item at a time @@ -27,15 +29,21 @@ impl<'py> PyFrozenSetBuilder<'py> { /// Adds an element to the set. pub fn add(&mut self, key: K) -> PyResult<()> where - K: ToPyObject, + K: IntoPyObject<'py>, { - fn inner(frozenset: &Bound<'_, PyFrozenSet>, key: PyObject) -> PyResult<()> { + fn inner(frozenset: &Bound<'_, PyFrozenSet>, key: Borrowed<'_, '_, PyAny>) -> PyResult<()> { err::error_on_minusone(frozenset.py(), unsafe { ffi::PySet_Add(frozenset.as_ptr(), key.as_ptr()) }) } - inner(&self.py_frozen_set, key.to_object(self.py_frozen_set.py())) + inner( + &self.py_frozen_set, + key.into_pyobject(self.py_frozen_set.py()) + .map_err(Into::into)? + .into_any() + .as_borrowed(), + ) } /// Finish building the set and take ownership of its current value @@ -83,11 +91,14 @@ impl PyFrozenSet { /// /// May panic when running out of memory. #[inline] - pub fn new<'a, 'p, T: ToPyObject + 'a>( - py: Python<'p>, - elements: impl IntoIterator, - ) -> PyResult> { - new_from_iter(py, elements) + pub fn new<'py, T>( + py: Python<'py>, + elements: impl IntoIterator, + ) -> PyResult> + where + T: IntoPyObject<'py>, + { + try_new_from_iter(py, elements) } /// Deprecated name for [`PyFrozenSet::new`]. @@ -97,7 +108,7 @@ impl PyFrozenSet { py: Python<'p>, elements: impl IntoIterator, ) -> PyResult> { - Self::new(py, elements) + Self::new(py, elements.into_iter().map(|e| e.to_object(py))) } /// Creates a new empty frozen set @@ -139,7 +150,7 @@ pub trait PyFrozenSetMethods<'py>: crate::sealed::Sealed { /// This is equivalent to the Python expression `key in self`. fn contains(&self, key: K) -> PyResult where - K: ToPyObject; + K: IntoPyObject<'py>; /// Returns an iterator of values in this set. fn iter(&self) -> BoundFrozenSetIterator<'py>; @@ -153,9 +164,12 @@ impl<'py> PyFrozenSetMethods<'py> for Bound<'py, PyFrozenSet> { fn contains(&self, key: K) -> PyResult where - K: ToPyObject, + K: IntoPyObject<'py>, { - fn inner(frozenset: &Bound<'_, PyFrozenSet>, key: Bound<'_, PyAny>) -> PyResult { + fn inner( + frozenset: &Bound<'_, PyFrozenSet>, + key: Borrowed<'_, '_, PyAny>, + ) -> PyResult { match unsafe { ffi::PySet_Contains(frozenset.as_ptr(), key.as_ptr()) } { 1 => Ok(true), 0 => Ok(false), @@ -164,7 +178,13 @@ impl<'py> PyFrozenSetMethods<'py> for Bound<'py, PyFrozenSet> { } let py = self.py(); - inner(self, key.to_object(py).into_bound(py)) + inner( + self, + key.into_pyobject(py) + .map_err(Into::into)? + .into_any() + .as_borrowed(), + ) } fn iter(&self) -> BoundFrozenSetIterator<'py> { @@ -229,31 +249,27 @@ impl<'py> ExactSizeIterator for BoundFrozenSetIterator<'py> { } #[inline] -pub(crate) fn new_from_iter( - py: Python<'_>, +pub(crate) fn try_new_from_iter<'py, T>( + py: Python<'py>, elements: impl IntoIterator, -) -> PyResult> { - fn inner<'py>( - py: Python<'py>, - elements: &mut dyn Iterator, - ) -> PyResult> { - let set = unsafe { - // We create the `Py` pointer because its Drop cleans up the set if user code panics. - ffi::PyFrozenSet_New(std::ptr::null_mut()) - .assume_owned_or_err(py)? - .downcast_into_unchecked() - }; - let ptr = set.as_ptr(); - - for obj in elements { - err::error_on_minusone(py, unsafe { ffi::PySet_Add(ptr, obj.as_ptr()) })?; - } - - Ok(set) +) -> PyResult> +where + T: IntoPyObject<'py>, +{ + let set = unsafe { + // We create the `Py` pointer because its Drop cleans up the set if user code panics. + ffi::PyFrozenSet_New(std::ptr::null_mut()) + .assume_owned_or_err(py)? + .downcast_into_unchecked() + }; + let ptr = set.as_ptr(); + + for e in elements { + let obj = e.into_pyobject(py).map_err(Into::into)?; + err::error_on_minusone(py, unsafe { ffi::PySet_Add(ptr, obj.as_ptr()) })?; } - let mut iter = elements.into_iter().map(|e| e.to_object(py)); - inner(py, &mut iter) + Ok(set) } #[cfg(test)] @@ -263,7 +279,7 @@ mod tests { #[test] fn test_frozenset_new_and_len() { Python::with_gil(|py| { - let set = PyFrozenSet::new(py, &[1]).unwrap(); + let set = PyFrozenSet::new(py, [1]).unwrap(); assert_eq!(1, set.len()); let v = vec![1]; @@ -283,7 +299,7 @@ mod tests { #[test] fn test_frozenset_contains() { Python::with_gil(|py| { - let set = PyFrozenSet::new(py, &[1]).unwrap(); + let set = PyFrozenSet::new(py, [1]).unwrap(); assert!(set.contains(1).unwrap()); }); } @@ -291,7 +307,7 @@ mod tests { #[test] fn test_frozenset_iter() { Python::with_gil(|py| { - let set = PyFrozenSet::new(py, &[1]).unwrap(); + let set = PyFrozenSet::new(py, [1]).unwrap(); for el in set { assert_eq!(1i32, el.extract::().unwrap()); @@ -302,7 +318,7 @@ mod tests { #[test] fn test_frozenset_iter_bound() { Python::with_gil(|py| { - let set = PyFrozenSet::new(py, &[1]).unwrap(); + let set = PyFrozenSet::new(py, [1]).unwrap(); for el in &set { assert_eq!(1i32, el.extract::().unwrap()); @@ -313,7 +329,7 @@ mod tests { #[test] fn test_frozenset_iter_size_hint() { Python::with_gil(|py| { - let set = PyFrozenSet::new(py, &[1]).unwrap(); + let set = PyFrozenSet::new(py, [1]).unwrap(); let mut iter = set.iter(); // Exact size diff --git a/src/types/set.rs b/src/types/set.rs index 42b827a9ee0..eddc2eb8885 100644 --- a/src/types/set.rs +++ b/src/types/set.rs @@ -1,3 +1,4 @@ +use crate::conversion::IntoPyObject; use crate::types::PyIterator; use crate::{ err::{self, PyErr, PyResult}, @@ -6,7 +7,7 @@ use crate::{ py_result_ext::PyResultExt, types::any::PyAnyMethods, }; -use crate::{ffi, PyAny, PyObject, Python, ToPyObject}; +use crate::{ffi, Borrowed, BoundObject, PyAny, Python, ToPyObject}; use std::ptr; /// Represents a Python `set`. @@ -42,11 +43,14 @@ impl PySet { /// /// Returns an error if some element is not hashable. #[inline] - pub fn new<'a, 'p, T: ToPyObject + 'a>( - py: Python<'p>, - elements: impl IntoIterator, - ) -> PyResult> { - new_from_iter(py, elements) + pub fn new<'py, T>( + py: Python<'py>, + elements: impl IntoIterator, + ) -> PyResult> + where + T: IntoPyObject<'py>, + { + try_new_from_iter(py, elements) } /// Deprecated name for [`PySet::new`]. @@ -56,7 +60,7 @@ impl PySet { py: Python<'p>, elements: impl IntoIterator, ) -> PyResult> { - Self::new(py, elements) + Self::new(py, elements.into_iter().map(|e| e.to_object(py))) } /// Creates a new empty set. @@ -101,19 +105,19 @@ pub trait PySetMethods<'py>: crate::sealed::Sealed { /// This is equivalent to the Python expression `key in self`. fn contains(&self, key: K) -> PyResult where - K: ToPyObject; + K: IntoPyObject<'py>; /// Removes the element from the set if it is present. /// /// Returns `true` if the element was present in the set. fn discard(&self, key: K) -> PyResult where - K: ToPyObject; + K: IntoPyObject<'py>; /// Adds an element to the set. fn add(&self, key: K) -> PyResult<()> where - K: ToPyObject; + K: IntoPyObject<'py>; /// Removes and returns an arbitrary element from the set. fn pop(&self) -> Option>; @@ -141,9 +145,9 @@ impl<'py> PySetMethods<'py> for Bound<'py, PySet> { fn contains(&self, key: K) -> PyResult where - K: ToPyObject, + K: IntoPyObject<'py>, { - fn inner(set: &Bound<'_, PySet>, key: Bound<'_, PyAny>) -> PyResult { + fn inner(set: &Bound<'_, PySet>, key: Borrowed<'_, '_, PyAny>) -> PyResult { match unsafe { ffi::PySet_Contains(set.as_ptr(), key.as_ptr()) } { 1 => Ok(true), 0 => Ok(false), @@ -152,14 +156,20 @@ impl<'py> PySetMethods<'py> for Bound<'py, PySet> { } let py = self.py(); - inner(self, key.to_object(py).into_bound(py)) + inner( + self, + key.into_pyobject(py) + .map_err(Into::into)? + .into_any() + .as_borrowed(), + ) } fn discard(&self, key: K) -> PyResult where - K: ToPyObject, + K: IntoPyObject<'py>, { - fn inner(set: &Bound<'_, PySet>, key: Bound<'_, PyAny>) -> PyResult { + fn inner(set: &Bound<'_, PySet>, key: Borrowed<'_, '_, PyAny>) -> PyResult { match unsafe { ffi::PySet_Discard(set.as_ptr(), key.as_ptr()) } { 1 => Ok(true), 0 => Ok(false), @@ -168,21 +178,33 @@ impl<'py> PySetMethods<'py> for Bound<'py, PySet> { } let py = self.py(); - inner(self, key.to_object(py).into_bound(py)) + inner( + self, + key.into_pyobject(py) + .map_err(Into::into)? + .into_any() + .as_borrowed(), + ) } fn add(&self, key: K) -> PyResult<()> where - K: ToPyObject, + K: IntoPyObject<'py>, { - fn inner(set: &Bound<'_, PySet>, key: Bound<'_, PyAny>) -> PyResult<()> { + fn inner(set: &Bound<'_, PySet>, key: Borrowed<'_, '_, PyAny>) -> PyResult<()> { err::error_on_minusone(set.py(), unsafe { ffi::PySet_Add(set.as_ptr(), key.as_ptr()) }) } let py = self.py(); - inner(self, key.to_object(py).into_bound(py)) + inner( + self, + key.into_pyobject(py) + .map_err(Into::into)? + .into_any() + .as_borrowed(), + ) } fn pop(&self) -> Option> { @@ -268,15 +290,18 @@ pub(crate) fn new_from_iter( py: Python<'_>, elements: impl IntoIterator, ) -> PyResult> { - let mut iter = elements.into_iter().map(|e| Ok(e.to_object(py))); + let mut iter = elements.into_iter().map(|e| e.to_object(py)); try_new_from_iter(py, &mut iter) } #[inline] -pub(crate) fn try_new_from_iter( - py: Python<'_>, - elements: impl IntoIterator>, -) -> PyResult> { +pub(crate) fn try_new_from_iter<'py, T>( + py: Python<'py>, + elements: impl IntoIterator, +) -> PyResult> +where + T: IntoPyObject<'py>, +{ let set = unsafe { // We create the `Bound` pointer because its Drop cleans up the set if // user code errors or panics. @@ -286,8 +311,9 @@ pub(crate) fn try_new_from_iter( }; let ptr = set.as_ptr(); - for obj in elements { - err::error_on_minusone(py, unsafe { ffi::PySet_Add(ptr, obj?.as_ptr()) })?; + for e in elements { + let obj = e.into_pyobject(py).map_err(Into::into)?; + err::error_on_minusone(py, unsafe { ffi::PySet_Add(ptr, obj.as_ptr()) })?; } Ok(set) @@ -297,16 +323,17 @@ pub(crate) fn try_new_from_iter( mod tests { use super::PySet; use crate::{ + conversion::IntoPyObject, ffi, types::{PyAnyMethods, PySetMethods}, - Python, ToPyObject, + Python, }; use std::collections::HashSet; #[test] fn test_set_new() { Python::with_gil(|py| { - let set = PySet::new(py, &[1]).unwrap(); + let set = PySet::new(py, [1]).unwrap(); assert_eq!(1, set.len()); let v = vec![1]; @@ -326,13 +353,13 @@ mod tests { #[test] fn test_set_len() { Python::with_gil(|py| { - let mut v = HashSet::new(); - let ob = v.to_object(py); - let set = ob.downcast_bound::(py).unwrap(); + let mut v = HashSet::::new(); + let ob = (&v).into_pyobject(py).unwrap(); + let set = ob.downcast::().unwrap(); assert_eq!(0, set.len()); v.insert(7); - let ob = v.to_object(py); - let set2 = ob.downcast_bound::(py).unwrap(); + let ob = v.into_pyobject(py).unwrap(); + let set2 = ob.downcast::().unwrap(); assert_eq!(1, set2.len()); }); } @@ -340,7 +367,7 @@ mod tests { #[test] fn test_set_clear() { Python::with_gil(|py| { - let set = PySet::new(py, &[1]).unwrap(); + let set = PySet::new(py, [1]).unwrap(); assert_eq!(1, set.len()); set.clear(); assert_eq!(0, set.len()); @@ -350,7 +377,7 @@ mod tests { #[test] fn test_set_contains() { Python::with_gil(|py| { - let set = PySet::new(py, &[1]).unwrap(); + let set = PySet::new(py, [1]).unwrap(); assert!(set.contains(1).unwrap()); }); } @@ -358,7 +385,7 @@ mod tests { #[test] fn test_set_discard() { Python::with_gil(|py| { - let set = PySet::new(py, &[1]).unwrap(); + let set = PySet::new(py, [1]).unwrap(); assert!(!set.discard(2).unwrap()); assert_eq!(1, set.len()); @@ -373,7 +400,7 @@ mod tests { #[test] fn test_set_add() { Python::with_gil(|py| { - let set = PySet::new(py, &[1, 2]).unwrap(); + let set = PySet::new(py, [1, 2]).unwrap(); set.add(1).unwrap(); // Add a dupliated element assert!(set.contains(1).unwrap()); }); @@ -382,7 +409,7 @@ mod tests { #[test] fn test_set_pop() { Python::with_gil(|py| { - let set = PySet::new(py, &[1]).unwrap(); + let set = PySet::new(py, [1]).unwrap(); let val = set.pop(); assert!(val.is_some()); let val2 = set.pop(); @@ -400,7 +427,7 @@ mod tests { #[test] fn test_set_iter() { Python::with_gil(|py| { - let set = PySet::new(py, &[1]).unwrap(); + let set = PySet::new(py, [1]).unwrap(); for el in set { assert_eq!(1i32, el.extract::<'_, i32>().unwrap()); @@ -413,7 +440,7 @@ mod tests { use crate::types::any::PyAnyMethods; Python::with_gil(|py| { - let set = PySet::new(py, &[1]).unwrap(); + let set = PySet::new(py, [1]).unwrap(); for el in &set { assert_eq!(1i32, el.extract::().unwrap()); @@ -425,7 +452,7 @@ mod tests { #[should_panic] fn test_set_iter_mutation() { Python::with_gil(|py| { - let set = PySet::new(py, &[1, 2, 3, 4, 5]).unwrap(); + let set = PySet::new(py, [1, 2, 3, 4, 5]).unwrap(); for _ in &set { let _ = set.add(42); @@ -437,7 +464,7 @@ mod tests { #[should_panic] fn test_set_iter_mutation_same_len() { Python::with_gil(|py| { - let set = PySet::new(py, &[1, 2, 3, 4, 5]).unwrap(); + let set = PySet::new(py, [1, 2, 3, 4, 5]).unwrap(); for item in &set { let item: i32 = item.extract().unwrap(); @@ -450,7 +477,7 @@ mod tests { #[test] fn test_set_iter_size_hint() { Python::with_gil(|py| { - let set = PySet::new(py, &[1]).unwrap(); + let set = PySet::new(py, [1]).unwrap(); let mut iter = set.iter(); // Exact size