Skip to content

Commit 44549d4

Browse files
authored
Add support for ArcArray as well (#20)
1 parent 98b0916 commit 44549d4

1 file changed

Lines changed: 128 additions & 1 deletion

File tree

src/ndarray.rs

Lines changed: 128 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@
44
//! The following conversions are supported:
55
//!
66
//! - `DLPackTensor` => `ndarray::Array` (makes a copy of the data)
7+
//! - `DLPackTensor` => `ndarray::ArcArray` (makes a copy of the data)
78
//! - `DLPackTensorRef` => `ndarray::ArrayView`
89
//! - `DLPackTensorRefMut` => `ndarray::ArrayViewMut`
910
//! - `ndarray::Array` => `DLPackTensor`
1011
//! - `&ndarray::Array` => `DLPackTensorRef`
1112
//! - `&mut ndarray::Array` => `DLPackTensorRefMut`
1213
//! - `ndarray::ArrayView` => `DLPackTensorRef`
1314
//! - `ndarray::ArrayViewMut` => `DLPackTensorRefMut`
15+
//! - `ndarray::ArcArray` => `DLPackTensor` (share data)
16+
//! - `&ndarray::ArcArray` => `DLPackTensorRef`
1417
//!
1518
//! # Examples
1619
//!
@@ -35,7 +38,8 @@
3538
//! let tensor_ref: DLPackTensorRef = (&array).try_into().unwrap();
3639
//! ```
3740
38-
use ndarray::{Array, Dimension, ShapeBuilder};
41+
use std::ffi::c_void;
42+
use ndarray::{Array, ArcArray, Dimension, ShapeBuilder};
3943

4044
use crate::data_types::{CastError, DLPackPointerCast, GetDLPackDataType};
4145
use crate::sys;
@@ -181,6 +185,22 @@ where
181185
}
182186
}
183187

188+
/// This implementation provides a conversion from a DLPack `DLPackTensor` to an
189+
/// `ndarray::ArcArray`.
190+
///
191+
/// **Note:** This conversion makes a copy of the underlying tensor data.
192+
impl<T, D> TryFrom<DLPackTensor> for ArcArray<T, D>
193+
where
194+
D: Dimension + DimFromVec + 'static,
195+
T: DLPackPointerCast + Clone + 'static,
196+
{
197+
type Error = DLPackNDarrayError;
198+
199+
fn try_from(tensor: DLPackTensor) -> Result<Self, Self::Error> {
200+
let array: Array<T, D> = tensor.try_into()?;
201+
Ok(array.into())
202+
}
203+
}
184204

185205
/*****************************************************************************/
186206
/* ndarray => DLPack */
@@ -277,6 +297,22 @@ impl<'a, T, D> TryFrom<&'a ndarray::Array<T, D>> for DLPackTensorRef<'a> where
277297
}
278298
}
279299

300+
impl<'a, T, D> TryFrom<&'a ArcArray<T, D>> for DLPackTensorRef<'a> where
301+
D: ndarray::Dimension,
302+
T: GetDLPackDataType,
303+
{
304+
type Error = DLPackNDarrayError;
305+
306+
fn try_from(array: &'a ArcArray<T, D>) -> Result<Self, Self::Error> {
307+
let tensor = array_to_tensor_view(array)?;
308+
309+
return Ok(unsafe {
310+
// SAFETY: we are constraining the lifetime of the return value
311+
DLPackTensorRef::from_raw(tensor)
312+
});
313+
}
314+
}
315+
280316
impl<'a, T, D> TryFrom<&'a mut ndarray::Array<T, D>> for DLPackTensorRefMut<'a> where
281317
D: ndarray::Dimension,
282318
T: GetDLPackDataType,
@@ -388,11 +424,65 @@ where
388424
}
389425
}
390426

