1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 // See Notices.txt for copyright information
4 #![cfg(feature = "python")]
7 CarryFlags, ConditionRegister, Instr, InstructionInput, InstructionOutput, OverflowFlags,
9 use pyo3::{exceptions::ValueError, prelude::*, wrap_pyfunction, PyObjectProtocol};
10 use std::{borrow::Cow, cell::RefCell, fmt};
13 fn to_python_repr(&self) -> Cow<str> {
14 struct Helper<T>(RefCell<Option<T>>);
16 impl<T: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result> fmt::Display for Helper<T> {
17 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
18 self.0.borrow_mut().take().unwrap()(f)
22 impl<T: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result> Helper<T> {
23 fn new(f: T) -> Self {
24 Helper(RefCell::new(Some(f)))
29 Helper::new(|f: &mut fmt::Formatter<'_>| -> fmt::Result { self.write(f) })
32 fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 f.write_str(&self.to_python_repr())
37 fn write_list_body_to_python_repr<I: IntoIterator<Item = T>, T: ToPythonRepr>(
39 f: &mut fmt::Formatter<'_>,
47 f.write_str(separator)?;
54 struct NamedArgPythonRepr<'a> {
56 value: &'a (dyn ToPythonRepr + 'a),
59 impl ToPythonRepr for NamedArgPythonRepr<'_> {
60 fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 f.write_str(self.name)?;
67 impl<T: ToPythonRepr> ToPythonRepr for &'_ T {
68 fn to_python_repr(&self) -> Cow<str> {
69 (**self).to_python_repr()
71 fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76 impl ToPythonRepr for bool {
77 fn to_python_repr(&self) -> Cow<str> {
78 Cow::Borrowed(match self {
85 impl<T: ToPythonRepr> ToPythonRepr for Option<T> {
86 fn to_python_repr(&self) -> Cow<str> {
88 Some(v) => v.to_python_repr(),
89 None => Cow::Borrowed("None"),
92 fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94 Some(v) => v.write(f),
95 None => f.write_str("None"),
100 impl<T: ToPythonRepr> ToPythonRepr for Vec<T> {
101 fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103 write_list_body_to_python_repr(self, f, ", ")?;
108 macro_rules! impl_int_to_python_repr {
109 ($($int:ident,)*) => {
111 impl ToPythonRepr for $int {
112 fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113 write!(f, "{}", self)
120 impl_int_to_python_repr! {u8, u16, u32, u64, u128, i8, i16, i32, i64, i128,}
122 macro_rules! wrap_type {
125 // use tt to work around PyO3 bug fixed in PyO3#832
126 #[pyclass $($pyclass_args:tt)?]
127 #[wrapped($value:ident: $wrapped:ident)]
130 struct $wrapper:ident {
132 #[set=$setter_name:ident]
133 $(#[$field_meta:meta])*
134 $field_name:ident:$field_type:ty,
138 #[pyclass $($pyclass_args)?]
145 impl<'source> FromPyObject<'source> for $wrapped {
146 fn extract(ob: &'source PyAny) -> PyResult<Self> {
147 Ok(ob.extract::<$wrapper>()?.$value)
151 impl IntoPy<PyObject> for $wrapped {
152 fn into_py(self, py: Python) -> PyObject {
153 $wrapper { $value: self }.into_py(py)
161 fn new($($field_name:$field_type),*) -> Self {
170 $(#[$field_meta:meta])*
171 fn $field_name(&self) -> $field_type {
172 self.$value.$field_name
175 fn $setter_name(&mut self, $field_name: $field_type) {
176 self.$value.$field_name = $field_name;
181 impl ToPythonRepr for $wrapped {
182 fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183 f.write_str(concat!(stringify!($wrapped), "("))?;
184 write_list_body_to_python_repr(&[
187 name: stringify!($field_name),
188 value: &self.$field_name,
197 impl PyObjectProtocol for $wrapper {
198 fn __str__(&self) -> String {
199 serde_json::to_string(&self.$value).unwrap()
201 fn __repr__(&self) -> String {
202 self.$value.to_python_repr().into_owned()
206 $m.add_class::<$wrapper>()?;
210 macro_rules! wrap_instr_fns {
212 #![pymodule($m:ident)]
214 // use tt to work around PyO3 bug fixed in PyO3#832
215 $(#[pyfunction $pyfunction_args:tt])?
217 fn $name:ident(inputs: $inputs:ty) -> $result:ty;
222 #[pyfunction $($pyfunction_args)?]
223 #[text_signature = "(inputs)"]
225 fn $name(inputs: $inputs) -> PyResult<InstructionOutput> {
226 $crate::instr_models::$name(inputs)
227 .map_err(|err| ValueError::py_err(err.to_string()))
230 $m.add_wrapped(wrap_pyfunction!($name))?;
237 fn power_instruction_analyzer(_py: Python, m: &PyModule) -> PyResult<()> {
240 #[pyclass(name = OverflowFlags)]
241 #[wrapped(value: OverflowFlags)]
242 #[args(so, ov, ov32)]
243 #[text_signature = "(so, ov, ov32)"]
244 struct PyOverflowFlags {
256 #[pyclass(name = CarryFlags)]
257 #[wrapped(value: CarryFlags)]
259 #[text_signature = "(ca, ca32)"]
260 struct PyCarryFlags {
270 #[pyclass(name = ConditionRegister)]
271 #[wrapped(value: ConditionRegister)]
272 #[args(lt, gt, eq, so)]
273 #[text_signature = "(lt, gt, eq, so)"]
274 struct PyConditionRegister {
288 #[pyclass(name = InstructionInput)]
289 #[wrapped(value: InstructionInput)]
290 #[args(ra="None", rb="None", rc="None", carry="None", overflow="None")]
291 #[text_signature = "(ra, rb, rc, carry, overflow)"]
292 struct PyInstructionInput {
300 carry: Option<CarryFlags>,
301 #[set = set_overflow]
302 overflow: Option<OverflowFlags>,
308 #[pyclass(name = InstructionOutput)]
309 #[wrapped(value: InstructionOutput)]
323 #[text_signature = "(\
336 struct PyInstructionOutput {
339 #[set = set_overflow]
340 overflow: Option<OverflowFlags>,
342 carry: Option<CarryFlags>,
344 cr0: Option<ConditionRegister>,
346 cr1: Option<ConditionRegister>,
348 cr2: Option<ConditionRegister>,
350 cr3: Option<ConditionRegister>,
352 cr4: Option<ConditionRegister>,
354 cr5: Option<ConditionRegister>,
356 cr6: Option<ConditionRegister>,
358 cr7: Option<ConditionRegister>,
366 .map(|&instr| instr.name())
367 .collect::<Vec<_>>(),
370 wrap_all_instr_fns!(m);