1use super::error::{ParameterError, ParameterResult};
10use std::collections::HashMap;
11use std::fmt;
12use std::str::FromStr;
13
14#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
20pub struct ParameterId {
21 name: String,
22}
23
24impl ParameterId {
25 pub const MAX_LEN: usize = 64;
27
28 pub fn new(name: impl Into<String>) -> ParameterResult<Self> {
36 let name = name.into();
37
38 if name.is_empty() {
39 return Err(ParameterError::Empty);
40 }
41
42 if name.len() > Self::MAX_LEN {
43 return Err(ParameterError::TooLong { max: Self::MAX_LEN });
44 }
45
46 let first = name.chars().next().unwrap();
47 if !first.is_ascii_alphabetic() {
48 return Err(ParameterError::MustStartWithLetter);
49 }
50
51 for c in name.chars() {
52 if !c.is_ascii_alphanumeric() && c != '_' {
53 return Err(ParameterError::InvalidCharacter(c));
54 }
55 }
56
57 Ok(Self { name })
58 }
59
60 pub fn as_str(&self) -> &str {
62 &self.name
63 }
64
65 pub fn into_string(self) -> String {
67 self.name
68 }
69}
70
71impl AsRef<str> for ParameterId {
72 fn as_ref(&self) -> &str {
73 &self.name
74 }
75}
76
77impl fmt::Display for ParameterId {
78 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79 write!(f, "{}", self.name)
80 }
81}
82
83impl FromStr for ParameterId {
84 type Err = ParameterError;
85
86 fn from_str(s: &str) -> Result<Self, Self::Err> {
87 ParameterId::new(s)
88 }
89}
90
91#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
97pub enum ParamType {
98 Float,
100
101 Int,
103
104 Bool,
106
107 String,
109
110 Choice,
112}
113
114impl ParamType {
115 pub fn name(&self) -> &'static str {
117 match self {
118 Self::Float => "float",
119 Self::Int => "int",
120 Self::Bool => "bool",
121 Self::String => "string",
122 Self::Choice => "choice",
123 }
124 }
125}
126
127impl fmt::Display for ParamType {
128 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129 write!(f, "{}", self.name())
130 }
131}
132
133#[derive(Debug, Clone, PartialEq)]
139#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
140pub enum ParamValue {
141 Float(f32),
143
144 Int(i32),
146
147 Bool(bool),
149
150 String(String),
152
153 Choice(String),
155}
156
157impl ParamValue {
158 pub fn param_type(&self) -> ParamType {
160 match self {
161 Self::Float(_) => ParamType::Float,
162 Self::Int(_) => ParamType::Int,
163 Self::Bool(_) => ParamType::Bool,
164 Self::String(_) => ParamType::String,
165 Self::Choice(_) => ParamType::Choice,
166 }
167 }
168
169 pub fn as_f32(&self) -> Option<f32> {
171 match self {
172 Self::Float(f) => Some(*f),
173 Self::Int(i) => Some(*i as f32),
174 Self::Bool(b) => Some(if *b { 1.0 } else { 0.0 }),
175 _ => None,
176 }
177 }
178
179 pub fn as_i32(&self) -> Option<i32> {
181 match self {
182 Self::Float(f) => Some(*f as i32),
183 Self::Int(i) => Some(*i),
184 Self::Bool(b) => Some(if *b { 1 } else { 0 }),
185 _ => None,
186 }
187 }
188
189 pub fn as_bool(&self) -> Option<bool> {
191 match self {
192 Self::Bool(b) => Some(*b),
193 Self::Float(f) => Some(*f > 0.5),
194 Self::Int(i) => Some(*i > 0),
195 _ => None,
196 }
197 }
198
199 pub fn as_str(&self) -> Option<&str> {
201 match self {
202 Self::String(s) | Self::Choice(s) => Some(s.as_str()),
203 _ => None,
204 }
205 }
206}
207
208#[derive(Debug, Clone, PartialEq)]
214pub struct ParamRange {
215 pub min: Option<f32>,
217
218 pub max: Option<f32>,
220
221 pub step: Option<f32>,
223}
224
225impl ParamRange {
226 pub fn new() -> Self {
228 Self {
229 min: None,
230 max: None,
231 step: None,
232 }
233 }
234
235 pub fn with_min(mut self, min: f32) -> Self {
237 self.min = Some(min);
238 self
239 }
240
241 pub fn with_max(mut self, max: f32) -> Self {
243 self.max = Some(max);
244 self
245 }
246
247 pub fn with_step(mut self, step: f32) -> Self {
249 self.step = Some(step);
250 self
251 }
252
253 pub fn contains(&self, value: f32) -> bool {
255 if let Some(min) = self.min {
256 if value < min {
257 return false;
258 }
259 }
260 if let Some(max) = self.max {
261 if value > max {
262 return false;
263 }
264 }
265 true
266 }
267
268 pub fn clamp(&self, value: f32) -> f32 {
270 let mut value = value;
271 if let Some(min) = self.min {
272 value = value.max(min);
273 }
274 if let Some(max) = self.max {
275 value = value.min(max);
276 }
277 value
278 }
279}
280
281impl Default for ParamRange {
282 fn default() -> Self {
283 Self::new()
284 }
285}
286
287#[derive(Debug, Clone, PartialEq)]
293pub struct ParamMetadata {
294 pub name: String,
296
297 pub description: String,
299
300 pub typ: ParamType,
302
303 pub default: ParamValue,
305
306 pub range: ParamRange,
308
309 pub unit: Option<String>,
311
312 pub choices: Option<Vec<(String, f32)>>,
314}
315
316impl ParamMetadata {
317 pub fn new(name: impl Into<String>, typ: ParamType, default: ParamValue) -> Self {
319 Self {
320 name: name.into(),
321 description: String::new(),
322 typ,
323 default,
324 range: ParamRange::default(),
325 unit: None,
326 choices: None,
327 }
328 }
329
330 pub fn with_description(mut self, description: impl Into<String>) -> Self {
332 self.description = description.into();
333 self
334 }
335
336 pub fn with_range(mut self, min: f32, max: f32, step: f32) -> Self {
338 self.range = ParamRange::new()
339 .with_min(min)
340 .with_max(max)
341 .with_step(step);
342 self
343 }
344
345 pub fn with_unit(mut self, unit: impl Into<String>) -> Self {
347 self.unit = Some(unit.into());
348 self
349 }
350
351 pub fn with_choices(mut self, choices: Vec<(String, f32)>) -> Self {
353 self.choices = Some(choices);
354 self
355 }
356}
357
358#[derive(Debug, Clone, Default)]
370#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
371pub struct NodeParams {
372 pub sample_rate: f32,
374
375 pub parameters: HashMap<String, ParamValue>,
377}
378
379impl NodeParams {
380 pub fn new(sample_rate: f32) -> Self {
382 Self {
383 sample_rate,
384 parameters: HashMap::new(),
385 }
386 }
387
388 pub fn with(mut self, key: impl Into<String>, value: ParamValue) -> Self {
390 self.parameters.insert(key.into(), value);
391 self
392 }
393
394 pub fn get(&self, key: &str) -> Option<&ParamValue> {
396 self.parameters.get(key)
397 }
398
399 pub fn insert(&mut self, key: impl Into<String>, value: ParamValue) -> Option<ParamValue> {
401 self.parameters.insert(key.into(), value)
402 }
403
404 pub fn remove(&mut self, key: &str) -> Option<ParamValue> {
406 self.parameters.remove(key)
407 }
408
409 pub fn contains(&self, key: &str) -> bool {
411 self.parameters.contains_key(key)
412 }
413
414 pub fn len(&self) -> usize {
416 self.parameters.len()
417 }
418
419 pub fn is_empty(&self) -> bool {
421 self.parameters.is_empty()
422 }
423
424 pub fn get_f32(&self, key: &str, default: f32) -> f32 {
426 self.parameters
427 .get(key)
428 .and_then(|v| v.as_f32())
429 .unwrap_or(default)
430 }
431
432 pub fn get_i32(&self, key: &str, default: i32) -> i32 {
434 self.parameters
435 .get(key)
436 .and_then(|v| v.as_i32())
437 .unwrap_or(default)
438 }
439
440 pub fn get_bool(&self, key: &str, default: bool) -> bool {
442 self.parameters
443 .get(key)
444 .and_then(|v| v.as_bool())
445 .unwrap_or(default)
446 }
447}
448
449#[cfg(test)]
454mod tests {
455 use super::*;
456
457 #[test]
458 fn test_parameter_id_valid() {
459 assert!(ParameterId::new("gain").is_ok());
460 assert!(ParameterId::new("cutoff_freq").is_ok());
461 assert!(ParameterId::new("delay_time_2").is_ok());
462 }
463
464 #[test]
465 fn test_parameter_id_invalid() {
466 assert!(ParameterId::new("").is_err());
467 assert!(ParameterId::new("1gain").is_err());
468 assert!(ParameterId::new("_gain").is_err());
469
470 let long_name = "a".repeat(ParameterId::MAX_LEN + 1);
471 assert!(ParameterId::new(long_name).is_err());
472 }
473
474 #[test]
475 fn test_param_value_conversion() {
476 let f = ParamValue::Float(42.0);
477 assert_eq!(f.as_f32(), Some(42.0));
478 assert_eq!(f.as_i32(), Some(42));
479 assert_eq!(f.as_bool(), Some(true));
480
481 let i = ParamValue::Int(0);
482 assert_eq!(i.as_f32(), Some(0.0));
483 assert_eq!(i.as_i32(), Some(0));
484 assert_eq!(i.as_bool(), Some(false));
485 }
486}