From 725025e12eaac58255f83ab24491c30c7cc1dfde Mon Sep 17 00:00:00 2001 From: Bas Schoenmaeckers Date: Thu, 21 May 2026 08:45:21 +0200 Subject: [PATCH] Add complex number support to c-api --- Cargo.lock | 1 + crates/capi/Cargo.toml | 1 + crates/capi/src/complexobject.rs | 52 ++++++++++++++++++++++++++++++++ crates/capi/src/lib.rs | 1 + 4 files changed, 55 insertions(+) create mode 100644 crates/capi/src/complexobject.rs diff --git a/Cargo.lock b/Cargo.lock index b1fe77d955..eab7707b5b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3231,6 +3231,7 @@ dependencies = [ name = "rustpython-capi" version = "0.5.0" dependencies = [ + "num-complex", "pyo3", "rustpython-stdlib", "rustpython-vm", diff --git a/crates/capi/Cargo.toml b/crates/capi/Cargo.toml index 85f42934a9..8c54a8b26a 100644 --- a/crates/capi/Cargo.toml +++ b/crates/capi/Cargo.toml @@ -12,6 +12,7 @@ license.workspace = true crate-type = ["cdylib", "rlib"] [dependencies] +num-complex = { workspace = true } rustpython-vm = { workspace = true, features = ["threading", "compiler"] } rustpython-stdlib = {workspace = true, features = ["threading"] } diff --git a/crates/capi/src/complexobject.rs b/crates/capi/src/complexobject.rs new file mode 100644 index 0000000000..a6b2bb731a --- /dev/null +++ b/crates/capi/src/complexobject.rs @@ -0,0 +1,52 @@ +use crate::object::define_py_check; +use crate::{PyObject, pystate::with_vm}; +use core::ffi::c_double; +use num_complex::{Complex, Complex64}; +use rustpython_vm::builtins::PyComplex; +use rustpython_vm::{PyResult, VirtualMachine}; + +define_py_check!(fn PyComplex_Check, types.complex_type); +define_py_check!(exact fn PyComplex_CheckExact, types.complex_type); + +#[unsafe(no_mangle)] +pub extern "C" fn PyComplex_FromDoubles(real: c_double, imag: c_double) -> *mut PyObject { + with_vm(|vm| vm.ctx.new_complex(Complex::new(real, imag))) +} + +fn try_to_complex(vm: &VirtualMachine, obj: &PyObject) -> PyResult { + obj.try_downcast_ref::(vm).map_or_else( + |type_err| { + if let Some((complex, _)) = obj.to_owned().try_complex(vm)? { + Ok(complex) + } else { + Err(type_err) + } + }, + |complex| Ok(complex.to_complex()), + ) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyComplex_RealAsDouble(obj: *mut PyObject) -> c_double { + with_vm(|vm| try_to_complex(vm, unsafe { &*obj }).map(|complex| complex.re)) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyComplex_ImagAsDouble(obj: *mut PyObject) -> c_double { + with_vm(|vm| try_to_complex(vm, unsafe { &*obj }).map(|complex| complex.im)) +} + +#[cfg(false)] +mod tests { + use pyo3::prelude::*; + use pyo3::types::PyComplex; + + #[test] + fn test_py_int() { + Python::attach(|py| { + let number = PyComplex::from_doubles(py, 1.0, 2.0); + assert_eq!(number.real(), 1.0); + assert_eq!(number.imag(), 2.0); + }) + } +} diff --git a/crates/capi/src/lib.rs b/crates/capi/src/lib.rs index baa4ddc6b7..c69a9299fe 100644 --- a/crates/capi/src/lib.rs +++ b/crates/capi/src/lib.rs @@ -12,6 +12,7 @@ pub mod abstract_; pub mod boolobject; pub mod bytesobject; pub mod ceval; +pub mod complexobject; pub mod dictobject; pub mod import; pub mod longobject;