Skip to main content

essentia_core/data/
conversion_into.rs

1use essentia_sys::ffi;
2use ndarray::{Array2, Array4};
3use std::collections::HashMap;
4
5use crate::{ConversionError, DataContainer, phantom};
6
7pub trait IntoDataContainer<T> {
8    fn into_data_container(self) -> DataContainer<'static, T>;
9}
10
11pub trait TryIntoDataContainer<T> {
12    fn try_into_data_container(self) -> Result<DataContainer<'static, T>, ConversionError>;
13}
14
15impl<T, V> TryIntoDataContainer<T> for V
16where
17    V: IntoDataContainer<T>,
18{
19    fn try_into_data_container(self) -> Result<DataContainer<'static, T>, ConversionError> {
20        Ok(self.into_data_container())
21    }
22}
23
24impl<'a, T> IntoDataContainer<T> for DataContainer<'a, T> {
25    fn into_data_container(self) -> DataContainer<'static, T> {
26        let owned_ptr = self.into_owned_ptr();
27        DataContainer::new_owned(owned_ptr)
28    }
29}
30
31impl IntoDataContainer<phantom::Bool> for bool {
32    fn into_data_container(self) -> DataContainer<'static, phantom::Bool> {
33        DataContainer::new_owned(ffi::create_data_container_from_bool(self))
34    }
35}
36
37impl IntoDataContainer<phantom::String> for &str {
38    fn into_data_container(self) -> DataContainer<'static, phantom::String> {
39        DataContainer::new_owned(ffi::create_data_container_from_string(self))
40    }
41}
42
43impl IntoDataContainer<phantom::Int> for i32 {
44    fn into_data_container(self) -> DataContainer<'static, phantom::Int> {
45        DataContainer::new_owned(ffi::create_data_container_from_int(self))
46    }
47}
48
49impl IntoDataContainer<phantom::Float> for f32 {
50    fn into_data_container(self) -> DataContainer<'static, phantom::Float> {
51        DataContainer::new_owned(ffi::create_data_container_from_float(self))
52    }
53}
54
55impl IntoDataContainer<phantom::UnsignedInt> for u32 {
56    fn into_data_container(self) -> DataContainer<'static, phantom::UnsignedInt> {
57        DataContainer::new_owned(ffi::create_data_container_from_unsigned_int(self))
58    }
59}
60
61impl IntoDataContainer<phantom::Long> for i64 {
62    fn into_data_container(self) -> DataContainer<'static, phantom::Long> {
63        DataContainer::new_owned(ffi::create_data_container_from_long(self))
64    }
65}
66
67impl IntoDataContainer<phantom::StereoSample> for ffi::StereoSample {
68    fn into_data_container(self) -> DataContainer<'static, phantom::StereoSample> {
69        DataContainer::new_owned(ffi::create_data_container_from_stereo_sample(self))
70    }
71}
72
73impl IntoDataContainer<phantom::Complex> for num::Complex<f32> {
74    fn into_data_container(self) -> DataContainer<'static, phantom::Complex> {
75        DataContainer::new_owned(ffi::create_data_container_from_complex(ffi::Complex {
76            real: self.re,
77            imag: self.im,
78        }))
79    }
80}
81
82impl IntoDataContainer<phantom::TensorFloat> for &Array4<f32> {
83    fn into_data_container(self) -> DataContainer<'static, phantom::TensorFloat> {
84        let slice = self.as_slice().expect("Array must be contiguous");
85        let shape = [
86            self.shape()[0],
87            self.shape()[1],
88            self.shape()[2],
89            self.shape()[3],
90        ];
91
92        DataContainer::new_owned(ffi::create_data_container_from_tensor_float(
93            ffi::TensorFloat {
94                slice,
95                shape: &shape,
96            },
97        ))
98    }
99}
100
101impl IntoDataContainer<phantom::VectorBool> for &[bool] {
102    fn into_data_container(self) -> DataContainer<'static, phantom::VectorBool> {
103        DataContainer::new_owned(ffi::create_data_container_from_vector_bool(self))
104    }
105}
106
107impl IntoDataContainer<phantom::VectorInt> for &[i32] {
108    fn into_data_container(self) -> DataContainer<'static, phantom::VectorInt> {
109        DataContainer::new_owned(ffi::create_data_container_from_vector_int(self))
110    }
111}
112
113impl IntoDataContainer<phantom::VectorString> for &[&str] {
114    fn into_data_container(self) -> DataContainer<'static, phantom::VectorString> {
115        DataContainer::new_owned(ffi::create_data_container_from_vector_string(self))
116    }
117}
118
119impl IntoDataContainer<phantom::VectorFloat> for &[f32] {
120    fn into_data_container(self) -> DataContainer<'static, phantom::VectorFloat> {
121        DataContainer::new_owned(ffi::create_data_container_from_vector_float(self))
122    }
123}
124
125impl IntoDataContainer<phantom::VectorStereoSample> for &[ffi::StereoSample] {
126    fn into_data_container(self) -> DataContainer<'static, phantom::VectorStereoSample> {
127        DataContainer::new_owned(ffi::create_data_container_from_vector_stereo_sample(self))
128    }
129}
130
131impl IntoDataContainer<phantom::VectorComplex> for &[num::Complex<f32>] {
132    fn into_data_container(self) -> DataContainer<'static, phantom::VectorComplex> {
133        let ffi_vec: Vec<ffi::Complex> = self
134            .iter()
135            .map(|c| ffi::Complex {
136                real: c.re,
137                imag: c.im,
138            })
139            .collect();
140        DataContainer::new_owned(ffi::create_data_container_from_vector_complex(&ffi_vec))
141    }
142}
143
144impl IntoDataContainer<phantom::VectorVectorFloat> for &[Vec<f32>] {
145    fn into_data_container(self) -> DataContainer<'static, phantom::VectorVectorFloat> {
146        DataContainer::new_owned(ffi::create_data_container_from_vector_vector_float(
147            self.iter()
148                .map(|item| ffi::SliceFloat {
149                    slice: item.as_slice(),
150                })
151                .collect(),
152        ))
153    }
154}
155
156impl IntoDataContainer<phantom::MatrixFloat> for &Array2<f32> {
157    fn into_data_container(self) -> DataContainer<'static, phantom::MatrixFloat> {
158        let slice = self.as_slice().expect("Array must be contiguous");
159        let (dim1, dim2) = self.dim();
160
161        DataContainer::new_owned(ffi::create_data_container_from_matrix_float(
162            ffi::MatrixFloat { slice, dim1, dim2 },
163        ))
164    }
165}
166
167impl IntoDataContainer<phantom::VectorVectorString> for &[&[&str]] {
168    fn into_data_container(self) -> DataContainer<'static, phantom::VectorVectorString> {
169        DataContainer::new_owned(ffi::create_data_container_from_vector_vector_string(
170            self.iter()
171                .map(|item| ffi::VecString {
172                    vec: item.iter().map(|s| s.to_string()).collect(),
173                })
174                .collect(),
175        ))
176    }
177}
178
179impl IntoDataContainer<phantom::VectorVectorStereoSample> for &[&[ffi::StereoSample]] {
180    fn into_data_container(self) -> DataContainer<'static, phantom::VectorVectorStereoSample> {
181        DataContainer::new_owned(ffi::create_data_container_from_vector_vector_stereo_sample(
182            self.iter()
183                .map(|item| ffi::SliceStereoSample { slice: item })
184                .collect(),
185        ))
186    }
187}
188
189impl IntoDataContainer<phantom::VectorVectorComplex> for &[Vec<num::Complex<f32>>] {
190    fn into_data_container(self) -> DataContainer<'static, phantom::VectorVectorComplex> {
191        DataContainer::new_owned(ffi::create_data_container_from_vector_vector_complex(
192            self.iter()
193                .map(|item| ffi::VecComplex {
194                    vec: item
195                        .iter()
196                        .map(|c| ffi::Complex {
197                            real: c.re,
198                            imag: c.im,
199                        })
200                        .collect(),
201                })
202                .collect(),
203        ))
204    }
205}
206
207impl IntoDataContainer<phantom::VectorMatrixFloat> for &[Array2<f32>] {
208    fn into_data_container(self) -> DataContainer<'static, phantom::VectorMatrixFloat> {
209        DataContainer::new_owned(ffi::create_data_container_from_vector_matrix_float(
210            self.iter()
211                .map(|array| {
212                    let slice = array.as_slice().expect("Array must be contiguous");
213                    let (dim1, dim2) = array.dim();
214                    ffi::MatrixFloat { slice, dim1, dim2 }
215                })
216                .collect(),
217        ))
218    }
219}
220
221impl IntoDataContainer<phantom::MapVectorFloat> for &HashMap<String, Vec<f32>> {
222    fn into_data_container(self) -> DataContainer<'static, phantom::MapVectorFloat> {
223        DataContainer::new_owned(ffi::create_data_container_from_map_vector_float(
224            self.iter()
225                .map(|(key, vec)| ffi::MapEntryVectorFloat {
226                    key: key.clone(),
227                    value: vec.as_slice(),
228                })
229                .collect(),
230        ))
231    }
232}
233
234impl IntoDataContainer<phantom::MapVectorString> for &HashMap<String, Vec<String>> {
235    fn into_data_container(self) -> DataContainer<'static, phantom::MapVectorString> {
236        DataContainer::new_owned(ffi::create_data_container_from_map_vector_string(
237            self.iter()
238                .map(|(key, vec)| ffi::MapEntryVectorString {
239                    key: key.clone(),
240                    value: vec.clone(),
241                })
242                .collect(),
243        ))
244    }
245}
246
247impl IntoDataContainer<phantom::MapVectorInt> for &HashMap<String, Vec<i32>> {
248    fn into_data_container(self) -> DataContainer<'static, phantom::MapVectorInt> {
249        DataContainer::new_owned(ffi::create_data_container_from_map_vector_int(
250            self.iter()
251                .map(|(key, vec)| ffi::MapEntryVectorInt {
252                    key: key.clone(),
253                    value: vec.as_slice(),
254                })
255                .collect(),
256        ))
257    }
258}
259
260impl IntoDataContainer<phantom::MapVectorComplex> for &HashMap<String, Vec<num::Complex<f32>>> {
261    fn into_data_container(self) -> DataContainer<'static, phantom::MapVectorComplex> {
262        let converted_data: Vec<(String, Vec<ffi::Complex>)> = self
263            .iter()
264            .map(|(key, vec)| {
265                (
266                    key.clone(),
267                    vec.iter()
268                        .map(|c| ffi::Complex {
269                            real: c.re,
270                            imag: c.im,
271                        })
272                        .collect(),
273                )
274            })
275            .collect();
276
277        let entries: Vec<ffi::MapEntryVectorComplex> = converted_data
278            .iter()
279            .map(|(key, ffi_vec)| ffi::MapEntryVectorComplex {
280                key: key.clone(),
281                value: ffi_vec.as_slice(),
282            })
283            .collect();
284
285        DataContainer::new_owned(ffi::create_data_container_from_map_vector_complex(entries))
286    }
287}
288
289impl IntoDataContainer<phantom::MapFloat> for &HashMap<String, f32> {
290    fn into_data_container(self) -> DataContainer<'static, phantom::MapFloat> {
291        DataContainer::new_owned(ffi::create_data_container_from_map_float(
292            self.iter()
293                .map(|(key, &val)| ffi::MapEntryFloat {
294                    key: key.clone(),
295                    value: val,
296                })
297                .collect(),
298        ))
299    }
300}
301
302impl TryIntoDataContainer<phantom::MatrixFloat> for &[Vec<f32>] {
303    fn try_into_data_container(
304        self,
305    ) -> Result<DataContainer<'static, phantom::MatrixFloat>, ConversionError> {
306        if self.is_empty() {
307            return Err(ConversionError::InvalidFormat {
308                message: "Cannot create matrix from empty vector".to_string(),
309            });
310        }
311
312        let expected_cols = self[0].len();
313        if expected_cols == 0 {
314            return Err(ConversionError::InvalidFormat {
315                message: "Cannot create matrix from empty rows".to_string(),
316            });
317        }
318
319        for (row_idx, row) in self.iter().enumerate() {
320            if row.len() != expected_cols {
321                return Err(ConversionError::InvalidFormat {
322                    message: format!(
323                        "Non-rectangular matrix: row {} has {} elements, expected {}",
324                        row_idx,
325                        row.len(),
326                        expected_cols
327                    ),
328                });
329            }
330        }
331
332        let mut flat_data = Vec::with_capacity(self.len() * expected_cols);
333        for row in self {
334            flat_data.extend(row);
335        }
336
337        let dim1 = flat_data.len() / expected_cols;
338        let dim2 = expected_cols;
339
340        Ok(DataContainer::new_owned(
341            ffi::create_data_container_from_matrix_float(ffi::MatrixFloat {
342                slice: &flat_data,
343                dim1,
344                dim2,
345            }),
346        ))
347    }
348}
349
350impl IntoDataContainer<phantom::Pool> for crate::pool::Pool {
351    fn into_data_container(self) -> DataContainer<'static, phantom::Pool> {
352        DataContainer::new_owned(ffi::create_data_container_from_pool(self.into_owned_ptr()))
353    }
354}