1use crate::{Dimension, GdlData, GdlType, XdlError, XdlResult, XdlValue};
4use ndarray::{ArrayD, IxDyn};
5use num_complex::{Complex32, Complex64};
6use std::fmt;
7
8#[derive(Debug, Clone)]
10pub struct XdlArray<T> {
11 data: ArrayD<T>,
12 dimensions: Dimension,
13 gdl_type: GdlType,
14}
15
16impl<T> XdlArray<T>
17where
18 T: Clone + Default + fmt::Debug + Send + Sync + 'static,
19{
20 pub fn new(dimensions: Dimension, gdl_type: GdlType) -> Result<Self, XdlError>
22 where
23 T: Default,
24 {
25 let shape: Vec<usize> = if dimensions.is_scalar() {
26 vec![]
27 } else {
28 dimensions.dims().to_vec()
29 };
30
31 let data = ArrayD::default(IxDyn(&shape));
32
33 Ok(Self {
34 data,
35 dimensions,
36 gdl_type,
37 })
38 }
39
40 pub fn from_vec(
42 data: Vec<T>,
43 dimensions: Dimension,
44 gdl_type: GdlType,
45 ) -> Result<Self, XdlError> {
46 if data.len() != dimensions.n_elements() {
47 return Err(XdlError::DimensionError(format!(
48 "Data length {} doesn't match dimension size {}",
49 data.len(),
50 dimensions.n_elements()
51 )));
52 }
53
54 let shape: Vec<usize> = if dimensions.is_scalar() {
55 vec![]
56 } else {
57 dimensions.dims().to_vec()
58 };
59
60 let array_data = ArrayD::from_shape_vec(IxDyn(&shape), data)
61 .map_err(|e| XdlError::DimensionError(format!("Shape error: {}", e)))?;
62
63 Ok(Self {
64 data: array_data,
65 dimensions,
66 gdl_type,
67 })
68 }
69
70 pub fn scalar(value: T, gdl_type: GdlType) -> Self {
72 let data = ArrayD::from_elem(IxDyn(&[]), value);
73 Self {
74 data,
75 dimensions: Dimension::scalar(),
76 gdl_type,
77 }
78 }
79
80 pub fn get(&self, indices: &[usize]) -> Result<&T, XdlError> {
82 if self.dimensions.is_scalar() && indices.is_empty() {
83 return Ok(&self.data[IxDyn(&[])]);
84 }
85
86 if indices.len() != self.dimensions.rank() {
87 return Err(XdlError::IndexError(format!(
88 "Index rank {} doesn't match array rank {}",
89 indices.len(),
90 self.dimensions.rank()
91 )));
92 }
93
94 let ix = IxDyn(indices);
95 self.data
96 .get(ix)
97 .ok_or_else(|| XdlError::IndexError(format!("Index {:?} out of bounds", indices)))
98 }
99
100 pub fn set(&mut self, indices: &[usize], value: T) -> Result<(), XdlError> {
102 if self.dimensions.is_scalar() && indices.is_empty() {
103 self.data[IxDyn(&[])] = value;
104 return Ok(());
105 }
106
107 if indices.len() != self.dimensions.rank() {
108 return Err(XdlError::IndexError(format!(
109 "Index rank {} doesn't match array rank {}",
110 indices.len(),
111 self.dimensions.rank()
112 )));
113 }
114
115 let ix = IxDyn(indices);
116 if let Some(elem) = self.data.get_mut(ix) {
117 *elem = value;
118 Ok(())
119 } else {
120 Err(XdlError::IndexError(format!(
121 "Index {:?} out of bounds",
122 indices
123 )))
124 }
125 }
126
127 pub fn get_linear(&self, index: usize) -> Result<&T, XdlError> {
129 if index >= self.dimensions.n_elements() {
130 return Err(XdlError::IndexError(format!(
131 "Linear index {} out of range",
132 index
133 )));
134 }
135
136 let multi_idx = self.dimensions.multi_index(index)?;
138 self.get(&multi_idx)
139 }
140
141 pub fn set_linear(&mut self, index: usize, value: T) -> Result<(), XdlError> {
143 if index >= self.dimensions.n_elements() {
144 return Err(XdlError::IndexError(format!(
145 "Linear index {} out of range",
146 index
147 )));
148 }
149
150 let multi_idx = self.dimensions.multi_index(index)?;
151 self.set(&multi_idx, value)
152 }
153
154 pub fn transpose(&self, axes: Option<&[usize]>) -> Result<Self, XdlError>
156 where
157 T: Clone,
158 {
159 let new_dims = self.dimensions.transpose(axes)?;
160 let new_data = if let Some(ax) = axes {
161 self.data.clone().permuted_axes(ax).to_owned()
162 } else {
163 let reversed_axes: Vec<usize> = (0..self.dimensions.rank()).rev().collect();
165 self.data
166 .clone()
167 .permuted_axes(reversed_axes.as_slice())
168 .to_owned()
169 };
170
171 Ok(Self {
172 data: new_data,
173 dimensions: new_dims,
174 gdl_type: self.gdl_type,
175 })
176 }
177
178 pub fn reform(&self, new_dims: Vec<usize>) -> Result<Self, XdlError>
180 where
181 T: Clone,
182 {
183 let new_dimensions = self.dimensions.reform(new_dims)?;
184 let shape: Vec<usize> = if new_dimensions.is_scalar() {
185 vec![]
186 } else {
187 new_dimensions.dims().to_vec()
188 };
189
190 let new_data = self
191 .data
192 .clone()
193 .into_shape(IxDyn(&shape))
194 .map_err(|e| XdlError::DimensionError(format!("Reform error: {}", e)))?;
195
196 Ok(Self {
197 data: new_data,
198 dimensions: new_dimensions,
199 gdl_type: self.gdl_type,
200 })
201 }
202
203 pub fn dimensions(&self) -> &Dimension {
205 &self.dimensions
206 }
207
208 pub fn gdl_type(&self) -> GdlType {
210 self.gdl_type
211 }
212
213 pub fn as_slice(&self) -> Option<&[T]> {
215 self.data.as_slice()
216 }
217
218 pub fn to_vec(&self) -> Vec<T>
220 where
221 T: Clone,
222 {
223 if let Some(slice) = self.as_slice() {
224 slice.to_vec()
225 } else {
226 self.data.iter().cloned().collect()
227 }
228 }
229}
230
231pub type ByteArray = XdlArray<u8>;
233pub type IntArray = XdlArray<i16>;
234pub type LongArray = XdlArray<i32>;
235pub type FloatArray = XdlArray<f32>;
236pub type DoubleArray = XdlArray<f64>;
237pub type ComplexArray = XdlArray<Complex32>;
238pub type DComplexArray = XdlArray<Complex64>;
239pub type StringArray = XdlArray<String>;
240
241macro_rules! impl_gdl_data {
243 ($array_type:ty, $gdl_type:expr) => {
244 impl GdlData for $array_type {
245 fn gdl_type(&self) -> GdlType {
246 $gdl_type
247 }
248
249 fn dimensions(&self) -> &Dimension {
250 &self.dimensions
251 }
252
253 fn n_elements(&self) -> usize {
254 self.dimensions.n_elements()
255 }
256
257 fn size_bytes(&self) -> usize {
258 self.n_elements() * $gdl_type.size()
259 }
260
261 fn clone_boxed(&self) -> Box<dyn GdlData> {
262 Box::new(self.clone())
263 }
264
265 fn to_string_repr(&self) -> String {
266 if self.dimensions.is_scalar() {
267 format!("{:?}", self.get(&[]).unwrap())
268 } else {
269 format!("Array[{}]: {}", self.gdl_type(), self.dimensions)
270 }
271 }
272 }
273 };
274}
275
276impl_gdl_data!(ByteArray, GdlType::Byte);
277impl_gdl_data!(IntArray, GdlType::Int);
278impl_gdl_data!(LongArray, GdlType::Long);
279impl_gdl_data!(FloatArray, GdlType::Float);
280impl_gdl_data!(DoubleArray, GdlType::Double);
281impl_gdl_data!(ComplexArray, GdlType::Complex);
282impl_gdl_data!(DComplexArray, GdlType::DComplex);
283impl_gdl_data!(StringArray, GdlType::String);
284
285impl XdlArray<f64> {
287 pub fn from_gdl_value(value: &XdlValue) -> XdlResult<Self> {
289 let double_val = value.to_double()?;
290 Ok(Self::scalar(double_val, GdlType::Double))
291 }
292}
293
294#[cfg(test)]
295mod tests {
296 use super::*;
297
298 #[test]
299 fn test_scalar_array() {
300 let arr = FloatArray::scalar(3.5, GdlType::Float);
301 assert!(arr.dimensions().is_scalar());
302 assert_eq!(arr.n_elements(), 1);
303 assert_eq!(*arr.get(&[]).unwrap(), 3.5);
304 }
305
306 #[test]
307 fn test_vector_array() {
308 let dim = Dimension::from_size(5).unwrap();
309 let data = vec![1, 2, 3, 4, 5];
310 let arr = LongArray::from_vec(data, dim, GdlType::Long).unwrap();
311
312 assert!(arr.dimensions().is_vector());
313 assert_eq!(arr.n_elements(), 5);
314 assert_eq!(*arr.get(&[2]).unwrap(), 3);
315 }
316
317 #[test]
318 fn test_multi_dim_array() {
319 let dim = Dimension::from_vec(vec![2, 3]).unwrap();
320 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0];
321 let arr = DoubleArray::from_vec(data, dim, GdlType::Double).unwrap();
322
323 assert_eq!(arr.dimensions().rank(), 2);
324 assert_eq!(arr.n_elements(), 6);
325 assert_eq!(*arr.get(&[1, 2]).unwrap(), 6.0);
326 }
327
328 #[test]
329 fn test_linear_indexing() {
330 let dim = Dimension::from_vec(vec![2, 3]).unwrap();
331 let data = vec![1, 2, 3, 4, 5, 6];
332 let mut arr = LongArray::from_vec(data, dim, GdlType::Long).unwrap();
333
334 assert_eq!(*arr.get_linear(5).unwrap(), 6);
335 arr.set_linear(0, 10).unwrap();
336 assert_eq!(*arr.get(&[0, 0]).unwrap(), 10);
337 }
338
339 #[test]
340 fn test_transpose() {
341 let dim = Dimension::from_vec(vec![2, 3]).unwrap();
342 let data = vec![1, 2, 3, 4, 5, 6];
343 let arr = LongArray::from_vec(data, dim, GdlType::Long).unwrap();
344
345 let transposed = arr.transpose(None).unwrap();
346 assert_eq!(transposed.dimensions().dims(), &[3, 2]);
347 }
348
349 #[test]
350 fn test_reform() {
351 let dim = Dimension::from_vec(vec![2, 3]).unwrap();
352 let data = vec![1, 2, 3, 4, 5, 6];
353 let arr = LongArray::from_vec(data, dim, GdlType::Long).unwrap();
354
355 let reformed = arr.reform(vec![3, 2]).unwrap();
356 assert_eq!(reformed.dimensions().dims(), &[3, 2]);
357 assert_eq!(reformed.n_elements(), 6);
358 }
359}