From 8d9b4dd153c6436bf0b9b8daacd799f40a0a8eed Mon Sep 17 00:00:00 2001 From: kngwyu Date: Mon, 18 Feb 2019 16:05:48 +0900 Subject: [PATCH] Introduce PyDictItem --- src/instance.rs | 2 +- src/types/dict.rs | 99 ++++++++++++++++++++++++++++++++--------------- 2 files changed, 68 insertions(+), 33 deletions(-) diff --git a/src/instance.rs b/src/instance.rs index 44093442..83c474d7 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -53,7 +53,7 @@ pub trait PyNativeType: PyObjectWithGIL {} /// let gil = Python::acquire_gil(); /// let py = gil.python(); /// let obj = PyRef::new(gil.python(), Point { x: 3, y: 4 }).unwrap(); -/// let d = vec![("p", obj)].into_py_dict(py); +/// let d = [("p", obj)].into_py_dict(py); /// py.run("assert p.length() == 12", None, Some(d)).unwrap(); /// ``` #[derive(Debug)] diff --git a/src/types/dict.rs b/src/types/dict.rs index a6e6a755..aa63f918 100644 --- a/src/types/dict.rs +++ b/src/types/dict.rs @@ -196,12 +196,7 @@ where H: hash::BuildHasher, { fn to_object(&self, py: Python) -> PyObject { - let dict = PyDict::new(py); - for (key, value) in self { - dict.set_item(key, value) - .expect("Failed to set_item on dict"); - } - dict.into() + IntoPyDict::into_py_dict(self, py).into() } } @@ -211,12 +206,7 @@ where V: ToPyObject, { fn to_object(&self, py: Python) -> PyObject { - let dict = PyDict::new(py); - for (key, value) in self { - dict.set_item(key, value) - .expect("Failed to set_item on dict"); - } - dict.into() + IntoPyDict::into_py_dict(self, py).into() } } @@ -227,27 +217,23 @@ where H: hash::BuildHasher, { fn into_object(self, py: Python) -> PyObject { - let dict = PyDict::new(py); - for (key, value) in self { - dict.set_item(key.into_object(py), value.into_object(py)) - .expect("Failed to set_item on dict"); - } - dict.into() + let iter = self + .into_iter() + .map(|(k, v)| (k.into_object(py), v.into_object(py))); + IntoPyDict::into_py_dict(iter, py).into() } } impl IntoPyObject for collections::BTreeMap where - K: cmp::Eq + ToPyObject, - V: ToPyObject, + K: cmp::Eq + IntoPyObject, + V: IntoPyObject, { fn into_object(self, py: Python) -> PyObject { - let dict = PyDict::new(py); - for (key, value) in self { - dict.set_item(key, value) - .expect("Failed to set_item on dict"); - } - dict.into() + let iter = self + .into_iter() + .map(|(k, v)| (k.into_object(py), v.into_object(py))); + IntoPyDict::into_py_dict(iter, py).into() } } @@ -259,22 +245,59 @@ pub trait IntoPyDict { fn into_py_dict(self, py: Python) -> &PyDict; } -impl IntoPyDict for I +impl IntoPyDict for I where - K: ToPyObject, - V: ToPyObject, - I: IntoIterator, + T: PyDictItem, + I: IntoIterator, { fn into_py_dict(self, py: Python) -> &PyDict { let dict = PyDict::new(py); - for (key, value) in self { - dict.set_item(key, value) + for item in self { + dict.set_item(item.key(), item.value()) .expect("Failed to set_item on dict"); } dict } } +/// 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; +} + +impl PyDictItem for (K, V) +where + K: ToPyObject, + V: ToPyObject, +{ + type K = K; + type V = V; + fn key(&self) -> &Self::K { + &self.0 + } + fn value(&self) -> &Self::V { + &self.1 + } +} + +impl PyDictItem for &(K, V) +where + K: ToPyObject, + V: ToPyObject, +{ + type K = K; + type V = V; + fn key(&self) -> &Self::K { + &self.0 + } + fn value(&self) -> &Self::V { + &self.1 + } +} + #[cfg(test)] mod test { use crate::conversion::{IntoPyObject, PyTryFrom, ToPyObject}; @@ -637,4 +660,16 @@ mod test { assert_eq!(py_map.len(), 3); assert_eq!(py_map.get_item("b").unwrap().extract::().unwrap(), 2); } + + #[test] + fn test_slice_into_dict() { + let gil = Python::acquire_gil(); + let py = gil.python(); + + let arr = [("a", 1), ("b", 2), ("c", 3)]; + let py_map = arr.into_py_dict(py); + + assert_eq!(py_map.len(), 3); + assert_eq!(py_map.get_item("b").unwrap().extract::().unwrap(), 2); + } }