diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 09edbb15e..2a9de3278 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -6,6 +6,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::cell::Cell; use std::ptr as std_ptr; use std::slice; @@ -151,6 +152,20 @@ where unsafe { ArrayViewMut::new(self.ptr, self.dim.clone(), self.strides.clone()) } } + /// Return a shared view of the array with elements as if they were embedded in cells. + /// + /// The cell view requires a mutable borrow of the array. Once borrowed the + /// cell view itself can be copied and accessed without exclusivity. + /// + /// The view acts "as if" the elements are temporarily in cells, and elements + /// can be changed through shared references using the regular cell methods. + pub fn cell_view(&mut self) -> ArrayView<'_, Cell, D> + where + S: DataMut, + { + self.view_mut().into_cell_view() + } + /// Return an uniquely owned copy of the array. /// /// If the input array is contiguous and its strides are positive, then the diff --git a/src/impl_views/conversions.rs b/src/impl_views/conversions.rs index 863d26ddb..4265f7616 100644 --- a/src/impl_views/conversions.rs +++ b/src/impl_views/conversions.rs @@ -6,6 +6,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::cell::Cell; use std::slice; use crate::imp_prelude::*; @@ -117,6 +118,21 @@ where pub fn into_slice(self) -> Option<&'a mut [A]> { self.try_into_slice().ok() } + + /// Return a shared view of the array with elements as if they were embedded in cells. + /// + /// The cell view itself can be copied and accessed without exclusivity. + /// + /// The view acts "as if" the elements are temporarily in cells, and elements + /// can be changed through shared references using the regular cell methods. + pub fn into_cell_view(self) -> ArrayView<'a, Cell, D> { + // safety: valid because + // A and Cell have the same representation + // &'a mut T is interchangeable with &'a Cell -- see method Cell::from_mut + unsafe { + self.into_raw_view_mut().cast::>().deref_into_view() + } + } } /// Private array view methods diff --git a/tests/views.rs b/tests/views.rs new file mode 100644 index 000000000..216e55402 --- /dev/null +++ b/tests/views.rs @@ -0,0 +1,16 @@ +use ndarray::prelude::*; +use ndarray::Zip; + +#[test] +fn cell_view() { + let mut a = Array::from_shape_fn((10, 5), |(i, j)| (i * j) as f32); + let answer = &a + 1.; + + { + let cv1 = a.cell_view(); + let cv2 = cv1; + + Zip::from(cv1).and(cv2).apply(|a, b| a.set(b.get() + 1.)); + } + assert_eq!(a, answer); +}