1use cxx::UniquePtr;
2use essentia_sys::ffi;
3use std::marker::PhantomData;
4
5use crate::{
6 algorithm::{
7 ComputeError, ConfigurationError, InputError, Introspection, OutputError, ParameterError,
8 ResetError,
9 },
10 data::types::HasDataType,
11 data::{DataContainer, InputOutputData, ParameterData, TryIntoDataContainer},
12 essentia::Essentia,
13 parameter_map::ParameterMap,
14};
15
16pub struct Initialized {
17 parameter_map: ParameterMap,
18}
19
20pub struct Configured;
21
22pub struct Algorithm<'a, State = Initialized> {
23 algorithm_bridge: UniquePtr<ffi::AlgorithmBridge>,
24 state: State,
25 introspection: Introspection,
26 _marker: PhantomData<&'a Essentia>,
27}
28
29impl<'a, State> Algorithm<'a, State> {
30 pub fn introspection(&self) -> &Introspection {
31 &self.introspection
32 }
33}
34
35impl<'a> Algorithm<'a, Initialized> {
36 pub(crate) fn new(algorithm_bridge: UniquePtr<ffi::AlgorithmBridge>) -> Self {
37 let introspection = Introspection::from_algorithm_bridge(&algorithm_bridge);
38
39 Self {
40 algorithm_bridge,
41 state: Initialized {
42 parameter_map: ParameterMap::new(),
43 },
44 introspection,
45 _marker: PhantomData,
46 }
47 }
48
49 pub fn parameter<T>(
50 mut self,
51 key: &str,
52 value: impl TryIntoDataContainer<T>,
53 ) -> Result<Self, ParameterError>
54 where
55 T: ParameterData + HasDataType,
56 {
57 self.set_parameter(key, value)?;
58 Ok(self)
59 }
60
61 pub fn set_parameter<T>(
62 &mut self,
63 key: &str,
64 value: impl TryIntoDataContainer<T>,
65 ) -> Result<(), ParameterError>
66 where
67 T: ParameterData + HasDataType,
68 {
69 let param_info = self.introspection.get_parameter(key).ok_or_else(|| {
70 ParameterError::ParameterNotFound {
71 parameter: key.to_string(),
72 }
73 })?;
74
75 let expected_type = T::data_type();
76 let param_data_type = param_info.parameter_type();
77
78 if param_data_type != expected_type {
79 return Err(ParameterError::TypeMismatch {
80 parameter: key.to_string(),
81 expected: expected_type,
82 actual: param_data_type,
83 });
84 }
85
86 let variant_data =
87 value
88 .try_into_data_container()
89 .map_err(|error| ParameterError::DataConversion {
90 parameter: key.to_string(),
91 source: error,
92 })?;
93
94 self.state.parameter_map.set_parameter(key, variant_data);
95
96 Ok(())
97 }
98
99 pub fn configure(mut self) -> Result<Algorithm<'a, Configured>, ConfigurationError> {
100 self.algorithm_bridge
101 .pin_mut()
102 .configure(self.state.parameter_map.parameter_map_bridge)?;
103
104 Ok(Algorithm {
105 algorithm_bridge: self.algorithm_bridge,
106 state: Configured,
107 introspection: self.introspection,
108 _marker: PhantomData,
109 })
110 }
111}
112
113impl<'a> Algorithm<'a, Configured> {
114 pub fn input<T>(
115 mut self,
116 key: &str,
117 value: impl TryIntoDataContainer<T>,
118 ) -> Result<Self, InputError>
119 where
120 T: InputOutputData + HasDataType,
121 {
122 self.set_input(key, value)?;
123 Ok(self)
124 }
125
126 pub fn set_input<T>(
127 &mut self,
128 key: &str,
129 value: impl TryIntoDataContainer<T>,
130 ) -> Result<(), InputError>
131 where
132 T: InputOutputData + HasDataType,
133 {
134 let input_info =
135 self.introspection
136 .get_input(key)
137 .ok_or_else(|| InputError::InputNotFound {
138 input: key.to_string(),
139 })?;
140
141 let expected_type = T::data_type();
142 let input_data_type = input_info.input_output_type();
143
144 if input_data_type != expected_type {
145 return Err(InputError::TypeMismatch {
146 input: key.to_string(),
147 expected: expected_type,
148 actual: input_data_type,
149 });
150 }
151
152 let variant_data =
153 value
154 .try_into_data_container()
155 .map_err(|error| InputError::DataConversion {
156 input: key.to_string(),
157 source: error,
158 })?;
159
160 let owned_ptr = variant_data.into_owned_ptr();
161
162 self.algorithm_bridge
163 .pin_mut()
164 .set_input(key, owned_ptr)
165 .map_err(|exception| InputError::Internal {
166 input: key.to_string(),
167 source: exception,
168 })?;
169
170 Ok(())
171 }
172
173 pub fn compute(&mut self) -> Result<ComputeResult<'a, '_>, ComputeError> {
174 for output in self.introspection.outputs() {
175 let data_type = output.input_output_type();
176
177 self.algorithm_bridge
178 .pin_mut()
179 .setup_output(output.name(), data_type.into())
180 .map_err(|exception| ComputeError::OutputSetup {
181 output: output.name().to_string(),
182 source: exception,
183 })?;
184 }
185
186 self.algorithm_bridge
187 .pin_mut()
188 .compute()
189 .map_err(ComputeError::Compute)?;
190
191 Ok(ComputeResult { algorithm: self })
192 }
193
194 pub fn reset(&mut self) -> Result<(), ResetError> {
195 self.algorithm_bridge
196 .pin_mut()
197 .reset()
198 .map_err(ResetError::Internal)
199 }
200}
201
202pub struct ComputeResult<'algorithm, 'result> {
203 algorithm: &'result Algorithm<'algorithm, Configured>,
204}
205
206impl<'algorithm, 'result> ComputeResult<'algorithm, 'result> {
207 pub fn output<T>(&self, key: &str) -> Result<DataContainer<'result, T>, OutputError>
208 where
209 T: InputOutputData + HasDataType,
210 {
211 let output_info = self
212 .algorithm
213 .introspection
214 .get_output(key)
215 .ok_or_else(|| OutputError::OutputNotFound {
216 output: key.to_string(),
217 })?;
218
219 let expected_type = T::data_type();
220 let output_data_type = output_info.input_output_type();
221
222 if output_data_type != expected_type {
223 return Err(OutputError::TypeMismatch {
224 output: key.to_string(),
225 expected: expected_type,
226 actual: output_data_type,
227 });
228 }
229
230 let variant_data = self
231 .algorithm
232 .algorithm_bridge
233 .get_output(key)
234 .map(|ffi_variant_data| DataContainer::new_borrowed(ffi_variant_data))
235 .map_err(|exception| OutputError::Internal {
236 output: key.to_string(),
237 source: exception,
238 })?;
239
240 Ok(variant_data)
241 }
242}