Skip to content

Commit 0c9f6e9

Browse files
committed
Removed PyClone trait, moved it methods to Element, and updated implementations/usages.
The updates including renaming the `py_clone` method to `clone_ref` to match that of `Py::clone_ref`, and replacing the `impl_py_clone!` macro with `clone_methods_impl!`.
1 parent 26266ee commit 0c9f6e9

File tree

6 files changed

+75
-143
lines changed

6 files changed

+75
-143
lines changed

src/array.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1473,7 +1473,7 @@ unsafe fn clone_elements<T: Element>(py: Python<'_>, elems: &[T], data_ptr: &mut
14731473
*data_ptr = data_ptr.add(elems.len());
14741474
} else {
14751475
for elem in elems {
1476-
data_ptr.write(elem.py_clone(py));
1476+
data_ptr.write(elem.clone_ref(py));
14771477
*data_ptr = data_ptr.add(1);
14781478
}
14791479
}
@@ -2205,7 +2205,7 @@ impl<'py, T, D> PyArrayMethods<'py, T, D> for Bound<'py, PyArray<T, D>> {
22052205
Idx: NpyIndex<Dim = D>,
22062206
{
22072207
let element = unsafe { self.get(index) };
2208-
element.map(|elem| elem.py_clone(self.py()))
2208+
element.map(|elem| elem.clone_ref(self.py()))
22092209
}
22102210

22112211
fn to_dyn(&self) -> &Bound<'py, PyArray<T, IxDyn>> {

src/convert.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ where
203203
let array = PyArray::<A, _>::new_bound(py, dim, false);
204204
let mut data_ptr = array.data();
205205
for item in self.iter() {
206-
data_ptr.write(item.py_clone(py));
206+
data_ptr.write(item.clone_ref(py));
207207
data_ptr = data_ptr.add(1);
208208
}
209209
array
@@ -236,7 +236,7 @@ where
236236
ptr::copy_nonoverlapping(self.data.ptr(), data_ptr, self.len());
237237
} else {
238238
for item in self.iter() {
239-
data_ptr.write(item.py_clone(py));
239+
data_ptr.write(item.clone_ref(py));
240240
data_ptr = data_ptr.add(1);
241241
}
242242
}

src/datetime.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ use std::marker::PhantomData;
6666
use pyo3::{sync::GILProtected, Bound, Py, Python};
6767
use rustc_hash::FxHashMap;
6868

69-
use crate::dtype::{Element, PyArrayDescr, PyArrayDescrMethods, impl_py_clone};
69+
use crate::dtype::{Element, PyArrayDescr, PyArrayDescrMethods, clone_methods_impl};
7070
use crate::npyffi::{
7171
PyArray_DatetimeDTypeMetaData, PyDataType_C_METADATA, NPY_DATETIMEUNIT, NPY_TYPES,
7272
};
@@ -155,8 +155,6 @@ impl<U: Unit> From<Datetime<U>> for i64 {
155155
}
156156
}
157157

158-
impl_py_clone!(Datetime<U>; [U: Unit]);
159-
160158
unsafe impl<U: Unit> Element for Datetime<U> {
161159
const IS_COPY: bool = true;
162160

@@ -165,6 +163,8 @@ unsafe impl<U: Unit> Element for Datetime<U> {
165163

166164
DTYPES.from_unit(py, U::UNIT)
167165
}
166+
167+
clone_methods_impl!(Self);
168168
}
169169

170170
impl<U: Unit> fmt::Debug for Datetime<U> {
@@ -192,8 +192,6 @@ impl<U: Unit> From<Timedelta<U>> for i64 {
192192
}
193193
}
194194

195-
impl_py_clone!(Timedelta<U>; [U: Unit]);
196-
197195
unsafe impl<U: Unit> Element for Timedelta<U> {
198196
const IS_COPY: bool = true;
199197

@@ -202,6 +200,8 @@ unsafe impl<U: Unit> Element for Timedelta<U> {
202200

203201
DTYPES.from_unit(py, U::UNIT)
204202
}
203+
204+
clone_methods_impl!(Self);
205205
}
206206

