1 | use std::{cmp, collections, hash}; |
2 | |
3 | #[cfg (feature = "experimental-inspect" )] |
4 | use crate::inspect::types::TypeInfo; |
5 | use crate::{ |
6 | types::{IntoPyDict, PyDict}, |
7 | FromPyObject, IntoPy, PyAny, PyErr, PyObject, Python, ToPyObject, |
8 | }; |
9 | |
10 | impl<K, V, H> ToPyObject for collections::HashMap<K, V, H> |
11 | where |
12 | K: hash::Hash + cmp::Eq + ToPyObject, |
13 | V: ToPyObject, |
14 | H: hash::BuildHasher, |
15 | { |
16 | fn to_object(&self, py: Python<'_>) -> PyObject { |
17 | IntoPyDict::into_py_dict(self, py).into() |
18 | } |
19 | } |
20 | |
21 | impl<K, V> ToPyObject for collections::BTreeMap<K, V> |
22 | where |
23 | K: cmp::Eq + ToPyObject, |
24 | V: ToPyObject, |
25 | { |
26 | fn to_object(&self, py: Python<'_>) -> PyObject { |
27 | IntoPyDict::into_py_dict(self, py).into() |
28 | } |
29 | } |
30 | |
31 | impl<K, V, H> IntoPy<PyObject> for collections::HashMap<K, V, H> |
32 | where |
33 | K: hash::Hash + cmp::Eq + IntoPy<PyObject>, |
34 | V: IntoPy<PyObject>, |
35 | H: hash::BuildHasher, |
36 | { |
37 | fn into_py(self, py: Python<'_>) -> PyObject { |
38 | let iter: impl Iterator- , …)>
= self |
39 | .into_iter() |
40 | .map(|(k: K, v: V)| (k.into_py(py), v.into_py(py))); |
41 | IntoPyDict::into_py_dict(self:iter, py).into() |
42 | } |
43 | |
44 | #[cfg (feature = "experimental-inspect" )] |
45 | fn type_output() -> TypeInfo { |
46 | TypeInfo::dict_of(K::type_output(), V::type_output()) |
47 | } |
48 | } |
49 | |
50 | impl<K, V> IntoPy<PyObject> for collections::BTreeMap<K, V> |
51 | where |
52 | K: cmp::Eq + IntoPy<PyObject>, |
53 | V: IntoPy<PyObject>, |
54 | { |
55 | fn into_py(self, py: Python<'_>) -> PyObject { |
56 | let iter: impl Iterator- , …)>
= self |
57 | .into_iter() |
58 | .map(|(k: K, v: V)| (k.into_py(py), v.into_py(py))); |
59 | IntoPyDict::into_py_dict(self:iter, py).into() |
60 | } |
61 | |
62 | #[cfg (feature = "experimental-inspect" )] |
63 | fn type_output() -> TypeInfo { |
64 | TypeInfo::dict_of(K::type_output(), V::type_output()) |
65 | } |
66 | } |
67 | |
68 | impl<'source, K, V, S> FromPyObject<'source> for collections::HashMap<K, V, S> |
69 | where |
70 | K: FromPyObject<'source> + cmp::Eq + hash::Hash, |
71 | V: FromPyObject<'source>, |
72 | S: hash::BuildHasher + Default, |
73 | { |
74 | fn extract(ob: &'source PyAny) -> Result<Self, PyErr> { |
75 | let dict: &PyDict = ob.downcast()?; |
76 | let mut ret: HashMap = collections::HashMap::with_capacity_and_hasher(capacity:dict.len(), S::default()); |
77 | for (k: &PyAny, v: &PyAny) in dict { |
78 | ret.insert(K::extract(k)?, V::extract(ob:v)?); |
79 | } |
80 | Ok(ret) |
81 | } |
82 | |
83 | #[cfg (feature = "experimental-inspect" )] |
84 | fn type_input() -> TypeInfo { |
85 | TypeInfo::mapping_of(K::type_input(), V::type_input()) |
86 | } |
87 | } |
88 | |
89 | impl<'source, K, V> FromPyObject<'source> for collections::BTreeMap<K, V> |
90 | where |
91 | K: FromPyObject<'source> + cmp::Ord, |
92 | V: FromPyObject<'source>, |
93 | { |
94 | fn extract(ob: &'source PyAny) -> Result<Self, PyErr> { |
95 | let dict: &PyDict = ob.downcast()?; |
96 | let mut ret: BTreeMap = collections::BTreeMap::new(); |
97 | for (k: &PyAny, v: &PyAny) in dict { |
98 | ret.insert(K::extract(k)?, V::extract(ob:v)?); |
99 | } |
100 | Ok(ret) |
101 | } |
102 | |
103 | #[cfg (feature = "experimental-inspect" )] |
104 | fn type_input() -> TypeInfo { |
105 | TypeInfo::mapping_of(K::type_input(), V::type_input()) |
106 | } |
107 | } |
108 | |
109 | #[cfg (test)] |
110 | mod tests { |
111 | use super::*; |
112 | use crate::{IntoPy, PyObject, Python, ToPyObject}; |
113 | use std::collections::{BTreeMap, HashMap}; |
114 | |
115 | #[test ] |
116 | fn test_hashmap_to_python() { |
117 | Python::with_gil(|py| { |
118 | let mut map = HashMap::<i32, i32>::new(); |
119 | map.insert(1, 1); |
120 | |
121 | let m = map.to_object(py); |
122 | let py_map: &PyDict = m.downcast(py).unwrap(); |
123 | |
124 | assert!(py_map.len() == 1); |
125 | assert!( |
126 | py_map |
127 | .get_item(1) |
128 | .unwrap() |
129 | .unwrap() |
130 | .extract::<i32>() |
131 | .unwrap() |
132 | == 1 |
133 | ); |
134 | assert_eq!(map, py_map.extract().unwrap()); |
135 | }); |
136 | } |
137 | |
138 | #[test ] |
139 | fn test_btreemap_to_python() { |
140 | Python::with_gil(|py| { |
141 | let mut map = BTreeMap::<i32, i32>::new(); |
142 | map.insert(1, 1); |
143 | |
144 | let m = map.to_object(py); |
145 | let py_map: &PyDict = m.downcast(py).unwrap(); |
146 | |
147 | assert!(py_map.len() == 1); |
148 | assert!( |
149 | py_map |
150 | .get_item(1) |
151 | .unwrap() |
152 | .unwrap() |
153 | .extract::<i32>() |
154 | .unwrap() |
155 | == 1 |
156 | ); |
157 | assert_eq!(map, py_map.extract().unwrap()); |
158 | }); |
159 | } |
160 | |
161 | #[test ] |
162 | fn test_hashmap_into_python() { |
163 | Python::with_gil(|py| { |
164 | let mut map = HashMap::<i32, i32>::new(); |
165 | map.insert(1, 1); |
166 | |
167 | let m: PyObject = map.into_py(py); |
168 | let py_map: &PyDict = m.downcast(py).unwrap(); |
169 | |
170 | assert!(py_map.len() == 1); |
171 | assert!( |
172 | py_map |
173 | .get_item(1) |
174 | .unwrap() |
175 | .unwrap() |
176 | .extract::<i32>() |
177 | .unwrap() |
178 | == 1 |
179 | ); |
180 | }); |
181 | } |
182 | |
183 | #[test ] |
184 | fn test_btreemap_into_py() { |
185 | Python::with_gil(|py| { |
186 | let mut map = BTreeMap::<i32, i32>::new(); |
187 | map.insert(1, 1); |
188 | |
189 | let m: PyObject = map.into_py(py); |
190 | let py_map: &PyDict = m.downcast(py).unwrap(); |
191 | |
192 | assert!(py_map.len() == 1); |
193 | assert!( |
194 | py_map |
195 | .get_item(1) |
196 | .unwrap() |
197 | .unwrap() |
198 | .extract::<i32>() |
199 | .unwrap() |
200 | == 1 |
201 | ); |
202 | }); |
203 | } |
204 | } |
205 | |