rustmex_separated_complex/
lib.rs1#![allow(unused_unsafe)]
2use std::slice::{from_raw_parts_mut, from_raw_parts};
3use core::ops::DerefMut;
4use rustmex_core::{
5 mxArray,
6
7 num_struct,
8 data_or_dangling,
9 create_uninit_numeric_array,
10 Complexity,
11
12 numeric::{NumericArray, ComplexNumericArray, MutNumericArray, MatlabNumber},
13 pointers::{MatlabPtr, MutMatlabPtr, MxArray},
14 mappable::{*},
15 convert::{ToMatlabResult, DataShapeMismatch, FromMatlabError},
16 shim::rustmex_create_uninit_numeric_array,
17 raw::{
18 mxClassID,
19 mwSize,
20 },
21
22 MatlabClass,
23 MutMatlabClass,
24 OwnedMatlabClass,
25 NewEmpty,
26 TakeData,
27};
28
29use num_complex::Complex;
30
31use ndarray::{
32 Array,
33 Dimension,
34 ArrayD,
35 ArrayViewD,
36 ArrayViewMutD,
37 Zip,
38};
39
40use core::ffi::c_void;
41
42extern "Rust" {
46 fn rustmex_get_separated_complex(mx: *const mxArray) -> Complex<*mut c_void>;
47 fn rustmex_set_separated_complex(mx: *mut mxArray, newdata: Complex<*mut c_void>);
48}
49
50num_struct!(SeparatedComplexArray, Complexity::Complex);
51
52macro_rules! data_access {
53 ($s:ident, $t1:ty, $builder:ident) => {{
54 let numel = $s.array.numel();
55 unsafe { rustmex_get_separated_complex($s.array.deref()) }
56 .map(|elem| data_or_dangling!(elem, $t1))
57 .map(|elem| unsafe { $builder(elem, numel) } )
58 }}
59}
60
61impl<'p, T, P> NumericArray<'p> for SeparatedComplexArray<T, P> where
62 T: MatlabNumber + 'p,
63 P: MatlabPtr + 'p,
64{
65 type Data = Complex<&'p [T]>;
66 fn data(&self) -> Self::Data {
67 data_access!(self, *const T, from_raw_parts)
68 }
69}
70
71impl<'p, T, P> MutNumericArray<'p> for SeparatedComplexArray<T, P> where
72 T: MatlabNumber + 'p,
73 P: MutMatlabPtr + 'p,
74{
75 type MutData = Complex<&'p mut [T]>;
76 fn mut_data(&mut self) -> Self::MutData {
77 data_access!(self, *mut T, from_raw_parts_mut)
78 }
79}
80
81impl<T, P> TakeData<P> for SeparatedComplexArray<T, P> where
82 T: MatlabNumber,
83 P: MutMatlabPtr,
84{
85 type OwnedData = Complex<Box<[T]>>;
86 fn take_data(&mut self) -> Self::OwnedData {
87
88 let data = self.mut_data();
91
92 let data = data.map(|part| {
102 unsafe { Vec::from_raw_parts(part.as_mut_ptr(), part.len(), part.len()) }
103 .into_boxed_slice()
104 });
105
106 unsafe { rustmex_set_separated_complex(self.deref_mut(),
109 Complex::init_value(core::ptr::null_mut())) };
110
111 data
112 }
113}
114
115impl<'p, T, P> ComplexNumericArray<'p> for SeparatedComplexArray<T, P> where
116 T: MatlabNumber + 'p,
117 P: MatlabPtr + 'p,
118{
119 type CDT = T;
120}
121
122macro_rules! copy_complex {
123 ($data:ident, $f:expr) => {{
124 let mut v = Vec::with_capacity($data.len());
125 v.extend($data.iter().map($f));
126 v.into_boxed_slice()
127 }}
128}
129
130impl<T: MatlabNumber + Copy> SeparatedComplexArray<T, MxArray> {
131 pub fn new(data: Box<[Complex<T>]>, shape: &[usize]) -> ToMatlabResult<Self, Box<[Complex<T>]>> {
132 let dimprod = shape.iter().product::<usize>();
133 if dimprod != data.len() {
134 return Err(DataShapeMismatch::because_numel_shape(data));
135 }
136 let split = Complex {
137 re: copy_complex!(data, |x|x.re),
138 im: copy_complex!(data, |x|x.im)
139 };
140 Ok(Self::new_separated_unchecked(split, shape))
141 }
142}
143
144impl<T: MatlabNumber> SeparatedComplexArray<T, MxArray> {
145 pub fn new_separated(data: Complex<Box<[T]>>, shape: &[usize]) -> ToMatlabResult<Self, Complex<Box<[T]>>> {
146 if data.re.len() != data.im.len() {
147 return Err(DataShapeMismatch::because_im_re(data));
148 }
149
150 if shape.iter().product::<usize>() != data.re.len() {
151 return Err(DataShapeMismatch::because_numel_shape(data));
152 }
153
154 Ok(Self::new_separated_unchecked(data, shape))
155 }
156
157 fn new_separated_unchecked(data: Complex<Box<[T]>>, shape: &[usize]) -> Self {
158 let mx = create_uninit_numeric_array!(shape, T, Complexity::Real);
159
160 unsafe { rustmex_set_separated_complex(mx, data.map(|x| Box::into_raw(x) as *mut core::ffi::c_void)); }
161
162 Self::construct(unsafe { MxArray::assume_responsibility_ptr(mx)})
163 }
164}
165
166impl<'a, 'b, T, P> From<&'b SeparatedComplexArray<T, P>> for Complex<ArrayViewD<'a, T>> where
167 T: MatlabNumber,
168 P: MatlabPtr + 'a,
169 'b: 'a,
170{
171 fn from(num: &SeparatedComplexArray<T, P>) -> Self {
172 let data = num.data();
173 let dimensions = num.dimensions();
174
175 data.map(|part| rustmex_core::from_num_to_ndarray!(part, dimensions, ArrayViewD<T>))
176 }
177}
178
179impl<'a, T> From<SeparatedComplexArray<T, &'a mxArray>> for Complex<ArrayViewD<'a, T>> where
180 T: MatlabNumber,
181{
182 fn from(arr: SeparatedComplexArray<T, &'a mxArray>) -> Self {
183 arr.into()
184 }
185}
186
187impl<'a, 'b, T, P> From<&'b mut SeparatedComplexArray<T, P>> for Complex<ArrayViewMutD<'a, T>> where
188 T: MatlabNumber,
189 P: MutMatlabPtr + 'a,
190 'b: 'a,
191{
192 fn from(num: &mut SeparatedComplexArray<T, P>) -> Self {
193 let data: Complex<&mut[T]> = num.mut_data();
194 let dimensions = num.dimensions();
195
196 data.map(|part| rustmex_core::from_num_to_ndarray!(part, dimensions, ArrayViewMutD<T>))
197 }
198}
199
200impl<'a, T> From<SeparatedComplexArray<T, &'a mut mxArray>> for Complex<ArrayViewMutD<'a, T>> where
201 T: MatlabNumber,
202{
203 fn from(arr: SeparatedComplexArray<T, &'a mut mxArray>) -> Self {
204 arr.into()
205 }
206}
207
208
209impl<T, P> From<SeparatedComplexArray<T, P>> for ArrayD<Complex<T>> where
210 T: MatlabNumber,
211 P: MatlabPtr,
212{
213 fn from(arr: SeparatedComplexArray<T, P>) -> Self {
214 let arr: Complex<ArrayViewD<T>> = (&arr).into();
220 Zip::from(&arr.re).and(&arr.im).map_collect(|&re, &im| Complex { re, im })
221 }
222}
223
224impl<T> From<Complex<T>> for SeparatedComplexArray<T, MxArray> where T: MatlabNumber {
225 fn from(c: Complex<T>) -> Self {
226 let alloced = c.map(|val| Box::from([val]));
227 Self::new_separated_unchecked(alloced, &[1,1])
228 }
229}
230
231impl<T> From<[Complex<T>;0]> for SeparatedComplexArray<T, MxArray> where T: MatlabNumber {
232 fn from(_empty: [Complex<T>;0]) -> Self {
233 Self::new_empty()
234 }
235}
236
237impl<'a, T, D> From<Array<Complex<T>, D>> for SeparatedComplexArray<T, MxArray> where
238 T: MatlabNumber + Copy,
239 D: Dimension,
240 SeparatedComplexArray<T, MxArray>: TryFrom<Complex<Array<T, D>>>
241{
242 fn from(arr: Array<Complex<T>, D>) -> Self {
247 let arr = arr.view().split_complex();
248 let arr = <Complex<_> as Mappable<_, _>>::map(arr, |component| {
249 let mut component = component.into_owned();
250 rustmex_core::from_ndarray_to_num!(@shuffle component)
251 });
252 let dim = arr.re.raw_dim();
253 let dimview = dim.as_array_view();
254 let shape = dimview.to_slice().unwrap();
255 let arr = arr.map(|x|x.into_raw_vec().into_boxed_slice());
256 Self::new_separated_unchecked(arr, &shape)
257 }
258}
259
260impl<'a, T, D> TryFrom<Complex<Array<T, D>>> for SeparatedComplexArray<T, MxArray> where
261 T: MatlabNumber,
262 D: Dimension,
263{
264 type Error = DataShapeMismatch<Complex<Array<T,D>>>;
265 fn try_from(arr: Complex<Array<T, D>>) -> Result<Self, Self::Error> {
266 if arr.re.shape() != arr.im.shape() {
270 return Err(DataShapeMismatch::because_im_re(arr));
271 }
272
273 let arr = arr.map(|mut arr| {
274 rustmex_core::from_ndarray_to_num!(@shuffle arr)
275 });
276
277 let dim = arr.re.raw_dim();
284 let dimview = dim.as_array_view();
285 let shape = dimview.to_slice().unwrap();
286
287 Ok(Self::new_separated_unchecked(arr.map(|x| {
288 x.into_raw_vec()
289 .into_boxed_slice()
290 }), &shape))
291 }
292}