use std::ffi::CStr;
use pyo3::exceptions::PyNotImplementedError;
use pyo3::prelude::*;
use pyo3::types::{PyCapsule, PyCapsuleMethods};
const DLTENSOR_NAME: &CStr = c"dltensor";
#[pyfunction]
pub fn from_dlpack(_py: Python<'_>, capsule: &Bound<'_, PyAny>) -> PyResult<Py<PyAny>> {
let cap = capsule.cast::<PyCapsule>().map_err(|_| {
PyNotImplementedError::new_err(
"from_dlpack: argument must be a PyCapsule (the result of tensor.__dlpack__()). \
Got a non-capsule object instead.",
)
})?;
let name_opt = cap.name().map_err(|e| {
PyNotImplementedError::new_err(format!("from_dlpack: could not read capsule name: {e}"))
})?;
let name_matches = match name_opt {
None => false,
Some(cn) => {
let name_cstr = unsafe { cn.as_cstr() };
name_cstr == DLTENSOR_NAME
}
};
if !name_matches {
return Err(PyNotImplementedError::new_err(
"from_dlpack: expected a PyCapsule named 'dltensor'. \
Pass the result of tensor.__dlpack__() directly.",
));
}
Err(PyNotImplementedError::new_err(
"from_dlpack: zero-copy CPU path will be enabled in a future release. \
Use numpy.from_dlpack(tensor) and pass the result to scirs2 functions instead. \
See scirs2_numpy::array_from_dlpack_f32 for the Rust-side DLTensor API.",
))
}
#[pyfunction]
pub fn to_dlpack(_py: Python<'_>, array: &Bound<'_, PyAny>) -> PyResult<Py<PyAny>> {
let _ = array;
Err(PyNotImplementedError::new_err(
"to_dlpack: creates a PyCapsule('dltensor') wrapping the array data pointer. \
This path will be enabled once the DLTensor ABI bridge is wired into scirs2-numpy. \
For now, use numpy arrays directly — they are already DLPack-compatible via \
numpy.from_dlpack / numpy.to_dlpack.",
))
}
pub fn register_dlpack_module(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(from_dlpack, m)?)?;
m.add_function(wrap_pyfunction!(to_dlpack, m)?)?;
Ok(())
}
#[cfg(test)]
mod tests {
#[test]
fn dlpack_module_symbol_exists() {
let _msg = "dlpack module compiled successfully";
}
}