querent_synapse/cross/
clrepr_python.rs1use crate::cross::{clrepr::CLReprObject, CLRepr, StringType};
2use pyo3::{
3 exceptions::{PyNotImplementedError, PyTypeError},
4 types::{
5 PyBool, PyComplex, PyDate, PyDict, PyFloat, PyFrame, PyFunction, PyInt, PyList, PySequence,
6 PySet, PyString, PyTraceback, PyTuple,
7 },
8 Py, PyAny, PyErr, PyObject, Python, ToPyObject,
9};
10
11#[derive(Debug, Clone)]
12pub enum PythonRef {
13 PyObject(PyObject),
14 PyFunction(Py<PyFunction>),
15 PyExternalFunction(Py<PyFunction>),
18}
19
20pub trait CLReprPython: Sized {
21 fn from_python_ref(v: &PyAny) -> Result<Self, PyErr>;
22 fn into_py_impl(from: CLRepr, py: Python) -> Result<PyObject, PyErr>;
23 fn into_py(self, py: Python) -> Result<PyObject, PyErr>;
24}
25
26impl CLReprPython for CLRepr {
27 fn from_python_ref(v: &PyAny) -> Result<Self, PyErr> {
29 if v.is_none() {
30 return Ok(Self::Null);
31 }
32
33 return Ok(if v.get_type().is_subclass_of::<PyString>()? {
34 let string_type =
35 if v.hasattr("is_safe")? { StringType::Safe } else { StringType::Normal };
36
37 Self::String(v.to_string(), string_type)
38 } else if v.get_type().is_subclass_of::<PyBool>()? {
39 Self::Bool(v.downcast::<PyBool>()?.is_true())
40 } else if v.get_type().is_subclass_of::<PyFloat>()? {
41 let f = v.downcast::<PyFloat>()?;
42 Self::Float(f.value())
43 } else if v.get_type().is_subclass_of::<PyInt>()? {
44 let i: i64 = v.downcast::<PyInt>()?.extract()?;
45 Self::Int(i)
46 } else if v.get_type().is_subclass_of::<PyDict>()? {
47 let d = v.downcast::<PyDict>()?;
48 let mut obj = CLReprObject::new();
49
50 for (k, v) in d.iter() {
51 if k.get_type().is_subclass_of::<PyString>()? {
52 let key_str = k.downcast::<PyString>()?;
53
54 obj.insert(key_str.to_string(), Self::from_python_ref(v)?);
55 }
56 }
57
58 Self::Object(obj)
59 } else if v.get_type().is_subclass_of::<PyList>()? {
60 let l = v.downcast::<PyList>()?;
61 let mut r = Vec::with_capacity(l.len());
62
63 for v in l.iter() {
64 r.push(Self::from_python_ref(v)?);
65 }
66
67 Self::Array(r)
68 } else if v.get_type().is_subclass_of::<PySet>()? {
69 let l = v.downcast::<PySet>()?;
70 let mut r = Vec::with_capacity(l.len());
71
72 for v in l.iter() {
73 r.push(Self::from_python_ref(v)?);
74 }
75
76 Self::Array(r)
77 } else if v.get_type().is_subclass_of::<PyTuple>()? {
78 let l = v.downcast::<PyTuple>()?;
79 let mut r = Vec::with_capacity(l.len());
80
81 for v in l.iter() {
82 r.push(Self::from_python_ref(v)?);
83 }
84
85 Self::Tuple(r)
86 } else if v.get_type().is_subclass_of::<PyFunction>()? {
87 let fun: Py<PyFunction> = v.downcast::<PyFunction>()?.into();
88
89 Self::PythonRef(PythonRef::PyFunction(fun))
90 } else if v.get_type().is_subclass_of::<PyComplex>()? {
91 return Err(PyErr::new::<PyTypeError, _>(
92 "Unable to represent PyComplex type as CLR from Python".to_string(),
93 ));
94 } else if v.get_type().is_subclass_of::<PyDate>()? {
95 return Err(PyErr::new::<PyTypeError, _>(
96 "Unable to represent PyDate type as CLR from Python".to_string(),
97 ));
98 } else if v.get_type().is_subclass_of::<PyFrame>()? {
99 let frame = v.downcast::<PyFrame>()?;
100
101 return Err(PyErr::new::<PyTypeError, _>(format!(
102 "Unable to represent PyFrame type as CLR from Python, value: {:?}",
103 frame
104 )));
105 } else if v.get_type().is_subclass_of::<PyTraceback>()? {
106 let trb = v.downcast::<PyTraceback>()?;
107
108 return Err(PyErr::new::<PyTypeError, _>(format!(
109 "Unable to represent PyTraceback type as CLR from Python, value: {:?}",
110 trb
111 )));
112 } else {
113 let is_sequence = unsafe { pyo3::ffi::PySequence_Check(v.as_ptr()) == 1 };
114 if is_sequence {
115 let seq = v.downcast::<PySequence>()?;
116
117 return Err(PyErr::new::<PyTypeError, _>(format!(
118 "Unable to represent PySequence type as CLR from Python, value: {:?}",
119 seq
120 )));
121 }
122
123 Self::PythonRef(PythonRef::PyObject(v.into()))
124 });
125 }
126
127 fn into_py_impl(from: CLRepr, py: Python) -> Result<PyObject, PyErr> {
128 Ok(match from {
129 CLRepr::String(v, _) => PyString::new(py, &v).to_object(py),
130 CLRepr::Bool(v) => PyBool::new(py, v).to_object(py),
131 CLRepr::Float(v) => PyFloat::new(py, v).to_object(py),
132 CLRepr::Int(v) => {
133 let py_int: &PyInt = unsafe { py.from_owned_ptr(pyo3::ffi::PyLong_FromLong(v)) };
134
135 py_int.to_object(py)
136 },
137 CLRepr::Array(arr) => {
138 let mut elements = Vec::with_capacity(arr.len());
139
140 for el in arr.into_iter() {
141 elements.push(Self::into_py_impl(el, py)?);
142 }
143
144 PyList::new(py, elements).to_object(py)
145 },
146 CLRepr::Tuple(arr) => {
147 let mut elements = Vec::with_capacity(arr.len());
148
149 for el in arr.into_iter() {
150 elements.push(Self::into_py_impl(el, py)?);
151 }
152
153 PyTuple::new(py, elements).to_object(py)
154 },
155 CLRepr::Object(obj) => {
156 let r = PyDict::new(py);
157
158 for (k, v) in obj.into_iter() {
159 r.set_item(k, Self::into_py_impl(v, py)?)?;
160 }
161
162 r.to_object(py)
163 },
164 CLRepr::Null => py.None(),
165 CLRepr::PythonRef(py_ref) => match py_ref {
166 PythonRef::PyObject(_) =>
167 return Err(PyErr::new::<PyNotImplementedError, _>(
168 "Unable to represent PyObject in Python",
169 )),
170 PythonRef::PyFunction(_) =>
171 return Err(PyErr::new::<PyNotImplementedError, _>(
172 "Unable to represent PyFunction in Python",
173 )),
174 PythonRef::PyExternalFunction(_) =>
175 return Err(PyErr::new::<PyNotImplementedError, _>(
176 "Unable to represent PyExternalFunction in Python",
177 )),
178 },
179 })
180 }
181
182 fn into_py(self, py: Python) -> Result<PyObject, PyErr> {
183 Self::into_py_impl(self, py)
184 }
185}