Expand description

miri-checked crates.io docs.rs GitHub

This crate provides a safe idiomatic Rust binding to DLPack which is the standard in-memory, (mostly) hardware agnostic data format, recognized by major Deep Learning frameworks such as PyTorch, TensorFlow, MXNet, TVM and major array processing frameworks such as NumPy and CuPy. An important feature of this standard is to provide zero-cost tensor conversion across frameworks on a particular supported hardware.

The Minimum Supported Rust Version (MSRV) is the stable toolchain 1.57.0.


There are two main cases related to where the owner of the underlying data / storage of a tensor resides and what kind of operations are to be done.

Memory Managed Tensor

In this case, ManagedTensor is built from ManagedTensorProxy which is a safe proxy for the unsafe ffi::DLManagedTensor.

Plain Not-Memory-Managed Tensor

In this case, the (invariant) Rust wrapper Tensor can be used or if needed the unsafe ffi::DLTensor.


When ownership is concerned, one can use the ManagedTensor. Here is an example on how the bi-directional conversion

ndarray::ArrayD <---> ManagedTensor

is done at zero-cost.

impl<'tensor, C> From<&'tensor mut ArrayD<f32>> for ManagedContext<'tensor, C> {
    fn from(t: &'tensor mut ArrayD<f32>) -> Self {
        let dlt: Tensor<'tensor> = Tensor::from(t);
        let inner = DLManagedTensor::new(dlt.0, None);

impl<'tensor, C> From<&mut ManagedContext<'tensor, C>> for ArrayD<f32> {
    fn from(mt: &mut ManagedContext<'tensor, C>) -> Self {
        let dlt: DLTensor = mt.0.inner.dl_tensor.into();
        unsafe {
            let arr = RawArrayViewMut::from_shape_ptr(dlt.shape().unwrap(), dlt.data() as *mut f32);

And when ownership is not concerned, one can use Tensor as a view. Here is an example on how the bi-directional converion

ndarray::ArrayD <---> Tensor

is done at zero-cost.

impl<'tensor> From<&'tensor mut ArrayD<f32>> for Tensor<'tensor> {
    fn from(arr: &'tensor mut ArrayD<f32>) -> Self {
        let inner = DLTensor::new(
            arr.as_mut_ptr() as *mut c_void,
            arr.ndim() as i32,
            arr.shape().as_ptr() as *const _ as *mut i64,
            arr.strides().as_ptr() as *const _ as *mut i64,

impl<'tensor> From<&'tensor mut Tensor<'tensor>> for ArrayD<f32> {
    fn from(t: &'tensor mut Tensor<'tensor>) -> Self {
        unsafe {
            let arr = RawArrayViewMut::from_shape_ptr(t.0.shape().unwrap(), t.0.data() as *mut f32);

See the complete examples/sample where the above cases have been simulated for the Rust ndarray conversion.


pub use datatype::DataType;
pub use datatype::DataTypeCode;
pub use device::Device;
pub use device::DeviceType;
pub use tensor::ManagedTensor;
pub use tensor::ManagedTensorProxy;
pub use tensor::ManagerContext;
pub use tensor::Tensor;