1use pyo3::prelude::*;
2use pyo3::types::{PyDict, PyList};
3use std::collections::HashMap;
4
5pub trait IntoPython {
7 fn into_python(self, py: Python) -> PyResult<Py<PyAny>>;
8}
9
10pub trait FromPython: Sized {
12 fn from_python(obj: &Bound<PyAny>) -> PyResult<Self>;
13}
14
15impl IntoPython for i32 {
17 fn into_python(self, py: Python) -> PyResult<Py<PyAny>> {
18 Ok(self.into_py(py))
19 }
20}
21
22impl FromPython for i32 {
23 fn from_python(obj: &Bound<PyAny>) -> PyResult<Self> {
24 obj.extract()
25 }
26}
27
28impl IntoPython for i64 {
29 fn into_python(self, py: Python) -> PyResult<Py<PyAny>> {
30 Ok(self.into_py(py))
31 }
32}
33
34impl FromPython for i64 {
35 fn from_python(obj: &Bound<PyAny>) -> PyResult<Self> {
36 obj.extract()
37 }
38}
39
40impl IntoPython for f32 {
41 fn into_python(self, py: Python) -> PyResult<Py<PyAny>> {
42 Ok(self.into_py(py))
43 }
44}
45
46impl FromPython for f32 {
47 fn from_python(obj: &Bound<PyAny>) -> PyResult<Self> {
48 obj.extract()
49 }
50}
51
52impl IntoPython for f64 {
53 fn into_python(self, py: Python) -> PyResult<Py<PyAny>> {
54 Ok(self.into_py(py))
55 }
56}
57
58impl FromPython for f64 {
59 fn from_python(obj: &Bound<PyAny>) -> PyResult<Self> {
60 obj.extract()
61 }
62}
63
64impl IntoPython for bool {
65 fn into_python(self, py: Python) -> PyResult<Py<PyAny>> {
66 Ok(self.into_py(py))
67 }
68}
69
70impl FromPython for bool {
71 fn from_python(obj: &Bound<PyAny>) -> PyResult<Self> {
72 obj.extract()
73 }
74}
75
76impl IntoPython for String {
77 fn into_python(self, py: Python) -> PyResult<Py<PyAny>> {
78 Ok(self.into_py(py))
79 }
80}
81
82impl FromPython for String {
83 fn from_python(obj: &Bound<PyAny>) -> PyResult<Self> {
84 obj.extract()
85 }
86}
87
88impl IntoPython for &str {
89 fn into_python(self, py: Python) -> PyResult<Py<PyAny>> {
90 Ok(self.into_py(py))
91 }
92}
93
94impl<T> IntoPython for Vec<T>
96where
97 T: IntoPy<Py<PyAny>> + Clone,
98{
99 fn into_python(self, py: Python) -> PyResult<Py<PyAny>> {
100 let items: Vec<Py<PyAny>> = self.into_iter().map(|item| item.into_py(py)).collect();
101 let list = PyList::new_bound(py, &items);
102 Ok(list.into())
103 }
104}
105
106impl<T> FromPython for Vec<T>
107where
108 T: for<'py> FromPyObject<'py>,
109{
110 fn from_python(obj: &Bound<PyAny>) -> PyResult<Self> {
111 obj.extract()
112 }
113}
114
115impl<K, V> IntoPython for HashMap<K, V>
117where
118 K: IntoPy<Py<PyAny>> + std::hash::Hash + Eq,
119 V: IntoPy<Py<PyAny>>,
120{
121 fn into_python(self, py: Python) -> PyResult<Py<PyAny>> {
122 let dict = PyDict::new_bound(py);
123 for (k, v) in self {
124 dict.set_item(k.into_py(py), v.into_py(py))?;
125 }
126 Ok(dict.into())
127 }
128}
129
130impl<K, V> FromPython for HashMap<K, V>
131where
132 K: for<'py> FromPyObject<'py> + std::hash::Hash + Eq,
133 V: for<'py> FromPyObject<'py>,
134{
135 fn from_python(obj: &Bound<PyAny>) -> PyResult<Self> {
136 obj.extract()
137 }
138}
139
140impl<T> IntoPython for Option<T>
142where
143 T: IntoPython,
144{
145 fn into_python(self, py: Python) -> PyResult<Py<PyAny>> {
146 match self {
147 Some(value) => value.into_python(py),
148 None => Ok(py.None().into()),
149 }
150 }
151}
152
153impl<T> FromPython for Option<T>
154where
155 T: FromPython,
156{
157 fn from_python(obj: &Bound<PyAny>) -> PyResult<Self> {
158 if obj.is_none() {
159 Ok(None)
160 } else {
161 T::from_python(obj).map(Some)
162 }
163 }
164}
165
166pub fn to_python<T: IntoPython>(value: T) -> PyResult<Py<PyAny>> {
168 Python::with_gil(|py| value.into_python(py))
169}
170
171pub fn from_python<T: FromPython>(obj: Py<PyAny>) -> PyResult<T> {
173 Python::with_gil(|py| {
174 let bound = obj.bind(py);
175 T::from_python(bound)
176 })
177}