Skip to main content

rustpy_ml/
convert.rs

1use pyo3::prelude::*;
2use pyo3::types::{PyDict, PyList};
3use std::collections::HashMap;
4
5/// Trait for converting Rust types to Python objects
6pub trait IntoPython {
7    fn into_python(self, py: Python) -> PyResult<Py<PyAny>>;
8}
9
10/// Trait for converting Python objects to Rust types
11pub trait FromPython: Sized {
12    fn from_python(obj: &Bound<PyAny>) -> PyResult<Self>;
13}
14
15// Implementations for primitive types
16impl 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
94// Vec implementations
95impl<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
115// HashMap implementations
116impl<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
140// Option implementations
141impl<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
166/// Helper function to convert Rust value to Python
167pub fn to_python<T: IntoPython>(value: T) -> PyResult<Py<PyAny>> {
168    Python::with_gil(|py| value.into_python(py))
169}
170
171/// Helper function to convert Python object to Rust value
172pub 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}