Skip to content

Commit 50e4b38

Browse files
committed
migrate IntoPyDict
1 parent 96cb7d0 commit 50e4b38

File tree

4 files changed

+71
-53
lines changed

4 files changed

+71
-53
lines changed

src/conversions/hashbrown.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use crate::{
2323
dict::PyDictMethods,
2424
frozenset::PyFrozenSetMethods,
2525
set::{new_from_iter, try_new_from_iter, PySetMethods},
26-
IntoPyDict, PyDict, PyFrozenSet, PySet,
26+
PyDict, PyFrozenSet, PySet,
2727
},
2828
Bound, BoundObject, FromPyObject, IntoPy, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject,
2929
};
@@ -36,7 +36,11 @@ where
3636
H: hash::BuildHasher,
3737
{
3838
fn to_object(&self, py: Python<'_>) -> PyObject {
39-
IntoPyDict::into_py_dict(self, py).into()
39+
let dict = PyDict::new(py);
40+
for (k, v) in self {
41+
dict.set_item(k.to_object(py), v.to_object(py)).unwrap();
42+
}
43+
dict.into_any().unbind()
4044
}
4145
}
4246

@@ -47,10 +51,11 @@ where
4751
H: hash::BuildHasher,
4852
{
4953
fn into_py(self, py: Python<'_>) -> PyObject {
50-
let iter = self
51-
.into_iter()
52-
.map(|(k, v)| (k.into_py(py), v.into_py(py)));
53-
IntoPyDict::into_py_dict(iter, py).into()
54+
let dict = PyDict::new(py);
55+
for (k, v) in self {
56+
dict.set_item(k.into_py(py), v.into_py(py)).unwrap();
57+
}
58+
dict.into_any().unbind()
5459
}
5560
}
5661

