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
200#[derive(Debug, Clone, PartialEq)]
206pub struct ParamRange {
207 pub min: Option<f32>,
209
210 pub max: Option<f32>,
212
213 pub step: Option<f32>,
215}
216
217impl ParamRange {
218 pub fn new() -> Self {
220 Self {
221 min: None,
222 max: None,
223 step: None,
224 }
225 }
226
227 pub fn with_min(mut self, min: f32) -> Self {
229 self.min = Some(min);
230 self
231 }
232
233 pub fn with_max(mut self, max: f32) -> Self {
235 self.max = Some(max);
236 self
237 }
238
239 pub fn with_step(mut self, step: f32) -> Self {
241 self.step = Some(step);
242 self
243 }
244
245 pub fn contains(&self, value: f32) -> bool {
247 if let Some(min) = self.min {
248 if value < min {
249 return false;
250 }
251 }
252 if let Some(max) = self.max {
253 if value > max {
254 return false;
255 }
256 }
257 true
258 }
259
260 pub fn clamp(&self, value: f32) -> f32 {
262 let mut value = value;
263 if let Some(min) = self.min {
264 value = value.max(min);
265 }
266 if let Some(max) = self.max {
267 value = value.min(max);
268 }
269 value
270 }
271}
272
273impl Default for ParamRange {
274 fn default() -> Self {
275 Self::new()
276 }
277}
278
279#[derive(Debug, Clone, PartialEq)]
285pub struct ParamMetadata {
286 pub name: String,
288
289 pub description: String,
291
292 pub typ: ParamType,
294
295 pub default: ParamValue,
297
298 pub range: ParamRange,
300
301 pub unit: Option<String>,
303
304 pub choices: Option<Vec<(String, f32)>>,
306}
307
308impl ParamMetadata {
309 pub fn new(name: impl Into<String>, typ: ParamType, default: ParamValue) -> Self {
311 Self {
312 name: name.into(),
313 description: String::new(),
314 typ,
315 default,
316 range: ParamRange::default(),
317 unit: None,
318 choices: None,
319 }
320 }
321
322 pub fn with_description(mut self, description: impl Into<String>) -> Self {
324 self.description = description.into();
325 self
326 }
327
328 pub fn with_range(mut self, min: f32, max: f32, step: f32) -> Self {
330 self.range = ParamRange::new()
331 .with_min(min)
332 .with_max(max)
333 .with_step(step);
334 self
335 }
336
337 pub fn with_unit(mut self, unit: impl Into<String>) -> Self {
339 self.unit = Some(unit.into());
340 self
341 }
342
343 pub fn with_choices(mut self, choices: Vec<(String, f32)>) -> Self {
345 self.choices = Some(choices);
346 self
347 }
348}
349
350#[derive(Debug, Clone, Default)]
362#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
363pub struct NodeParams {
364 pub sample_rate: f32,
366
367 pub parameters: HashMap<String, ParamValue>,
369}
370
371impl NodeParams {
372 pub fn new(sample_rate: f32) -> Self {
374 Self {
375 sample_rate,
376 parameters: HashMap::new(),
377 }
378 }
379
380 pub fn with(mut self, key: impl Into<String>, value: ParamValue) -> Self {
382 self.parameters.insert(key.into(), value);
383 self
384 }
385
386 pub fn get(&self, key: &str) -> Option<&ParamValue> {
388 self.parameters.get(key)
389 }
390
391 pub fn insert(&mut self, key: impl Into<String>, value: ParamValue) -> Option<ParamValue> {
393 self.parameters.insert(key.into(), value)
394 }
395
396 pub fn remove(&mut self, key: &str) -> Option<ParamValue> {
398 self.parameters.remove(key)
399 }
400
401 pub fn contains(&self, key: &str) -> bool {
403 self.parameters.contains_key(key)
404 }
405
406 pub fn len(&self) -> usize {
408 self.parameters.len()
409 }
410
411 pub fn is_empty(&self) -> bool {
413 self.parameters.is_empty()
414 }
415
416 pub fn get_f32(&self, key: &str, default: f32) -> f32 {
418 self.parameters
419 .get(key)
420 .and_then(|v| v.as_f32())
421 .unwrap_or(default)
422 }
423
424 pub fn get_i32(&self, key: &str, default: i32) -> i32 {
426 self.parameters
427 .get(key)
428 .and_then(|v| v.as_i32())
429 .unwrap_or(default)
430 }
431
432 pub fn get_bool(&self, key: &str, default: bool) -> bool {
434 self.parameters
435 .get(key)
436 .and_then(|v| v.as_bool())
437 .unwrap_or(default)
438 }
439}
440
441#[cfg(test)]
446mod tests {
447 use super::*;
448
449 #[test]
450 fn test_parameter_id_valid() {
451 assert!(ParameterId::new("gain").is_ok());
452 assert!(ParameterId::new("cutoff_freq").is_ok());
453 assert!(ParameterId::new("delay_time_2").is_ok());
454 }
455
456 #[test]
457 fn test_parameter_id_invalid() {
458 assert!(ParameterId::new("").is_err());
459 assert!(ParameterId::new("1gain").is_err());
460 assert!(ParameterId::new("_gain").is_err());
461
462 let long_name = "a".repeat(ParameterId::MAX_LEN + 1);
463 assert!(ParameterId::new(long_name).is_err());
464 }
465
466 #[test]
467 fn test_param_value_conversion() {
468 let f = ParamValue::Float(42.0);
469 assert_eq!(f.as_f32(), Some(42.0));
470 assert_eq!(f.as_i32(), Some(42));
471 assert_eq!(f.as_bool(), Some(true));
472
473 let i = ParamValue::Int(0);
474 assert_eq!(i.as_f32(), Some(0.0));
475 assert_eq!(i.as_i32(), Some(0));
476 assert_eq!(i.as_bool(), Some(false));
477 }
478}