essentia_core/algorithm/
introspection.rs1use std::collections::HashMap;
2
3use essentia_sys::ffi;
4
5use crate::data::DataType;
6
7#[derive(Debug, Clone)]
8pub struct Introspection {
9 name: String,
10 category: String,
11 description: String,
12 input_infos: HashMap<String, InputOutputInfo>,
13 output_infos: HashMap<String, InputOutputInfo>,
14 parameter_infos: HashMap<String, ParameterInfo>,
15}
16
17impl Introspection {
18 pub fn from_algorithm_bridge(algorithm_bridge: &ffi::AlgorithmBridge) -> Self {
19 let input_info = algorithm_bridge
20 .get_input_infos()
21 .into_iter()
22 .map(|info| {
23 let info: InputOutputInfo = info.into();
24 (info.name.clone(), info)
25 })
26 .collect();
27
28 let output_info = algorithm_bridge
29 .get_output_infos()
30 .into_iter()
31 .map(|info| {
32 let info: InputOutputInfo = info.into();
33 (info.name.clone(), info)
34 })
35 .collect();
36
37 let parameter_info = algorithm_bridge
38 .get_parameter_infos()
39 .into_iter()
40 .map(|info| {
41 let info: ParameterInfo = info.into();
42 (info.name.clone(), info)
43 })
44 .collect();
45
46 Self {
47 name: algorithm_bridge.get_name(),
48 category: algorithm_bridge.get_category(),
49 description: algorithm_bridge.get_description(),
50 input_infos: input_info,
51 output_infos: output_info,
52 parameter_infos: parameter_info,
53 }
54 }
55
56 pub fn name(&self) -> &str {
57 &self.name
58 }
59 pub fn category(&self) -> &str {
60 &self.category
61 }
62 pub fn description(&self) -> &str {
63 &self.description
64 }
65 pub fn inputs(&self) -> impl Iterator<Item = &InputOutputInfo> {
66 self.input_infos.values()
67 }
68 pub fn outputs(&self) -> impl Iterator<Item = &InputOutputInfo> {
69 self.output_infos.values()
70 }
71 pub fn parameters(&self) -> impl Iterator<Item = &ParameterInfo> {
72 self.parameter_infos.values()
73 }
74
75 pub fn get_parameter(&self, name: &str) -> Option<&ParameterInfo> {
76 self.parameter_infos.get(name)
77 }
78 pub fn get_input(&self, name: &str) -> Option<&InputOutputInfo> {
79 self.input_infos.get(name)
80 }
81 pub fn get_output(&self, name: &str) -> Option<&InputOutputInfo> {
82 self.output_infos.get(name)
83 }
84}
85
86#[derive(Debug, Clone)]
87pub struct InputOutputInfo {
88 name: String,
89 data_type: DataType,
90 description: String,
91}
92
93impl InputOutputInfo {
94 pub fn name(&self) -> &str {
95 &self.name
96 }
97 pub fn input_output_type(&self) -> DataType {
98 self.data_type
99 }
100 pub fn description(&self) -> &str {
101 &self.description
102 }
103}
104
105impl From<ffi::InputOutputInfo> for InputOutputInfo {
106 fn from(value: ffi::InputOutputInfo) -> Self {
107 let data_type = DataType::from(value.data_type);
108
109 InputOutputInfo {
110 name: value.name,
111 data_type,
112 description: value.description,
113 }
114 }
115}
116
117#[derive(Debug, Clone, PartialEq)]
118pub enum Constraint {
119 Any,
120 PositiveReal,
121 NonNegativeReal,
122 IntRange { min: i32, max: i32 },
123 NonNegativeInt,
124 PositiveInt,
125 OneOf(Vec<String>),
126 Custom(String),
127}
128
129impl From<&str> for Constraint {
130 fn from(s: &str) -> Self {
131 if s.is_empty() {
132 return Constraint::Any;
133 }
134 match s {
135 "(0,inf)" => Constraint::PositiveReal,
136 "[0,inf)" => Constraint::NonNegativeReal,
137 s if s.starts_with('{') && s.ends_with('}') => Self::parse_one_of_constraint(s),
138 s if s.starts_with('[') && s.ends_with(']') => {
139 Self::parse_int_range_constraint(s).unwrap_or_else(|| Self::Custom(s.to_string()))
140 }
141 _ => Constraint::Custom(s.to_string()),
142 }
143 }
144}
145
146impl Constraint {
147 fn parse_one_of_constraint(s: &str) -> Self {
148 let inner = &s[1..s.len() - 1];
149 let values = inner.split(',').map(|v| v.trim().to_string()).collect();
150 Self::OneOf(values)
151 }
152 fn parse_int_range_constraint(s: &str) -> Option<Self> {
153 let inner = &s[1..s.len() - 1];
154 let (min_str, max_str) = inner.split_once(',')?;
155 let min = min_str.trim().parse::<i32>().ok()?;
156 let max = max_str.trim().parse::<i32>().ok()?;
157 Some(Self::IntRange { min, max })
158 }
159}
160
161#[derive(Debug, Clone)]
162pub struct ParameterInfo {
163 name: String,
164 data_type: DataType,
165 description: String,
166 constraint: Constraint,
167 default_value: String,
168}
169
170impl ParameterInfo {
171 pub fn name(&self) -> &str {
172 &self.name
173 }
174 pub fn parameter_type(&self) -> DataType {
175 self.data_type
176 }
177 pub fn description(&self) -> &str {
178 &self.description
179 }
180 pub fn constraint(&self) -> &Constraint {
181 &self.constraint
182 }
183 pub fn default_value(&self) -> &str {
184 &self.default_value
185 }
186 pub fn optional(&self) -> bool {
187 !self.default_value.is_empty()
188 }
189}
190
191impl From<ffi::ParameterInfo> for ParameterInfo {
192 fn from(value: ffi::ParameterInfo) -> Self {
193 let data_type = DataType::from(value.data_type);
194
195 ParameterInfo {
196 name: value.name,
197 data_type,
198 description: value.description,
199 constraint: Constraint::from(value.constraint.as_str()),
200 default_value: value.default_value,
201 }
202 }
203}