src/python_access/function.rs

changeset 1
a4137aedcb3a
--- /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<Self> {
+        // 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::Output, Self::Error> {
+        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::Output, Self::Error> {
+        self._into_py(py)
+    }
+}

mercurial