From 3563ef4fd17e3a1bf42331055a10f1c34d0e57e5 Mon Sep 17 00:00:00 2001 From: Icxolu <10486322+Icxolu@users.noreply.github.com> Date: Sun, 25 Aug 2024 17:45:59 +0200 Subject: [PATCH] migrate `IntoPyDict` --- src/conversions/hashbrown.rs | 18 +++++++---- src/conversions/indexmap.rs | 15 ++++++--- src/conversions/std/map.rs | 32 ++++++++++++------- src/types/dict.rs | 59 +++++++++++++++++------------------- 4 files changed, 71 insertions(+), 53 deletions(-) diff --git a/src/conversions/hashbrown.rs b/src/conversions/hashbrown.rs index e6cd46c4800..54495d682af 100644 --- a/src/conversions/hashbrown.rs +++ b/src/conversions/hashbrown.rs @@ -23,7 +23,7 @@ use crate::{ dict::PyDictMethods, frozenset::PyFrozenSetMethods, set::{new_from_iter, try_new_from_iter, PySetMethods}, - IntoPyDict, PyDict, PyFrozenSet, PySet, + PyDict, PyFrozenSet, PySet, }, Bound, BoundObject, FromPyObject, IntoPy, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject, }; @@ -36,7 +36,11 @@ where H: hash::BuildHasher, { fn to_object(&self, py: Python<'_>) -> PyObject { - IntoPyDict::into_py_dict(self, py).into() + let dict = PyDict::new(py); + for (k, v) in self { + dict.set_item(k.to_object(py), v.to_object(py)).unwrap(); + } + dict.into_any().unbind() } } @@ -47,10 +51,11 @@ where H: hash::BuildHasher, { fn into_py(self, py: Python<'_>) -> PyObject { - let iter = self - .into_iter() - .map(|(k, v)| (k.into_py(py), v.into_py(py))); - IntoPyDict::into_py_dict(iter, py).into() + let dict = PyDict::new(py); + for (k, v) in self { + dict.set_item(k.into_py(py), v.into_py(py)).unwrap(); + } + dict.into_any().unbind() } } @@ -197,6 +202,7 @@ where #[cfg(test)] mod tests { use super::*; + use crate::types::IntoPyDict; #[test] fn test_hashbrown_hashmap_to_python() { diff --git a/src/conversions/indexmap.rs b/src/conversions/indexmap.rs index 940c01eeaa1..72676ce1403 100644 --- a/src/conversions/indexmap.rs +++ b/src/conversions/indexmap.rs @@ -99,7 +99,11 @@ where H: hash::BuildHasher, { fn to_object(&self, py: Python<'_>) -> PyObject { - IntoPyDict::into_py_dict(self, py).into() + let dict = PyDict::new(py); + for (k, v) in self { + dict.set_item(k.to_object(py), v.to_object(py)).unwrap(); + } + dict.into_any().unbind() } } @@ -110,10 +114,11 @@ where H: hash::BuildHasher, { fn into_py(self, py: Python<'_>) -> PyObject { - let iter = self - .into_iter() - .map(|(k, v)| (k.into_py(py), v.into_py(py))); - IntoPyDict::into_py_dict(iter, py).into() + let dict = PyDict::new(py); + for (k, v) in self { + dict.set_item(k.into_py(py), v.into_py(py)).unwrap(); + } + dict.into_any().unbind() } } diff --git a/src/conversions/std/map.rs b/src/conversions/std/map.rs index 9affef926bf..582c56b613f 100644 --- a/src/conversions/std/map.rs +++ b/src/conversions/std/map.rs @@ -5,7 +5,7 @@ use crate::inspect::types::TypeInfo; use crate::{ conversion::IntoPyObject, instance::Bound, - types::{any::PyAnyMethods, dict::PyDictMethods, IntoPyDict, PyDict}, + types::{any::PyAnyMethods, dict::PyDictMethods, PyDict}, FromPyObject, IntoPy, PyAny, PyErr, PyObject, Python, ToPyObject, }; @@ -16,7 +16,11 @@ where H: hash::BuildHasher, { fn to_object(&self, py: Python<'_>) -> PyObject { - IntoPyDict::into_py_dict(self, py).into() + let dict = PyDict::new(py); + for (k, v) in self { + dict.set_item(k.to_object(py), v.to_object(py)).unwrap(); + } + dict.into_any().unbind() } } @@ -26,7 +30,11 @@ where V: ToPyObject, { fn to_object(&self, py: Python<'_>) -> PyObject { - IntoPyDict::into_py_dict(self, py).into() + let dict = PyDict::new(py); + for (k, v) in self { + dict.set_item(k.to_object(py), v.to_object(py)).unwrap(); + } + dict.into_any().unbind() } } @@ -37,10 +45,11 @@ where H: hash::BuildHasher, { fn into_py(self, py: Python<'_>) -> PyObject { - let iter = self - .into_iter() - .map(|(k, v)| (k.into_py(py), v.into_py(py))); - IntoPyDict::into_py_dict(iter, py).into() + let dict = PyDict::new(py); + for (k, v) in self { + dict.set_item(k.into_py(py), v.into_py(py)).unwrap(); + } + dict.into_any().unbind() } #[cfg(feature = "experimental-inspect")] @@ -93,10 +102,11 @@ where V: IntoPy, { fn into_py(self, py: Python<'_>) -> PyObject { - let iter = self - .into_iter() - .map(|(k, v)| (k.into_py(py), v.into_py(py))); - IntoPyDict::into_py_dict(iter, py).into() + let dict = PyDict::new(py); + for (k, v) in self { + dict.set_item(k.into_py(py), v.into_py(py)).unwrap(); + } + dict.into_any().unbind() } #[cfg(feature = "experimental-inspect")] diff --git a/src/types/dict.rs b/src/types/dict.rs index 4d8ce45d30e..dd1a5438ffe 100644 --- a/src/types/dict.rs +++ b/src/types/dict.rs @@ -6,7 +6,7 @@ use crate::instance::{Borrowed, Bound}; use crate::py_result_ext::PyResultExt; use crate::types::any::PyAnyMethods; use crate::types::{PyAny, PyList}; -use crate::{ffi, BoundObject, Python, ToPyObject}; +use crate::{ffi, BoundObject, Python}; /// Represents a Python `dict`. /// @@ -557,28 +557,29 @@ pub(crate) use borrowed_iter::BorrowedDictIter; /// Conversion trait that allows a sequence of tuples to be converted into `PyDict` /// Primary use case for this trait is `call` and `call_method` methods as keywords argument. -pub trait IntoPyDict: Sized { +pub trait IntoPyDict<'py>: Sized { /// Converts self into a `PyDict` object pointer. Whether pointer owned or borrowed /// depends on implementation. - fn into_py_dict(self, py: Python<'_>) -> Bound<'_, PyDict>; + fn into_py_dict(self, py: Python<'py>) -> Bound<'_, PyDict>; /// Deprecated name for [`IntoPyDict::into_py_dict`]. #[deprecated(since = "0.23.0", note = "renamed to `IntoPyDict::into_py_dict`")] #[inline] - fn into_py_dict_bound(self, py: Python<'_>) -> Bound<'_, PyDict> { + fn into_py_dict_bound(self, py: Python<'py>) -> Bound<'_, PyDict> { self.into_py_dict(py) } } -impl IntoPyDict for I +impl<'py, T, I> IntoPyDict<'py> for I where - T: PyDictItem, + T: PyDictItem<'py>, I: IntoIterator, { - fn into_py_dict(self, py: Python<'_>) -> Bound<'_, PyDict> { + fn into_py_dict(self, py: Python<'py>) -> Bound<'_, PyDict> { let dict = PyDict::new(py); for item in self { - dict.set_item(item.key().to_object(py), item.value().to_object(py)) + let (key, value) = item.unpack(); + dict.set_item(key, value) .expect("Failed to set_item on dict"); } dict @@ -586,40 +587,35 @@ where } /// Represents a tuple which can be used as a PyDict item. -pub trait PyDictItem { - type K: ToPyObject; - type V: ToPyObject; - fn key(&self) -> &Self::K; - fn value(&self) -> &Self::V; +pub trait PyDictItem<'py> { + type K: IntoPyObject<'py>; + type V: IntoPyObject<'py>; + fn unpack(self) -> (Self::K, Self::V); } -impl PyDictItem for (K, V) +impl<'py, K, V> PyDictItem<'py> for (K, V) where - K: ToPyObject, - V: ToPyObject, + K: IntoPyObject<'py>, + V: IntoPyObject<'py>, { type K = K; type V = V; - fn key(&self) -> &Self::K { - &self.0 - } - fn value(&self) -> &Self::V { - &self.1 + + fn unpack(self) -> (Self::K, Self::V) { + (self.0, self.1) } } -impl PyDictItem for &(K, V) +impl<'a, 'py, K, V> PyDictItem<'py> for &'a (K, V) where - K: ToPyObject, - V: ToPyObject, + &'a K: IntoPyObject<'py>, + &'a V: IntoPyObject<'py>, { - type K = K; - type V = V; - fn key(&self) -> &Self::K { - &self.0 - } - fn value(&self) -> &Self::V { - &self.1 + type K = &'a K; + type V = &'a V; + + fn unpack(self) -> (Self::K, Self::V) { + (&self.0, &self.1) } } @@ -627,6 +623,7 @@ where mod tests { use super::*; use crate::types::PyTuple; + use crate::ToPyObject; use std::collections::{BTreeMap, HashMap}; #[test]