#![cfg(feature = "num-complex")]
#![cfg_attr(docsrs, doc(cfg(feature = "num-complex")))]
#![cfg_attr(docsrs, cfg_attr(docsrs, doc = concat!("pyo3 = { version = \"", env!("CARGO_PKG_VERSION"), "\", features = [\"num-complex\"] }")))]
#![cfg_attr(
not(docsrs),
doc = "pyo3 = { version = \"*\", features = [\"num-complex\"] }"
)]
use crate::{
ffi, types::PyComplex, AsPyPointer, FromPyObject, PyAny, PyErr, PyNativeType, PyObject,
PyResult, Python, ToPyObject,
};
use num_complex::Complex;
use std::os::raw::c_double;
impl PyComplex {
pub fn from_complex<F: Into<c_double>>(py: Python, complex: Complex<F>) -> &PyComplex {
unsafe {
let ptr = ffi::PyComplex_FromDoubles(complex.re.into(), complex.im.into());
py.from_owned_ptr(ptr)
}
}
}
macro_rules! complex_conversion {
($float: ty) => {
impl ToPyObject for Complex<$float> {
#[inline]
fn to_object(&self, py: Python) -> PyObject {
crate::IntoPy::<PyObject>::into_py(self.to_owned(), py)
}
}
impl crate::IntoPy<PyObject> for Complex<$float> {
fn into_py(self, py: Python) -> PyObject {
unsafe {
let raw_obj =
ffi::PyComplex_FromDoubles(self.re as c_double, self.im as c_double);
PyObject::from_owned_ptr(py, raw_obj)
}
}
}
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
#[allow(clippy::float_cmp)] impl<'source> FromPyObject<'source> for Complex<$float> {
fn extract(obj: &'source PyAny) -> PyResult<Complex<$float>> {
unsafe {
let val = ffi::PyComplex_AsCComplex(obj.as_ptr());
if val.real == -1.0 && PyErr::occurred(obj.py()) {
Err(PyErr::fetch(obj.py()))
} else {
Ok(Complex::new(val.real as $float, val.imag as $float))
}
}
}
}
#[cfg(any(Py_LIMITED_API, PyPy))]
#[allow(clippy::float_cmp)] impl<'source> FromPyObject<'source> for Complex<$float> {
fn extract(obj: &'source PyAny) -> PyResult<Complex<$float>> {
unsafe {
let ptr = obj.as_ptr();
let real = ffi::PyComplex_RealAsDouble(ptr);
if real == -1.0 && PyErr::occurred(obj.py()) {
return Err(PyErr::fetch(obj.py()));
}
let imag = ffi::PyComplex_ImagAsDouble(ptr);
Ok(Complex::new(real as $float, imag as $float))
}
}
}
};
}
complex_conversion!(f32);
complex_conversion!(f64);
#[cfg(test)]
mod tests {
use super::*;
#[allow(clippy::float_cmp)] #[test]
fn from_complex() {
Python::with_gil(|py| {
let complex = Complex::new(3.0, 1.2);
let py_c = PyComplex::from_complex(py, complex);
assert_eq!(py_c.real(), 3.0);
assert_eq!(py_c.imag(), 1.2);
});
}
#[test]
fn to_from_complex() {
Python::with_gil(|py| {
let val = Complex::new(3.0, 1.2);
let obj = val.to_object(py);
assert_eq!(obj.extract::<Complex<f64>>(py).unwrap(), val);
});
}
#[test]
fn from_complex_err() {
Python::with_gil(|py| {
let obj = vec![1].to_object(py);
assert!(obj.extract::<Complex<f64>>(py).is_err());
});
}
}