427+
/// Convert a shared `ArcArray` into a `DLPackTensor`.
428+
/// This is ZERO-COPY: it increments the reference count of the data.
429+
impl<'a, T, D> TryFrom<&'a ArcArray<T, D>> for DLPackTensor
430+
where
431+
D: Dimension,
432+
T: GetDLPackDataType + 'static + Clone,
433+
{
434+
type Error = DLPackNDarrayError;
435+
436+
fn try_from(array: &'a ArcArray<T, D>) -> Result<Self, Self::Error> {
437+
let shared_view = array.clone();
438+
439+
let shape: Vec<i64> = shared_view.shape().iter().map(|&s| s as i64).collect();
440+
let strides: Vec<i64> = shared_view.strides().iter().map(|&s| s as i64).collect();
441+
let ndim = shape.len() as i32;
442+
443+
let mut ctx = Box::new(ManagerContext {
444+
_array: shared_view,
445+
shape,
446+
strides,
447+
});
448+
449+
let data_ptr = ctx._array.as_ptr() as *mut c_void;
450+
let shape_ptr = ctx.shape.as_mut_ptr();
451+
let strides_ptr = ctx.strides.as_mut_ptr();
452+
453+
let dl_tensor = sys::DLTensor {
454+
data: data_ptr,
455+
device: sys::DLDevice {
456+
device_type: sys::DLDeviceType::kDLCPU,
457+
device_id: 0,
458+
},
459+
ndim,
460+
dtype: T::get_dlpack_data_type(),
461+
shape: shape_ptr,
462+
strides: strides_ptr,
463+
byte_offset: 0,
464+
};
465+
466+
let managed_tensor = sys::DLManagedTensorVersioned {
467+
version: sys::DLPackVersion::current(),
468+
manager_ctx: Box::into_raw(ctx) as *mut _,
469+
deleter: Some(deleter_fn::<ArcArray<T, D>>),
470+
flags: 0,
471+
dl_tensor,
472+
};
473+
474+
unsafe {
475+
Ok(DLPackTensor::from_raw(managed_tensor))
476+
}
477+
}
478+
}
479+
391480
#[cfg(test)]
392481
mod tests {
393482
use super::*;
394483
use crate::sys::{DLDevice, DLDeviceType, DLTensor};
395484
use ndarray::prelude::*;
485+
use ndarray::ArcArray2;
396486

397487
#[test]
398488
fn test_dlpack_to_ndarray() {
@@ -554,4 +644,41 @@ mod tests {
554644

555645
assert_eq!(original_array, final_array);
556646
}
647+
648+
#[test]
649+
fn test_arc_array_to_dlpack_share() {
650+
let array = ArcArray2::from_shape_vec((2, 3), vec![1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0]).unwrap();
651+
let ptr = array.as_ptr();
652+
653+
// Conversion to DLPackTensor (Owned) should share data
654+
let tensor: DLPackTensor = (&array).try_into().unwrap();
655+
let raw = unsafe { &tensor.raw.as_ref().dl_tensor };
656+
657+
assert_eq!(raw.data as *const f32, ptr);
658+
659+
// Convert back to Array (Copy)
660+
let array_copy: Array<f32, _> = tensor.try_into().unwrap();
661+
assert_eq!(array, array_copy);
662+
// Pointers should differ due to copy
663+
assert_ne!(array_copy.as_ptr(), ptr);
664+
}
665+
666+
#[test]
667+
fn test_dlpack_to_arc_array() {
668+
let array = arr2(&[[10.0f32, 11.0], [12.0, 13.0]]);
669+
let tensor: DLPackTensor = array.clone().try_into().unwrap();
670+
671+
let arc_array: ArcArray<f32, _> = tensor.try_into().unwrap();
672+
assert_eq!(arc_array, array);
673+
}
674+
675+
#[test]
676+
fn test_arc_array_to_dlpack_ref() {
677+
let array = ArcArray2::from_shape_vec((2, 2), vec![1, 2, 3, 4]).unwrap();
678+
let tensor_ref: DLPackTensorRef = (&array).try_into().unwrap();
679+
680+
assert_eq!(tensor_ref.n_dims(), 2);
681+
let shape = tensor_ref.shape();
682+
assert_eq!(shape, &[2, 2]);
683+
}
557684
}

0 commit comments

Comments
 (0)