|
28 | 28 | #![allow(clippy::needless_return, clippy::redundant_field_names)] |
29 | 29 | #![forbid(clippy::as_ptr_cast_mut, clippy::ptr_cast_constness)] |
30 | 30 |
|
31 | | -use std::{ffi::c_void, ptr::NonNull}; |
| 31 | +use std::ptr::NonNull; |
32 | 32 |
|
33 | 33 | pub mod sys; |
34 | 34 | pub use self::sys::{DLDataType, DLDataTypeCode, DLDevice, DLDeviceType, DLPackVersion}; |
@@ -252,63 +252,26 @@ impl Drop for DLPackTensor { |
252 | 252 | } |
253 | 253 | } |
254 | 254 |
|
255 | | -struct RustBoxedManager { |
256 | | - // tensor: std::pin::Pin<sys::DLManagedTensorVersioned>, |
257 | | - original_ctx: *mut c_void, |
258 | | - original_deleter: Option<unsafe extern "C" fn(*mut sys::DLManagedTensorVersioned) -> ()>, |
259 | | -} |
260 | | - |
261 | | -unsafe extern "C" fn rust_boxed_manager_deleter(tensor: *mut sys::DLManagedTensorVersioned) { |
262 | | - if tensor.is_null() { |
263 | | - return; |
264 | | - } |
265 | | - |
266 | | - let manager = (*tensor).manager_ctx.cast::<RustBoxedManager>(); |
267 | | - assert!(!manager.is_null()); |
268 | | - |
269 | | - (*tensor).manager_ctx = (*manager).original_ctx; |
270 | | - (*tensor).deleter = (*manager).original_deleter; |
271 | | - |
272 | | - if let Some(deleter) = (*tensor).deleter { |
273 | | - deleter(tensor); |
274 | | - } |
275 | | - |
276 | | - std::mem::drop(Box::from_raw(manager)); |
277 | | - std::mem::drop(Box::from_raw(tensor)); |
278 | | -} |
279 | | - |
280 | 255 | impl DLPackTensor { |
281 | | - /// Create a `DLPackTensor` from a raw `DLManagedTensorVersioned`. |
| 256 | + /// Create a `DLPackTensor` from a pointer to `DLManagedTensorVersioned`. |
282 | 257 | /// |
283 | 258 | /// # Safety |
284 | 259 | /// |
285 | 260 | /// The `DLManagedTensorVersioned` should have a valid `deleter` that can |
286 | 261 | /// be called from Rust, or have the deleter set to `None`. |
287 | | - pub unsafe fn from_raw(mut tensor: sys::DLManagedTensorVersioned) -> DLPackTensor { |
288 | | - // we need to move the tensor to the heap, so we need to wrap the |
289 | | - // manager_ctx and deleter into another one that will also free the |
290 | | - // tensor from the heap. |
291 | | - let manager = Box::new(RustBoxedManager { |
292 | | - original_ctx: tensor.manager_ctx, |
293 | | - original_deleter: tensor.deleter, |
294 | | - }); |
295 | | - tensor.manager_ctx = Box::into_raw(manager).cast(); |
296 | | - tensor.deleter = Some(rust_boxed_manager_deleter); |
297 | | - |
298 | | - let tensor = Box::new(tensor); |
| 262 | + pub unsafe fn from_ptr(tensor: *mut sys::DLManagedTensorVersioned) -> DLPackTensor { |
| 263 | + let tensor = NonNull::new(tensor).expect("DLManagedTensorVersioned pointer is null"); |
299 | 264 |
|
300 | | - return DLPackTensor{ |
301 | | - raw: NonNull::new_unchecked(Box::into_raw(tensor)), |
302 | | - }; |
| 265 | + return DLPackTensor::from_raw(tensor); |
303 | 266 | } |
304 | 267 |
|
305 | | - /// Create a `DLPackTensor` from a non-null pointer to `DLManagedTensorVersioned`. |
| 268 | + /// Create a `DLPackTensor` from a non-null pointer to |
| 269 | + /// `DLManagedTensorVersioned`. |
306 | 270 | /// |
307 | 271 | /// # Safety |
308 | 272 | /// |
309 | | - /// The `DLManagedTensorVersioned` should have a valid `deleter` that can |
310 | | - /// be called from Rust, or have the deleter set to `None`. |
311 | | - pub unsafe fn from_ptr(tensor: NonNull<sys::DLManagedTensorVersioned>) -> DLPackTensor { |
| 273 | + /// The same safety requirements as `from_ptr` apply. |
| 274 | + pub unsafe fn from_raw(tensor: NonNull<sys::DLManagedTensorVersioned>) -> DLPackTensor { |
312 | 275 | if tensor.as_ref().version.major != sys::DLPACK_MAJOR_VERSION { |
313 | 276 | // from the spec, we need to call the deleter here (and it is the |
314 | 277 | // only thing we can do) |
@@ -353,6 +316,14 @@ impl DLPackTensor { |
353 | 316 | } |
354 | 317 | } |
355 | 318 |
|
| 319 | + /// Get the ABI version of this DLPack tensor. |
| 320 | + pub fn version(&self) -> DLPackVersion { |
| 321 | + let tensor_ref = unsafe { |
| 322 | + self.raw.as_ref() |
| 323 | + }; |
| 324 | + tensor_ref.version |
| 325 | + } |
| 326 | + |
356 | 327 | /// Get a pointer to data in this tensor. This pointer can be a device |
357 | 328 | /// pointer according to [`DLPackTensor::device`]. |
358 | 329 | pub fn data_ptr<T>(&self) -> Result<*const T, CastError> where T: DLPackPointerCast { |
@@ -504,9 +475,13 @@ impl<'a> DLPackTensorRef<'a> { |
504 | 475 |
|
505 | 476 | /// Get the shape of this tensor |
506 | 477 | pub fn shape(&self) -> &[i64] { |
507 | | - assert!(!self.raw.shape.is_null()); |
508 | | - unsafe { |
509 | | - return std::slice::from_raw_parts(self.raw.shape, self.n_dims()); |
| 478 | + if self.raw.shape.is_null() { |
| 479 | + assert!(self.raw.ndim == 0, "Shape pointer is null but ndim is not 0"); |
| 480 | + return &[]; |
| 481 | + } else { |
| 482 | + unsafe { |
| 483 | + return std::slice::from_raw_parts(self.raw.shape, self.n_dims()); |
| 484 | + } |
510 | 485 | } |
511 | 486 | } |
512 | 487 |
|
@@ -639,6 +614,14 @@ pub mod pyo3; |
639 | 614 | #[cfg(feature = "sync")] |
640 | 615 | pub mod sync; |
641 | 616 |
|
| 617 | +/// Small wrapper type to mark a tensor as read-only when there is a choice |
| 618 | +/// between a read-only and a read-write implementation. |
| 619 | +pub struct ReadOnly<T>(pub T); |
| 620 | + |
| 621 | +/// Small wrapper type to mark a tensor as read-write when there is a choice |
| 622 | +/// between a read-only and a read-write implementation. |
| 623 | +pub struct ReadWrite<T>(pub T); |
| 624 | + |
642 | 625 |
|
643 | 626 | #[cfg(test)] |
644 | 627 | mod tests { |
|
0 commit comments