diff -r 7ec1cfe19a24 -r a4137aedcb3a src/python_access/function.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/python_access/function.rs Thu Feb 26 09:32:12 2026 -0500 @@ -0,0 +1,77 @@ +/*! +Conversions between [`DolfinxPyFunction_f64`] and `dolfinx.fem.Function` in Python. +*/ + +use crate::dolfinx_access::ffi; +use crate::dolfinx_access::DolfinxPyFunction_f64; +use pyo3::conversion::FromPyObject; +use pyo3::exceptions::PyException; +use pyo3::prelude::*; + +macro_rules! py_bail { + ($msg:literal $(,)?) => { + return Err(PyException::new_err(format!($msg))) + }; + ($err:expr $(,)?) => { + return Err(PyException::new_err(format!($err))) + }; + ($fmt:expr, $($arg:tt)*) => { + return Err(PyException::new_err(format!($fmt, $($arg)*))) + }; +} + +impl<'a, 'py, const N: u32, const O: u32, const D: u32> FromPyObject<'a, 'py> + for DolfinxPyFunction_f64<'py, N, O, D> +{ + type Error = PyErr; + + fn extract(u_: Borrowed<'a, 'py, PyAny>) -> PyResult { + // We maintain our reference-counted copy + let u = u_.to_owned(); + // The "_cpp_object" attribute of a Python Dolfinx Function points to the C++ instance + let u_cpp = u.getattr("_cpp_object")?; + let cxx = unsafe { ffi::cast_mut_Function_f64(u_cpp.as_ptr() as *mut ffi::PyObject) } + .or_else(|err| py_bail!("CXX cast error: {}", err))?; + let info = unsafe { ffi::info_Function_f64(cxx) }; + if !info.triangular_mesh { + py_bail!("Triangular mesh required") + } + if info.order < O { + py_bail!("Insufficient order") + } + if info.codomain_dim != D { + py_bail!("Codomain of invalid size") + } + if info.domain_dim != N { + py_bail!("Domain of invalid size") + } + DolfinxPyFunction_f64::new_prechecked(u, cxx) + } +} + +// TODO: should probably use internal mutability to avoid just supporting mut references. +impl<'a, 'py, const N: u32, const O: u32, const D: u32> IntoPyObject<'py> + for &'a mut DolfinxPyFunction_f64<'py, N, O, D> +where + 'py: 'a, +{ + type Target = PyAny; + type Error = PyErr; + type Output = pyo3::Borrowed<'a, 'py, Self::Target>; + + fn into_pyobject(self, py: Python<'py>) -> Result { + self._into_py_ref(py) + } +} + +impl<'py, const N: u32, const O: u32, const D: u32> IntoPyObject<'py> + for DolfinxPyFunction_f64<'py, N, O, D> +{ + type Target = PyAny; + type Error = PyErr; + type Output = pyo3::Bound<'py, Self::Target>; + + fn into_pyobject(self, py: Python<'py>) -> Result { + self._into_py(py) + } +}