Skip to content

Commit 3563ef4

Browse files
committed
migrate IntoPyDict
1 parent 7ead7ff commit 3563ef4

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

@@ -197,6 +202,7 @@ where
197202
#[cfg(test)]
198203
mod tests {
199204
use super::*;
205+
use crate::types::IntoPyDict;
200206

201207
#[test]
202208
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
///
@@ -557,76 +557,73 @@ pub(crate) use borrowed_iter::BorrowedDictIter;
557557

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

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

573-
impl<T, I> IntoPyDict for I
573+
impl<'py, T, I> IntoPyDict<'py> for I
574574
where
575-
T: PyDictItem,
575+
T: PyDictItem<'py>,
576576
I: IntoIterator<Item = T>,
577577
{
578-
fn into_py_dict(self, py: Python<'_>) -> Bound<'_, PyDict> {
578+
fn into_py_dict(self, py: Python<'py>) -> Bound<'_, PyDict> {
579579
let dict = PyDict::new(py);
580580
for item in self {
581-
dict.set_item(item.key().to_object(py), item.value().to_object(py))
581+
let (key, value) = item.unpack();
582+
dict.set_item(key, value)
582583
.expect("Failed to set_item on dict");
583584
}
584585
dict
585586
}
586587
}
587588

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

596-
impl<K, V> PyDictItem for (K, V)
596+
impl<'py, K, V> PyDictItem<'py> for (K, V)
597597
where
598-
K: ToPyObject,
599-
V: ToPyObject,
598+
K: IntoPyObject<'py>,
599+
V: IntoPyObject<'py>,
600600
{
601601
type K = K;
602602
type V = V;
603-
fn key(&self) -> &Self::K {
604-
&self.0
605-
}
606-
fn value(&self) -> &Self::V {
607-
&self.1
603+
604+
fn unpack(self) -> (Self::K, Self::V) {
605+
(self.0, self.1)
608606
}
609607
}
610608

611-
impl<K, V> PyDictItem for &(K, V)
609+
impl<'a, 'py, K, V> PyDictItem<'py> for &'a (K, V)
612610
where
613-
K: ToPyObject,
614-
V: ToPyObject,
611+
&'a K: IntoPyObject<'py>,
612+
&'a V: IntoPyObject<'py>,
615613
{
616-
type K = K;
617-
type V = V;
618-
fn key(&self) -> &Self::K {
619-
&self.0
620-
}
621-
fn value(&self) -> &Self::V {
622-
&self.1
614+
type K = &'a K;
615+
type V = &'a V;
616+
617+
fn unpack(self) -> (Self::K, Self::V) {
618+
(&self.0, &self.1)
623619
}
624620
}
625621

626622
#[cfg(test)]
627623
mod tests {
628624
use super::*;
629625
use crate::types::PyTuple;
626+
use crate::ToPyObject;
630627
use std::collections::{BTreeMap, HashMap};
631628

632629
#[test]

0 commit comments

Comments
 (0)