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,
10 exceptions::{IndexError, OverflowError, ValueError},
12 wrap_pyfunction, PyObjectProtocol,
14 use std::{borrow::Cow, cell::RefCell, fmt};
17 fn to_python_repr(&self) -> Cow<str> {
18 struct Helper<T>(RefCell<Option<T>>);
20 impl<T: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result> fmt::Display for Helper<T> {
21 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22 self.0.borrow_mut().take().unwrap()(f)
26 impl<T: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result> Helper<T> {
27 fn new(f: T) -> Self {
28 Helper(RefCell::new(Some(f)))
33 Helper::new(|f: &mut fmt::Formatter<'_>| -> fmt::Result { self.write(f) })
36 fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 f.write_str(&self.to_python_repr())
41 fn write_list_body_to_python_repr<I: IntoIterator<Item = T>, T: ToPythonRepr>(
43 f: &mut fmt::Formatter<'_>,
51 f.write_str(separator)?;
58 struct NamedArgPythonRepr<'a> {
60 value: &'a (dyn ToPythonRepr + 'a),
63 impl ToPythonRepr for NamedArgPythonRepr<'_> {
64 fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65 f.write_str(self.name)?;
71 impl<T: ToPythonRepr> ToPythonRepr for &'_ T {
72 fn to_python_repr(&self) -> Cow<str> {
73 (**self).to_python_repr()
75 fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 impl ToPythonRepr for bool {
81 fn to_python_repr(&self) -> Cow<str> {
82 Cow::Borrowed(match self {
89 impl<T: ToPythonRepr> ToPythonRepr for Option<T> {
90 fn to_python_repr(&self) -> Cow<str> {
92 Some(v) => v.to_python_repr(),
93 None => Cow::Borrowed("None"),
96 fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98 Some(v) => v.write(f),
99 None => f.write_str("None"),
104 impl<T: ToPythonRepr> ToPythonRepr for Vec<T> {
105 fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107 write_list_body_to_python_repr(self, f, ", ")?;
112 macro_rules! impl_int_to_python_repr {
113 ($($int:ident,)*) => {
115 impl ToPythonRepr for $int {
116 fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117 write!(f, "{}", self)
124 impl_int_to_python_repr! {u8, u16, u32, u64, u128, i8, i16, i32, i64, i128,}
126 macro_rules! wrap_type {
129 // use tt to work around PyO3 bug fixed in PyO3#832
130 #[pyclass $($pyclass_args:tt)?]
131 #[wrapped($value:ident: $wrapped:ident)]
134 struct $wrapper:ident {
136 #[set=$setter_name:ident]
137 $(#[$field_meta:meta])*
138 $field_name:ident:$field_type:ty,
142 #[pyclass $($pyclass_args)?]
149 impl<'source> FromPyObject<'source> for $wrapped {
150 fn extract(ob: &'source PyAny) -> PyResult<Self> {
151 Ok(ob.extract::<$wrapper>()?.$value)
155 impl IntoPy<PyObject> for $wrapped {
156 fn into_py(self, py: Python) -> PyObject {
157 $wrapper { $value: self }.into_py(py)
165 fn new($($field_name:$field_type),*) -> Self {
174 $(#[$field_meta:meta])*
175 fn $field_name(&self) -> $field_type {
176 self.$value.$field_name
179 fn $setter_name(&mut self, $field_name: $field_type) {
180 self.$value.$field_name = $field_name;
185 impl ToPythonRepr for $wrapped {
186 fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187 f.write_str(concat!(stringify!($wrapped), "("))?;
188 write_list_body_to_python_repr(&[
191 name: stringify!($field_name),
192 value: &self.$field_name,
201 impl PyObjectProtocol for $wrapper {
202 fn __str__(&self) -> String {
203 serde_json::to_string(&self.$value).unwrap()
205 fn __repr__(&self) -> String {
206 self.$value.to_python_repr().into_owned()
210 $m.add_class::<$wrapper>()?;
214 macro_rules! wrap_instr_fns {
216 #![pymodule($m:ident)]
218 // use tt to work around PyO3 bug fixed in PyO3#832
219 $(#[pyfunction $pyfunction_args:tt])?
221 fn $name:ident(inputs: $inputs:ty) -> $result:ty;
226 #[pyfunction $($pyfunction_args)?]
227 #[text_signature = "(inputs)"]
229 fn $name(inputs: $inputs) -> PyResult<InstructionOutput> {
230 $crate::instr_models::$name(inputs)
231 .map_err(|err| ValueError::py_err(err.to_string()))
234 $m.add_wrapped(wrap_pyfunction!($name))?;
241 fn power_instruction_analyzer(_py: Python, m: &PyModule) -> PyResult<()> {
244 #[pyclass(name = OverflowFlags)]
245 #[wrapped(value: OverflowFlags)]
246 #[args(so, ov, ov32)]
247 #[text_signature = "(so, ov, ov32)"]
248 struct PyOverflowFlags {
259 impl PyOverflowFlags {
260 #[text_signature = "(xer)"]
262 pub fn from_xer(xer: u64) -> OverflowFlags {
263 OverflowFlags::from_xer(xer)
265 #[text_signature = "($self)"]
266 pub fn to_xer(&self) -> u64 {
273 #[pyclass(name = CarryFlags)]
274 #[wrapped(value: CarryFlags)]
276 #[text_signature = "(ca, ca32)"]
277 struct PyCarryFlags {
287 #[text_signature = "(xer)"]
289 pub fn from_xer(xer: u64) -> CarryFlags {
290 CarryFlags::from_xer(xer)
292 #[text_signature = "($self)"]
293 pub fn to_xer(&self) -> u64 {
300 #[pyclass(name = ConditionRegister)]
301 #[wrapped(value: ConditionRegister)]
302 #[args(lt, gt, eq, so)]
303 #[text_signature = "(lt, gt, eq, so)"]
304 struct PyConditionRegister {
317 impl PyConditionRegister {
318 #[text_signature = "(bits)"]
320 fn from_4_bits(bits: u8) -> PyResult<ConditionRegister> {
322 OverflowError::into("int too big to convert")?;
324 Ok(ConditionRegister::from_4_bits(bits))
326 #[text_signature = "(cr, field_index)"]
328 fn from_cr_field(cr: u32, mut field_index: isize) -> PyResult<ConditionRegister> {
329 // adjust for python-style indexes
331 field_index += ConditionRegister::CR_FIELD_COUNT as isize;
333 if field_index < 0 || field_index >= ConditionRegister::CR_FIELD_COUNT as isize {
334 IndexError::into("field_index out of range")?;
336 Ok(ConditionRegister::from_cr_field(cr, field_index as usize))
342 #[pyclass(name = InstructionInput)]
343 #[wrapped(value: InstructionInput)]
344 #[args(ra="None", rb="None", rc="None", immediate="None", carry="None", overflow="None")]
345 #[text_signature = "(ra=None, rb=None, rc=None, immediate=None, carry=None, overflow=None)"]
346 struct PyInstructionInput {
353 #[set = set_immediate]
354 immediate: Option<u64>,
356 carry: Option<CarryFlags>,
357 #[set = set_overflow]
358 overflow: Option<OverflowFlags>,
364 #[pyclass(name = InstructionOutput)]
365 #[wrapped(value: InstructionOutput)]
379 #[text_signature = "(\
392 struct PyInstructionOutput {
395 #[set = set_overflow]
396 overflow: Option<OverflowFlags>,
398 carry: Option<CarryFlags>,
400 cr0: Option<ConditionRegister>,
402 cr1: Option<ConditionRegister>,
404 cr2: Option<ConditionRegister>,
406 cr3: Option<ConditionRegister>,
408 cr4: Option<ConditionRegister>,
410 cr5: Option<ConditionRegister>,
412 cr6: Option<ConditionRegister>,
414 cr7: Option<ConditionRegister>,
422 .map(|&instr| instr.name())
423 .collect::<Vec<_>>(),
426 wrap_all_instr_fns!(m);