207207
impl<U: Unit> fmt::Debug for Timedelta<U> {

src/dtype.rs

+61-87
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ use pyo3::{
1010
ffi::{self, PyTuple_Size},
1111
pyobject_native_type_extract, pyobject_native_type_named,
1212
types::{PyAnyMethods, PyDict, PyDictMethods, PyTuple, PyType},
13-
Borrowed, Bound, PyAny, PyObject, PyResult, PyTypeInfo, Python, ToPyObject,
13+
Borrowed, Bound, Py, PyAny, PyObject, PyResult, PyTypeInfo, Python, ToPyObject,
1414
};
1515
#[cfg(feature = "half")]
16-
use pyo3::{sync::GILOnceCell, Py};
16+
use pyo3::{sync::GILOnceCell};
1717
#[cfg(feature = "gil-refs")]
1818
use pyo3::{AsPyPointer, PyNativeType};
1919

@@ -644,56 +644,6 @@ impl<'py> PyArrayDescrMethods<'py> for Bound<'py, PyArrayDescr> {
644644

645645
impl Sealed for Bound<'_, PyArrayDescr> {}
646646

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

750700
/// Returns the associated type descriptor ("dtype") for the given element type.
751701
fn get_dtype_bound(py: Python<'_>) -> Bound<'_, PyArrayDescr>;
702+
703+
/// Create a clone of the value while the GIL is guaranteed to be held.
704+
fn clone_ref(&self, py: Python<'_>) -> Self;
705+
706+
/// Create an owned copy of the slice while the GIL is guaranteed to be held.
707+
///
708+
/// Some types may provide implementations of this method that are more efficient
709+
/// than simply mapping the `py_clone` method to each element in the slice.
710+
#[inline]
711+
fn vec_from_slice(py: Python<'_>, slc: &[Self]) -> Vec<Self> {
712+
slc.iter().map(|elem| elem.clone_ref(py)).collect()
713+
}
714+
715+
/// Create an owned copy of the array while the GIL is guaranteed to be held.
716+
///
717+
/// Some types may provide implementations of this method that are more efficient
718+
/// than simply mapping the `py_clone` method to each element in the view.
719+
#[inline]
720+
fn array_from_view<D>(
721+
py: Python<'_>,
722+
view: ::ndarray::ArrayView<'_, Self, D>,
723+
) -> ::ndarray::Array<Self, D>
724+
where
725+
D: ::ndarray::Dimension,
726+
{
727+
view.map(|elem| elem.clone_ref(py))
728+
}
752729
}
753730

754731
fn npy_int_type_lookup<T, T0, T1, T2>(npy_types: [NPY_TYPES; 3]) -> NPY_TYPES {
@@ -796,34 +773,33 @@ fn npy_int_type<T: Bounded + Zero + Sized + PartialEq>() -> NPY_TYPES {
796773
}
797774
}
798775

799-
// Implements `PyClone` for a type that implements `Clone`
800-
macro_rules! impl_py_clone {
801-
($ty:ty $(; [$param:ident $(: $bound:ident)?])?) => {
802-
impl <$($param$(: $bound)*)?> $crate::dtype::PyClone for $ty {
803-
#[inline]
804-
fn py_clone(&self, _py: ::pyo3::Python<'_>) -> Self {
805-
self.clone()
806-
}
776+
// Invoke within the `Element` impl for a `Clone` type to provide an efficient
777+
// implementation of the cloning methods
778+
macro_rules! clone_methods_impl {
779+
($Self:ty) => {
780+
#[inline]
781+
fn clone_ref(&self, _py: ::pyo3::Python<'_>) -> $Self {
782+
::std::clone::Clone::clone(self)
783+
}
807784

808-
#[inline]
809-
fn vec_from_slice(_py: ::pyo3::Python<'_>, slc: &[Self]) -> Vec<Self> {
810-
slc.to_owned()
811-
}
785+
#[inline]
786+
fn vec_from_slice(_py: ::pyo3::Python<'_>, slc: &[$Self]) -> Vec<$Self> {
787+
::std::borrow::ToOwned::to_owned(slc)
788+
}
812789

813-
#[inline]
814-
fn array_from_view<D>(
815-
_py: ::pyo3::Python<'_>,
816-
view: ::ndarray::ArrayView<'_, Self, D>
817-
) -> ::ndarray::Array<Self, D>
818-
where
819-
D: ::ndarray::Dimension
820-
{
821-
view.to_owned()
822-
}
790+
#[inline]
791+
fn array_from_view<D>(
792+
_py: ::pyo3::Python<'_>,
793+
view: ::ndarray::ArrayView<'_, $Self, D>
794+
) -> ::ndarray::Array<$Self, D>
795+
where
796+
D: ::ndarray::Dimension
797+
{
798+
::ndarray::ArrayView::to_owned(&view)
823799
}
824800
}
825801
}
826-
pub(crate) use impl_py_clone;
802+
pub(crate) use clone_methods_impl;
827803

828804
macro_rules! impl_element_scalar {
829805
(@impl: $ty:ty, $npy_type:expr $(,#[$meta:meta])*) => {
@@ -834,8 +810,9 @@ macro_rules! impl_element_scalar {
834810
fn get_dtype_bound(py: Python<'_>) -> Bound<'_, PyArrayDescr> {
835811
PyArrayDescr::from_npy_type(py, $npy_type)
836812
}
813+
814+
clone_methods_impl!($ty);
837815
}
838-
impl_py_clone!($ty);
839816
};
840817
($ty:ty => $npy_type:ident $(,#[$meta:meta])*) => {
841818
impl_element_scalar!(@impl: $ty, NPY_TYPES::$npy_type $(,#[$meta])*);
@@ -870,10 +847,9 @@ unsafe impl Element for bf16 {
870847
.clone_ref(py)
871848
.into_bound(py)
872849
}
873-
}
874850

875-
#[cfg(feature = "half")]
876-
impl_py_clone!(bf16);
851+
clone_methods_impl!(Self);
852+
}
877853

878854
impl_element_scalar!(Complex32 => NPY_CFLOAT,
879855
#[doc = "Complex type with `f32` components which maps to `numpy.csingle` (`numpy.complex64`)."]);
@@ -883,19 +859,17 @@ impl_element_scalar!(Complex64 => NPY_CDOUBLE,
883859
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
884860
impl_element_scalar!(usize, isize);
885861

886-
impl PyClone for PyObject {
887-
#[inline]
888-
fn py_clone(&self, py: Python<'_>) -> Self {
889-
self.clone_ref(py)
890-
}
891-
}
892-
893862
unsafe impl Element for PyObject {
894863
const IS_COPY: bool = false;
895864

896865
fn get_dtype_bound(py: Python<'_>) -> Bound<'_, PyArrayDescr> {
897866
PyArrayDescr::object_bound(py)
898867
}
868+
869+
#[inline]
870+
fn clone_ref(&self, py: Python<'_>) -> Self {
871+
Py::clone_ref(self, py)
872+
}
899873
}
900874

901875
#[cfg(test)]

src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ pub use crate::convert::{IntoPyArray, NpyIndex, ToNpyDims, ToPyArray};
114114
#[cfg(feature = "gil-refs")]
115115
pub use crate::dtype::dtype;
116116
pub use crate::dtype::{
117-
dtype_bound, Complex32, Complex64, Element, PyArrayDescr, PyArrayDescrMethods, PyClone,
117+
dtype_bound, Complex32, Complex64, Element, PyArrayDescr, PyArrayDescrMethods,
118118
};
119119
pub use crate::error::{BorrowError, FromVecError, NotContiguousError};
120120
pub use crate::npyffi::{PY_ARRAY_API, PY_UFUNC_API};

src/strings.rs

+4-46
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use pyo3::{
1717
};
1818
use rustc_hash::FxHashMap;
1919

20-
use crate::dtype::{Element, PyArrayDescr, PyArrayDescrMethods, PyClone};
20+
use crate::dtype::{clone_methods_impl, Element, PyArrayDescr, PyArrayDescrMethods};
2121
use crate::npyffi::PyDataType_SET_ELSIZE;
2222
use crate::npyffi::NPY_TYPES;
2323

@@ -82,29 +82,8 @@ unsafe impl<const N: usize> Element for PyFixedString<N> {
8282

8383
unsafe { DTYPES.from_size(py, NPY_TYPES::NPY_STRING, b'|' as _, size_of::<Self>()) }
8484
}
85-
}
86-
87-
impl<const N: usize> PyClone for PyFixedString<N> {
88-
#[inline]
89-
fn py_clone(&self, _py: Python<'_>) -> Self {
90-
*self
91-
}
9285

93-
#[inline]
94-
fn vec_from_slice(_py: Python<'_>, slc: &[Self]) -> Vec<Self> {
95-
slc.to_owned()
96-
}
97-
98-
#[inline]
99-
fn array_from_view<D>(
100-
_py: Python<'_>,
101-
view: ::ndarray::ArrayView<'_, Self, D>,
102-
) -> ::ndarray::Array<Self, D>
103-
where
104-
D: ::ndarray::Dimension,
105-
{
106-
view.to_owned()
107-
}
86+
clone_methods_impl!(Self);
10887
}
10988

11089
/// A newtype wrapper around [`[PyUCS4; N]`][Py_UCS4] to handle [`str_` scalars][numpy-str] while satisfying coherence.
@@ -168,29 +147,6 @@ impl<const N: usize> From<[Py_UCS4; N]> for PyFixedUnicode<N> {
168147
}
169148
}
170149

171-
impl<const N: usize> PyClone for PyFixedUnicode<N> {
172-
#[inline]
173-
fn py_clone(&self, _py: Python<'_>) -> Self {
174-
*self
175-
}
176-
177-
#[inline]
178-
fn vec_from_slice(_py: Python<'_>, slc: &[Self]) -> Vec<Self> {
179-
slc.to_owned()
180-
}
181-
182-
#[inline]
183-
fn array_from_view<D>(
184-
_py: Python<'_>,
185-
view: ::ndarray::ArrayView<'_, Self, D>,
186-
) -> ::ndarray::Array<Self, D>
187-
where
188-
D: ::ndarray::Dimension,
189-
{
190-
view.to_owned()
191-
}
192-
}
193-
194150
unsafe impl<const N: usize> Element for PyFixedUnicode<N> {
195151
const IS_COPY: bool = true;
196152

@@ -199,6 +155,8 @@ unsafe impl<const N: usize> Element for PyFixedUnicode<N> {
199155

200156
unsafe { DTYPES.from_size(py, NPY_TYPES::NPY_UNICODE, b'=' as _, size_of::<Self>()) }
201157
}
158+
159+
clone_methods_impl!(Self);
202160
}
203161

204162
struct TypeDescriptors {

0 commit comments

Comments
 (0)