@@ -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" ) ]
1818use pyo3:: { AsPyPointer , PyNativeType } ;
1919
@@ -644,56 +644,6 @@ impl<'py> PyArrayDescrMethods<'py> for Bound<'py, PyArrayDescr> {
644644
645645impl 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
754731fn 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
828804macro_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
878854impl_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" ) ) ]
884860impl_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-
893862unsafe 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) ]
0 commit comments