1use crate::dimension::Dimension;
4use crate::dtype::{DType, Element};
5use crate::error::{FerrayError, FerrayResult};
6
7use super::ArrayFlags;
8use super::owned::Array;
9use super::view::ArrayView;
10
11impl<T: Element, D: Dimension> Array<T, D> {
16 #[inline]
18 pub const fn itemsize(&self) -> usize {
19 std::mem::size_of::<T>()
20 }
21
22 #[inline]
24 pub fn nbytes(&self) -> usize {
25 self.size() * self.itemsize()
26 }
27
28 #[inline]
30 pub fn dtype(&self) -> DType {
31 T::dtype()
32 }
33
34 pub fn t(&self) -> ArrayView<'_, T, D> {
40 let transposed = self.inner.view().reversed_axes();
41 ArrayView::from_ndarray(transposed)
42 }
43
44 #[must_use]
46 pub fn copy(&self) -> Self {
47 Self {
48 inner: self.inner.clone(),
49 dim: self.dim.clone(),
50 }
51 }
52
53 pub fn to_vec_flat(&self) -> Vec<T> {
55 self.inner.iter().cloned().collect()
56 }
57
58 pub fn to_bytes(&self) -> FerrayResult<&[u8]>
63 where
64 T: Copy,
65 {
66 let slice = self.inner.as_slice().ok_or_else(|| {
67 FerrayError::invalid_value("array is not contiguous; cannot produce byte slice")
68 })?;
69 let ptr = slice.as_ptr().cast::<u8>();
70 let len = std::mem::size_of_val(slice);
71 Ok(unsafe { std::slice::from_raw_parts(ptr, len) })
74 }
75
76 pub fn flags(&self) -> ArrayFlags {
78 let layout = self.layout();
79 ArrayFlags {
80 c_contiguous: layout.is_c_contiguous(),
81 f_contiguous: layout.is_f_contiguous(),
82 owndata: true,
83 writeable: true,
84 aligned: true,
87 }
88 }
89}
90
91impl<T: Element, D: Dimension> ArrayView<'_, T, D> {
96 #[inline]
98 pub const fn itemsize(&self) -> usize {
99 std::mem::size_of::<T>()
100 }
101
102 #[inline]
104 pub fn nbytes(&self) -> usize {
105 self.size() * self.itemsize()
106 }
107
108 #[inline]
110 pub fn dtype(&self) -> DType {
111 T::dtype()
112 }
113
114 pub fn t(&self) -> ArrayView<'_, T, D> {
116 let transposed = self.inner.clone().reversed_axes();
117 ArrayView::from_ndarray(transposed)
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124 use crate::dimension::{Ix1, Ix2};
125
126 #[test]
127 fn introspect_basics() {
128 let arr = Array::<f64, Ix2>::from_vec(Ix2::new([2, 3]), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
129 .unwrap();
130
131 assert_eq!(arr.ndim(), 2);
132 assert_eq!(arr.size(), 6);
133 assert_eq!(arr.shape(), &[2, 3]);
134 assert_eq!(arr.itemsize(), 8); assert_eq!(arr.nbytes(), 48); assert_eq!(arr.dtype(), DType::F64);
137 assert!(!arr.is_empty());
138 }
139
140 #[test]
141 fn introspect_empty() {
142 let arr = Array::<f64, Ix1>::from_vec(Ix1::new([0]), vec![]).unwrap();
143 assert!(arr.is_empty());
144 assert_eq!(arr.size(), 0);
145 assert_eq!(arr.nbytes(), 0);
146 }
147
148 #[test]
149 fn flags_owned() {
150 let arr = Array::<f64, Ix2>::zeros(Ix2::new([3, 4])).unwrap();
151 let f = arr.flags();
152 assert!(f.c_contiguous);
153 assert!(f.owndata);
154 assert!(f.writeable);
155 assert!(f.aligned, "owned arrays go through Vec<T> — always aligned");
156 }
157
158 #[test]
159 fn flags_owned_aligned_for_various_dtypes() {
160 let f64_arr = Array::<f64, Ix1>::zeros(Ix1::new([8])).unwrap();
163 assert!(f64_arr.flags().aligned);
164 let i32_arr = Array::<i32, Ix1>::zeros(Ix1::new([8])).unwrap();
165 assert!(i32_arr.flags().aligned);
166 let u8_arr = Array::<u8, Ix1>::zeros(Ix1::new([8])).unwrap();
167 assert!(u8_arr.flags().aligned);
168 }
169
170 #[test]
171 fn transpose_view() {
172 let arr = Array::<f64, Ix2>::from_vec(Ix2::new([2, 3]), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
173 .unwrap();
174 let t = arr.t();
175 assert_eq!(t.shape(), &[3, 2]);
176 assert_eq!(t.size(), 6);
177 }
178
179 #[test]
180 fn copy_is_independent() {
181 let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
182 let copy = arr.copy();
183 assert_eq!(copy.as_slice().unwrap(), arr.as_slice().unwrap());
184 assert_ne!(copy.as_ptr(), arr.as_ptr());
185 }
186
187 #[test]
188 fn to_vec_flat() {
189 let arr = Array::<i32, Ix2>::from_vec(Ix2::new([2, 2]), vec![1, 2, 3, 4]).unwrap();
190 assert_eq!(arr.to_vec_flat(), vec![1, 2, 3, 4]);
191 }
192
193 #[test]
194 fn to_bytes_contiguous() {
195 let arr = Array::<u8, Ix1>::from_vec(Ix1::new([4]), vec![0xDE, 0xAD, 0xBE, 0xEF]).unwrap();
196 let bytes = arr.to_bytes().unwrap();
197 assert_eq!(bytes, &[0xDE, 0xAD, 0xBE, 0xEF]);
198 }
199
200 #[test]
201 fn view_introspection() {
202 let arr = Array::<f64, Ix2>::from_vec(Ix2::new([2, 3]), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
203 .unwrap();
204 let v = arr.view();
205 assert_eq!(v.itemsize(), 8);
206 assert_eq!(v.nbytes(), 48);
207 assert_eq!(v.dtype(), DType::F64);
208 }
209
210 #[test]
211 fn view_transpose() {
212 let arr = Array::<f64, Ix2>::from_vec(Ix2::new([2, 3]), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
213 .unwrap();
214 let v = arr.view();
215 let vt = v.t();
216 assert_eq!(vt.shape(), &[3, 2]);
217 }
218}