Skip to main content

ferray_core/array/
view_mut.rs

1// ferray-core: Mutable array view — ArrayViewMut<'a, T, D> (REQ-3)
2
3use crate::dimension::Dimension;
4use crate::dtype::Element;
5use crate::layout::MemoryLayout;
6
7use super::ArrayFlags;
8use super::owned::Array;
9
10/// A mutable, borrowed view into an existing array's data.
11///
12/// This is a zero-copy mutable slice. The lifetime `'a` ties this view
13/// to the source array, and Rust's borrow checker ensures exclusivity.
14pub struct ArrayViewMut<'a, T: Element, D: Dimension> {
15    pub(crate) inner: ndarray::ArrayViewMut<'a, T, D::NdarrayDim>,
16    pub(crate) dim: D,
17}
18
19impl<'a, T: Element, D: Dimension> ArrayViewMut<'a, T, D> {
20    /// Create from an ndarray mutable view. Crate-internal.
21    pub(crate) fn from_ndarray(inner: ndarray::ArrayViewMut<'a, T, D::NdarrayDim>) -> Self {
22        let dim = D::from_ndarray_dim(&inner.raw_dim());
23        Self { inner, dim }
24    }
25
26    /// Shape as a slice.
27    #[inline]
28    pub fn shape(&self) -> &[usize] {
29        self.inner.shape()
30    }
31
32    /// Number of dimensions.
33    #[inline]
34    pub fn ndim(&self) -> usize {
35        self.dim.ndim()
36    }
37
38    /// Total number of elements.
39    #[inline]
40    pub fn size(&self) -> usize {
41        self.inner.len()
42    }
43
44    /// Whether the view has zero elements.
45    #[inline]
46    pub fn is_empty(&self) -> bool {
47        self.inner.is_empty()
48    }
49
50    /// Strides as a slice.
51    #[inline]
52    pub fn strides(&self) -> &[isize] {
53        self.inner.strides()
54    }
55
56    /// Raw pointer to the first element.
57    #[inline]
58    pub fn as_ptr(&self) -> *const T {
59        self.inner.as_ptr()
60    }
61
62    /// Mutable raw pointer to the first element.
63    #[inline]
64    pub fn as_mut_ptr(&mut self) -> *mut T {
65        self.inner.as_mut_ptr()
66    }
67
68    /// Try to get a contiguous slice.
69    pub fn as_slice(&self) -> Option<&[T]> {
70        self.inner.as_slice()
71    }
72
73    /// Try to get a contiguous mutable slice.
74    pub fn as_slice_mut(&mut self) -> Option<&mut [T]> {
75        self.inner.as_slice_mut()
76    }
77
78    /// Memory layout.
79    pub fn layout(&self) -> MemoryLayout {
80        if self.inner.is_standard_layout() {
81            MemoryLayout::C
82        } else {
83            let shape = self.dim.as_slice();
84            let strides: Vec<isize> = self.inner.strides().to_vec();
85            crate::layout::detect_layout(shape, &strides)
86        }
87    }
88
89    /// Return a reference to the internal dimension descriptor.
90    #[inline]
91    pub fn dim(&self) -> &D {
92        &self.dim
93    }
94
95    /// Convert to a flat `Vec<T>` in logical (row-major) order.
96    pub fn to_vec_flat(&self) -> Vec<T> {
97        self.inner.iter().cloned().collect()
98    }
99
100    /// Array flags for this mutable view.
101    pub fn flags(&self) -> ArrayFlags {
102        let layout = self.layout();
103        ArrayFlags {
104            c_contiguous: layout.is_c_contiguous(),
105            f_contiguous: layout.is_f_contiguous(),
106            owndata: false,
107            writeable: true,
108        }
109    }
110}
111
112// Create an ArrayViewMut from an owned Array
113impl<T: Element, D: Dimension> Array<T, D> {
114    /// Create a mutable view of this array.
115    pub fn view_mut(&mut self) -> ArrayViewMut<'_, T, D> {
116        ArrayViewMut::from_ndarray(self.inner.view_mut())
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123    use crate::dimension::Ix1;
124
125    #[test]
126    fn view_mut_from_owned() {
127        let mut arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
128        let v = arr.view_mut();
129        assert_eq!(v.shape(), &[3]);
130        assert!(v.flags().writeable);
131        assert!(!v.flags().owndata);
132    }
133
134    #[test]
135    fn view_mut_modify() {
136        let mut arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
137        {
138            let mut v = arr.view_mut();
139            if let Some(s) = v.as_slice_mut() {
140                s[0] = 99.0;
141            }
142        }
143        assert_eq!(arr.as_slice().unwrap()[0], 99.0);
144    }
145}