Skip to content

Commit 437f5fa

Browse files
JRRudy1davidhewitt
authored andcommitted
Added PyClone trait that will replace Clone as supertrait of Element.
This trait can be trivially implemented for `Clone` types, but can also be implemented for types such as `PyObject` that can only be safely cloned while the GIL is held.
1 parent bcf5f52 commit 437f5fa

File tree

1 file changed

+50
-0
lines changed

1 file changed

+50
-0
lines changed

src/dtype.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::mem::size_of;
22
use std::os::raw::{c_int, c_long, c_longlong, c_short, c_uint, c_ulong, c_ulonglong, c_ushort};
33
use std::ptr;
4+
use ndarray::{Array, ArrayView, Dimension};
45

56
#[cfg(feature = "half")]
67
use half::{bf16, f16};
@@ -644,6 +645,55 @@ impl<'py> PyArrayDescrMethods<'py> for Bound<'py, PyArrayDescr> {
644645

645646
impl Sealed for Bound<'_, PyArrayDescr> {}
646647

648+
649+
/// Weaker form of `Clone` for types that can be cloned while the GIL is held.
650+
///
651+
/// Any type that implements `Clone` can trivially implement `PyClone` by forwarding
652+
/// to the `Clone::clone` method. However, some types (notably `PyObject`) can only
653+
/// be safely cloned while the GIL is held, and therefore cannot implement `Clone`.
654+
/// This trait provides a mechanism for performing a clone while the GIL is held, as
655+
/// represented by the [`Python`] token provided as an argument to the [`py_clone`]
656+
/// method. All API's in the `numpy` crate require the GIL to be held, so this weaker
657+
/// alternative to `Clone` is a sufficient prerequisite for implementing the
658+
/// [`Element`] trait.
659+
///
660+
/// # Implementing `PyClone`
661+
/// Implementing this trait is trivial for most types, and simply requires defining
662+
/// the `py_clone` method. The `vec_from_slice` and `array_from_view` methods have
663+
/// default implementations that simply map the `py_clone` method to each item in
664+
/// the collection, but types may want to override these implementations if there
665+
/// is a more efficient way to perform the conversion. In particular, `Clone` types
666+
/// may instead defer to the `ToOwned::to_owned` and `ArrayBase::to_owned` methods
667+
/// for increased performance.
668+
///
669+
/// [`py_clone`]: Self::py_clone
670+
pub trait PyClone: Sized {
671+
/// Create a clone of the value while the GIL is guaranteed to be held.
672+
fn py_clone(&self, py: Python<'_>) -> Self;
673+
674+
/// Create an owned copy of the slice while the GIL is guaranteed to be held.
675+
///
676+
/// Some types may provide implementations of this method that are more efficient
677+
/// than simply mapping the `py_clone` method to each element in the slice.
678+
#[inline]
679+
fn vec_from_slice(py: Python<'_>, slc: &[Self]) -> Vec<Self> {
680+
slc.iter().map(|elem| elem.py_clone(py)).collect()
681+
}
682+
683+
/// Create an owned copy of the array while the GIL is guaranteed to be held.
684+
///
685+
/// Some types may provide implementations of this method that are more efficient
686+
/// than simply mapping the `py_clone` method to each element in the view.
687+
#[inline]
688+
fn array_from_view<D>(py: Python<'_>, view: ArrayView<'_, Self, D>) -> Array<Self, D>
689+
where
690+
D: Dimension
691+
{
692+
view.map(|elem| elem.py_clone(py))
693+
}
694+
}
695+
696+
647697
/// Represents that a type can be an element of `PyArray`.
648698
///
649699
/// Currently, only integer/float/complex/object types are supported. The [NumPy documentation][enumerated-types]

0 commit comments

Comments
 (0)