1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 // See Notices.txt for copyright information
4 #![cfg(feature = "python")]
6 use crate::{ConditionRegister, Instr, InstructionInput, InstructionResult, OverflowFlags};
7 use pyo3::{prelude::*, wrap_pyfunction, PyObjectProtocol};
8 use std::{borrow::Cow, cell::RefCell, fmt};
11 fn to_python_repr(&self) -> Cow<str> {
12 struct Helper<T>(RefCell<Option<T>>);
14 impl<T: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result> fmt::Display for Helper<T> {
15 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16 self.0.borrow_mut().take().unwrap()(f)
20 impl<T: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result> Helper<T> {
21 fn new(f: T) -> Self {
22 Helper(RefCell::new(Some(f)))
27 Helper::new(|f: &mut fmt::Formatter<'_>| -> fmt::Result { self.write(f) })
30 fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 f.write_str(&self.to_python_repr())
35 fn write_list_body_to_python_repr<I: IntoIterator<Item = T>, T: ToPythonRepr>(
37 f: &mut fmt::Formatter<'_>,
45 f.write_str(separator)?;
52 struct NamedArgPythonRepr<'a> {
54 value: &'a (dyn ToPythonRepr + 'a),
57 impl ToPythonRepr for NamedArgPythonRepr<'_> {
58 fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59 f.write_str(self.name)?;
65 impl<T: ToPythonRepr> ToPythonRepr for &'_ T {
66 fn to_python_repr(&self) -> Cow<str> {
67 (**self).to_python_repr()
69 fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74 impl ToPythonRepr for bool {
75 fn to_python_repr(&self) -> Cow<str> {
76 Cow::Borrowed(match self {
83 impl<T: ToPythonRepr> ToPythonRepr for Option<T> {
84 fn to_python_repr(&self) -> Cow<str> {
86 Some(v) => v.to_python_repr(),
87 None => Cow::Borrowed("None"),
90 fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92 Some(v) => v.write(f),
93 None => f.write_str("None"),
98 impl<T: ToPythonRepr> ToPythonRepr for Vec<T> {
99 fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 write_list_body_to_python_repr(self, f, ", ")?;
106 macro_rules! impl_int_to_python_repr {
107 ($($int:ident,)*) => {
109 impl ToPythonRepr for $int {
110 fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111 write!(f, "{}", self)
118 impl_int_to_python_repr! {u8, u16, u32, u64, u128, i8, i16, i32, i64, i128,}
120 macro_rules! wrap_type {
123 // use tt to work around PyO3 bug fixed in PyO3#832
124 #[pyclass $($pyclass_args:tt)?]
125 #[wrapped($value:ident: $wrapped:ident)]
128 struct $wrapper:ident {
130 #[set=$setter_name:ident]
131 $(#[$field_meta:meta])*
132 $field_name:ident:$field_type:ty,
136 #[pyclass $($pyclass_args)?]
143 impl<'source> FromPyObject<'source> for $wrapped {
144 fn extract(ob: &'source PyAny) -> PyResult<Self> {
145 Ok(ob.extract::<$wrapper>()?.$value)
149 impl IntoPy<PyObject> for $wrapped {
150 fn into_py(self, py: Python) -> PyObject {
151 $wrapper { $value: self }.into_py(py)
159 fn new($($field_name:$field_type),*) -> Self {
168 $(#[$field_meta:meta])*
169 fn $field_name(&self) -> $field_type {
170 self.$value.$field_name
173 fn $setter_name(&mut self, $field_name: $field_type) {
174 self.$value.$field_name = $field_name;
179 impl ToPythonRepr for $wrapped {
180 fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181 f.write_str(concat!(stringify!($wrapped), "("))?;
182 write_list_body_to_python_repr(&[
185 name: stringify!($field_name),
186 value: &self.$field_name,
195 impl PyObjectProtocol for $wrapper {
196 fn __str__(&self) -> String {
197 serde_json::to_string(&self.$value).unwrap()
199 fn __repr__(&self) -> String {
200 self.$value.to_python_repr().into_owned()
204 $m.add_class::<$wrapper>()?;
208 macro_rules! wrap_instr_fns {
210 #![pymodule($m:ident)]
212 // use tt to work around PyO3 bug fixed in PyO3#832
213 $(#[pyfunction $pyfunction_args:tt])?
215 fn $name:ident(inputs: $inputs:ty) -> $result:ty;
220 #[pyfunction $($pyfunction_args)?]
221 #[text_signature = "(inputs)"]
223 fn $name(inputs: $inputs) -> $result {
224 $crate::instr_models::$name(inputs)
227 $m.add_wrapped(wrap_pyfunction!($name))?;
234 fn power_instruction_analyzer(_py: Python, m: &PyModule) -> PyResult<()> {
237 #[pyclass(name = OverflowFlags)]
238 #[wrapped(value: OverflowFlags)]
239 #[args(so, ov, ov32)]
240 #[text_signature = "(so, ov, ov32)"]
241 struct PyOverflowFlags {
253 #[pyclass(name = ConditionRegister)]
254 #[wrapped(value: ConditionRegister)]
255 #[args(lt, gt, eq, so)]
256 #[text_signature = "(lt, gt, eq, so)"]
257 struct PyConditionRegister {
271 #[pyclass(name = InstructionInput)]
272 #[wrapped(value: InstructionInput)]
274 #[text_signature = "(ra, rb, rc)"]
275 struct PyInstructionInput {
287 #[pyclass(name = InstructionResult)]
288 #[wrapped(value: InstructionResult)]
301 #[text_signature = "(\
313 struct PyInstructionResult {
316 #[set = set_overflow]
317 overflow: Option<OverflowFlags>,
319 cr0: Option<ConditionRegister>,
321 cr1: Option<ConditionRegister>,
323 cr2: Option<ConditionRegister>,
325 cr3: Option<ConditionRegister>,
327 cr4: Option<ConditionRegister>,
329 cr5: Option<ConditionRegister>,
331 cr6: Option<ConditionRegister>,
333 cr7: Option<ConditionRegister>,
341 .map(|&instr| instr.name())
342 .collect::<Vec<_>>(),
345 wrap_all_instr_fns!(m);