@@ -181,6 +186,7 @@ where
181186
#[cfg(test)]
182187
mod tests {
183188
use super::*;
189+
use crate::types::IntoPyDict;
184190

185191
#[test]
186192
fn test_hashbrown_hashmap_to_python() {

src/conversions/indexmap.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,11 @@ where
9999
H: hash::BuildHasher,
100100
{
101101
fn to_object(&self, py: Python<'_>) -> PyObject {
102-
IntoPyDict::into_py_dict(self, py).into()
102+
let dict = PyDict::new(py);
103+
for (k, v) in self {
104+
dict.set_item(k.to_object(py), v.to_object(py)).unwrap();
105+
}
106+
dict.into_any().unbind()
103107
}
104108
}
105109

@@ -110,10 +114,11 @@ where
110114
H: hash::BuildHasher,
111115
{
112116
fn into_py(self, py: Python<'_>) -> PyObject {
113-
let iter = self
114-
.into_iter()
115-
.map(|(k, v)| (k.into_py(py), v.into_py(py)));
116-
IntoPyDict::into_py_dict(iter, py).into()
117+
let dict = PyDict::new(py);
118+
for (k, v) in self {
119+
dict.set_item(k.into_py(py), v.into_py(py)).unwrap();
120+
}
121+
dict.into_any().unbind()
117122
}
118123
}
119124

src/conversions/std/map.rs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::inspect::types::TypeInfo;
55
use crate::{
66
conversion::IntoPyObject,
77
instance::Bound,
8-
types::{any::PyAnyMethods, dict::PyDictMethods, IntoPyDict, PyDict},
8+
types::{any::PyAnyMethods, dict::PyDictMethods, PyDict},
99
FromPyObject, IntoPy, PyAny, PyErr, PyObject, Python, ToPyObject,
1010
};
1111

@@ -16,7 +16,11 @@ where
1616
H: hash::BuildHasher,
1717
{
1818
fn to_object(&self, py: Python<'_>) -> PyObject {
19-
IntoPyDict::into_py_dict(self, py).into()
19+
let dict = PyDict::new(py);
20+
for (k, v) in self {
21+
dict.set_item(k.to_object(py), v.to_object(py)).unwrap();
22+
}
23+
dict.into_any().unbind()
2024
}
2125
}
2226

@@ -26,7 +30,11 @@ where
2630
V: ToPyObject,
2731
{
2832
fn to_object(&self, py: Python<'_>) -> PyObject {
29-
IntoPyDict::into_py_dict(self, py).into()
33+
let dict = PyDict::new(py);
34+
for (k, v) in self {
35+
dict.set_item(k.to_object(py), v.to_object(py)).unwrap();
36+
}
37+
dict.into_any().unbind()
3038
}
3139
}
3240

@@ -37,10 +45,11 @@ where
3745
H: hash::BuildHasher,
3846
{
3947
fn into_py(self, py: Python<'_>) -> PyObject {
40-
let iter = self
41-
.into_iter()
42-
.map(|(k, v)| (k.into_py(py), v.into_py(py)));
43-
IntoPyDict::into_py_dict(iter, py).into()
48+
let dict = PyDict::new(py);
49+
for (k, v) in self {
50+
dict.set_item(k.into_py(py), v.into_py(py)).unwrap();
51+
}
52+
dict.into_any().unbind()
4453
}
4554

4655
#[cfg(feature = "experimental-inspect")]
@@ -93,10 +102,11 @@ where
93102
V: IntoPy<PyObject>,
94103
{
95104
fn into_py(self, py: Python<'_>) -> PyObject {
96-
let iter = self
97-
.into_iter()
98-
.map(|(k, v)| (k.into_py(py), v.into_py(py)));
99-
IntoPyDict::into_py_dict(iter, py).into()
105+
let dict = PyDict::new(py);
106+
for (k, v) in self {
107+
dict.set_item(k.into_py(py), v.into_py(py)).unwrap();
108+
}
109+
dict.into_any().unbind()
100110
}
101111

102112
#[cfg(feature = "experimental-inspect")]

src/types/dict.rs

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::instance::{Borrowed, Bound};
66
use crate::py_result_ext::PyResultExt;
77
use crate::types::any::PyAnyMethods;
88
use crate::types::{PyAny, PyList};
9-
use crate::{ffi, BoundObject, Python, ToPyObject};
9+
use crate::{ffi, BoundObject, Python};
1010

1111
/// Represents a Python `dict`.
1212
///
@@ -559,76 +559,73 @@ pub(crate) use borrowed_iter::BorrowedDictIter;
559559

560560
/// Conversion trait that allows a sequence of tuples to be converted into `PyDict`
561561
/// Primary use case for this trait is `call` and `call_method` methods as keywords argument.
562-
pub trait IntoPyDict: Sized {
562+
pub trait IntoPyDict<'py>: Sized {
563563
/// Converts self into a `PyDict` object pointer. Whether pointer owned or borrowed
564564
/// depends on implementation.
565-
fn into_py_dict(self, py: Python<'_>) -> Bound<'_, PyDict>;
565+
fn into_py_dict(self, py: Python<'py>) -> Bound<'_, PyDict>;
566566

567567
/// Deprecated name for [`IntoPyDict::into_py_dict`].
568568
#[deprecated(since = "0.23.0", note = "renamed to `IntoPyDict::into_py_dict`")]
569569
#[inline]
570-
fn into_py_dict_bound(self, py: Python<'_>) -> Bound<'_, PyDict> {
570+
fn into_py_dict_bound(self, py: Python<'py>) -> Bound<'_, PyDict> {
571571
self.into_py_dict(py)
572572
}
573573
}
574574

575-
impl<T, I> IntoPyDict for I
575+
impl<'py, T, I> IntoPyDict<'py> for I
576576
where
577-
T: PyDictItem,
577+
T: PyDictItem<'py>,
578578
I: IntoIterator<Item = T>,
579579
{
580-
fn into_py_dict(self, py: Python<'_>) -> Bound<'_, PyDict> {
580+
fn into_py_dict(self, py: Python<'py>) -> Bound<'_, PyDict> {
581581
let dict = PyDict::new(py);
582582
for item in self {
583-
dict.set_item(item.key().to_object(py), item.value().to_object(py))
583+
let (key, value) = item.unpack();
584+
dict.set_item(key, value)
584585
.expect("Failed to set_item on dict");
585586
}
586587
dict
587588
}
588589
}
589590

590591
/// Represents a tuple which can be used as a PyDict item.
591-
pub trait PyDictItem {
592-
type K: ToPyObject;
593-
type V: ToPyObject;
594-
fn key(&self) -> &Self::K;
595-
fn value(&self) -> &Self::V;
592+
pub trait PyDictItem<'py> {
593+
type K: IntoPyObject<'py>;
594+
type V: IntoPyObject<'py>;
595+
fn unpack(self) -> (Self::K, Self::V);
596596
}
597597

598-
impl<K, V> PyDictItem for (K, V)
598+
impl<'py, K, V> PyDictItem<'py> for (K, V)
599599
where
600-
K: ToPyObject,
601-
V: ToPyObject,
600+
K: IntoPyObject<'py>,
601+
V: IntoPyObject<'py>,
602602
{
603603
type K = K;
604604
type V = V;
605-
fn key(&self) -> &Self::K {
606-
&self.0
607-
}
608-
fn value(&self) -> &Self::V {
609-
&self.1
605+
606+
fn unpack(self) -> (Self::K, Self::V) {
607+
(self.0, self.1)
610608
}
611609
}
612610

613-
impl<K, V> PyDictItem for &(K, V)
611+
impl<'a, 'py, K, V> PyDictItem<'py> for &'a (K, V)
614612
where
615-
K: ToPyObject,
616-
V: ToPyObject,
613+
&'a K: IntoPyObject<'py>,
614+
&'a V: IntoPyObject<'py>,
617615
{
618-
type K = K;
619-
type V = V;
620-
fn key(&self) -> &Self::K {
621-
&self.0
622-
}
623-
fn value(&self) -> &Self::V {
624-
&self.1
616+
type K = &'a K;
617+
type V = &'a V;
618+
619+
fn unpack(self) -> (Self::K, Self::V) {
620+
(&self.0, &self.1)
625621
}
626622
}
627623

628624
#[cfg(test)]
629625
mod tests {
630626
use super::*;
631627
use crate::types::PyTuple;
628+
use crate::ToPyObject;
632629
use std::collections::{BTreeMap, HashMap};
633630

634631
#[test]

0 commit comments

Comments
 (0)