@@ -182,6 +182,41 @@ impl DataType {
182182/// This means that all data types except for `DataType::Object` are assumed to be trivially copyable.
183183/// Furthermore, it is assumed that for `DataType::Object` the elements are pointers into the Python heap
184184/// and that the corresponding `Clone` implemenation will never panic as it only increases the reference count.
185+ ///
186+ /// # Custom element types
187+ ///
188+ /// You can implement this trait to manage arrays of custom element types, but they still need to be stored
189+ /// on Python's heap using PyO3's [Py](pyo3::Py) type.
190+ ///
191+ /// ```
192+ /// use numpy::{ndarray::Array2, DataType, Element, PyArray, PyArrayDescr, ToPyArray};
193+ /// use pyo3::{pyclass, Py, Python};
194+ ///
195+ /// #[pyclass]
196+ /// pub struct CustomElement;
197+ ///
198+ /// // The transparent wrapper is necessary as one cannot implement
199+ /// // a foreign trait (`Element`) on a foreign type (`Py`) directly.
200+ /// #[derive(Clone)]
201+ /// #[repr(transparent)]
202+ /// pub struct Wrapper(pub Py<CustomElement>);
203+ ///
204+ /// unsafe impl Element for Wrapper {
205+ /// const DATA_TYPE: DataType = DataType::Object;
206+ ///
207+ /// fn is_same_type(dtype: &PyArrayDescr) -> bool {
208+ /// dtype.get_datatype() == Some(DataType::Object)
209+ /// }
210+ /// }
211+ ///
212+ /// Python::with_gil(|py| {
213+ /// let array = Array2::<Wrapper>::from_shape_fn((2, 3), |(_i, _j)| {
214+ /// Wrapper(Py::new(py, CustomElement).unwrap())
215+ /// });
216+ ///
217+ /// let _array: &PyArray<Wrapper, _> = array.to_pyarray(py);
218+ /// });
219+ /// ```
185220pub unsafe trait Element : Clone + Send {
186221 /// `DataType` corresponding to this type.
187222 const DATA_TYPE : DataType ;
0 commit comments