dlpark
A pure Rust implementation of dmlc/dlpack.
This implementation focuses on transferring tensors between Rust and Python, and between Rust tensor/array libraries, without copying.
What is DLPack?
DLPack is a common in-memory tensor structure that enables sharing tensor data between different deep learning frameworks. It provides a standardized way to exchange tensor data without copying, making it efficient for framework interoperability.
Key features of DLPack:
- Zero-copy tensor sharing between frameworks
- Support for various data types and devices (CPU, GPU, etc.)
- Memory management through deleter functions
- Versioned ABI for compatibility
Implementation Details
Versioning
The library implements both legacy and versioned DLPack structures:
legacy::Dlpack: Legacy managed tensor capsule supportversioned::Dlpack: Versioned managed tensor capsule support with:- Major version: 1
- Minor version: 3
- Additional flags for tensor properties (read-only, copied, sub-byte type padding)
Safe Abstractions
The library provides a Rust ownership wrapper over the C-style DLPack structures, ManagedBox<M>:
- RAII wrapper around a raw managed
DLPacktensor pointer - Automatic cleanup through the DLPack deleter function on drop
legacy::Dlpackandversioned::Dlpackare convenience aliases forManagedBox<DLManagedTensor>andManagedBox<DLManagedTensorVersioned>— the two concrete forms you'll actually use
Other key features:
- Memory safety through Rust's ownership system
- Support for
imagebuffers, ndarray, and candle tensors, plus raw DLPack tensor layouts - Python interoperability through PyO3
- Optional DLPack 1.3 C Exchange API fast path when a producer type exposes
__dlpack_c_exchange_api__
Choosing Builder Metadata
Builder<C, L> uses the metadata type L to select its allocation strategy:
CopiedArray<S, T, N>— fixed rank known at compile time. Shape and strides are copied into the managed tensor allocation.buildandbuild_raware infallible.CopiedSlice<S, T>— dynamic rank. The containers may be borrowed slices or owned values such asVec<i64>. Usetry_buildortry_build_raw.BorrowedArray<N>— fixed-rank, zero-copy metadata. Itsbuildmethods are unsafe because the arrays must outlive the managed tensor.BorrowedSlice— dynamic-rank, zero-copy metadata. Itstry_buildmethods are unsafe for the same lifetime reason.
Copied metadata and the managed tensor share one allocation. Borrowed metadata only allocates the managed tensor header.
Python Exchange Paths
The pyo3 feature supports the standard Python DLPack capsule protocol:
legacy::Dlpackconsumes or produces legacy"dltensor"capsules.versioned::Dlpackconsumes or produces"dltensor_versioned"capsules.- When extracting a versioned tensor from a Python object, dlpark first checks the object's type for a
__dlpack_c_exchange_api__PyCapsule named"dlpack_exchange_api". If present, it uses the DLPack C Exchange API no-sync function table. Otherwise it falls back toobj.__dlpack__(max_version=(1, 3)), and then to no-argobj.__dlpack__()for older producers.
The C Exchange API is intended for extension/library use where the consumer can borrow tensors and coordinate work on the producer's current stream. It is not a replacement for the normal __dlpack__ ingestion path.
Features
| Feature | Description | Status |
|---|---|---|
pyo3 |
Python interop via pyo3 (capsule protocol + DLPack C Exchange API fast path) | ✅ |
image |
Zero-copy conversion with image buffers | ✅ |
ndarray |
Zero-copy conversion with ndarray arrays/views | ✅ |
half |
f16/bf16 element type support (via half) |
✅ |
candle |
Conversion with candle Tensor — CPU only; candle's CUDA backend needs separate integration work |
✅ |
cudarc |
Zero-copy conversion with cudarc CudaSlice<T> — no automated tests here, needs a CUDA-capable device to exercise |
✅ |
Quick Start
Two runnable examples:
examples/dlparkimg— a Python extension module (viapyo3) transferringimage::RgbImageto/from Python (e.g.torch.Tensor).examples/ndarray-candle— a plain binary round-tripping data through DLPack:ndarray::Array2→legacy::Dlpack→candle::Tensor→legacy::Dlpack→ndarrayview, run withcargo run -p ndarray-candle.
Usage Examples
Converting between Rust and Python
use legacy;
use *;
// Rust to Python
// Python to Rust
Image Processing
use legacy;
use ;
let img = from_vec?;
let tensor = from;
let img2 = try_from?;
ndarray
use legacy;
use ;
let array = arr2;
let tensor = try_from?;
let view = try_from?;
assert_eq!;
let dynamic: = arr2.into_dyn;
let dynamic_tensor = try_from?;
candle
Zero-copy from candle::Tensor to DLPack; the reverse direction (DLPack to candle::Tensor) always copies, since candle has no borrowed CPU tensor type.
use Tensor;
use ;
let tensor = new?;
let dlpack = try_from?;
let tensor2 = try_from?;
assert_eq!;
let tensor = new?;
let builder = try_from?;
let dlpack = builder
.flags
.?;
cudarc
Zero-copy in both directions between a cudarc CudaSlice<T> and a DLPack tensor. from_cuda_slice/from_cuda_slice_versioned take shape/strides explicitly (not derivable from a flat device buffer alone); the reverse direction consumes the managed tensor through TryFrom<ManagedBox<M>> for BorrowedCudaSlice<M, T>, keeping it alive for as long as the CUDA view exists.
use ;
let dlpack = from_cuda_slice?;
let borrowed = try_from?;