1use super::error::{ParameterError, ParameterResult};
10use std::collections::HashMap;
11use std::fmt;
12use std::str::FromStr;
13use std::sync::Arc;
14
15#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
21pub struct ParameterId {
22 name: String,
23}
24
25impl ParameterId {
26 pub const MAX_LEN: usize = 64;
28
29 pub fn new(name: impl Into<String>) -> ParameterResult<Self> {
37 let name = name.into();
38
39 if name.is_empty() {
40 return Err(ParameterError::Empty);
41 }
42
43 if name.len() > Self::MAX_LEN {
44 return Err(ParameterError::TooLong { max: Self::MAX_LEN });
45 }
46
47 let first = name.chars().next().unwrap();
48 if !first.is_ascii_alphabetic() {
49 return Err(ParameterError::MustStartWithLetter);
50 }
51
52 for c in name.chars() {
53 if !c.is_ascii_alphanumeric() && c != '_' {
54 return Err(ParameterError::InvalidCharacter(c));
55 }
56 }
57
58 Ok(Self { name })
59 }
60
61 pub fn as_str(&self) -> &str {
63 &self.name
64 }
65
66 pub fn into_string(self) -> String {
68 self.name
69 }
70}
71
72impl AsRef<str> for ParameterId {
73 fn as_ref(&self) -> &str {
74 &self.name
75 }
76}
77
78impl fmt::Display for ParameterId {
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 write!(f, "{}", self.name)
81 }
82}
83
84impl FromStr for ParameterId {
85 type Err = ParameterError;
86
87 fn from_str(s: &str) -> Result<Self, Self::Err> {
88 ParameterId::new(s)
89 }
90}
91
92#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
98pub enum ParamType {
99 Float,
101
102 Int,
104
105 Bool,
107
108 String,
110
111 Choice,
113
114 Bytes,
116
117 Slab,
119}
120
121impl ParamType {
122 pub fn name(&self) -> &'static str {
124 match self {
125 Self::Float => "float",
126 Self::Int => "int",
127 Self::Bool => "bool",
128 Self::String => "string",
129 Self::Choice => "choice",
130 Self::Bytes => "bytes",
131 Self::Slab => "slab",
132 }
133 }
134}
135
136impl fmt::Display for ParamType {
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 write!(f, "{}", self.name())
139 }
140}
141
142#[derive(Debug, Clone)]
152pub struct SignalSlab {
153 pub channels: Vec<Box<[f32]>>,
156 pub sample_rate: f32,
158 pub num_frames: usize,
160}
161
162#[derive(Debug, Clone)]
168#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
169pub enum ParamValue {
170 Float(f32),
172
173 Int(i32),
175
176 Bool(bool),
178
179 String(String),
181
182 Choice(String),
184
185 Bytes(Vec<u8>),
187
188 #[cfg_attr(feature = "serde", serde(skip))]
193 SignalSlab(Arc<SignalSlab>),
194}
195
196impl PartialEq for ParamValue {
197 fn eq(&self, other: &Self) -> bool {
198 match (self, other) {
199 (Self::Float(a), Self::Float(b)) => a == b,
200 (Self::Int(a), Self::Int(b)) => a == b,
201 (Self::Bool(a), Self::Bool(b)) => a == b,
202 (Self::String(a), Self::String(b)) => a == b,
203 (Self::Choice(a), Self::Choice(b)) => a == b,
204 (Self::Bytes(a), Self::Bytes(b)) => a == b,
205 (Self::SignalSlab(a), Self::SignalSlab(b)) => Arc::ptr_eq(a, b),
206 _ => false,
207 }
208 }
209}
210
211impl ParamValue {
212 pub fn param_type(&self) -> ParamType {
214 match self {
215 Self::Float(_) => ParamType::Float,
216 Self::Int(_) => ParamType::Int,
217 Self::Bool(_) => ParamType::Bool,
218 Self::String(_) => ParamType::String,
219 Self::Choice(_) => ParamType::Choice,
220 Self::Bytes(_) => ParamType::Bytes,
221 Self::SignalSlab(_) => ParamType::Slab,
222 }
223 }
224
225 pub fn as_f32(&self) -> Option<f32> {
227 match self {
228 Self::Float(f) => Some(*f),
229 Self::Int(i) => Some(*i as f32),
230 Self::Bool(b) => Some(if *b { 1.0 } else { 0.0 }),
231 _ => None,
232 }
233 }
234
235 pub fn as_i32(&self) -> Option<i32> {
237 match self {
238 Self::Float(f) => Some(*f as i32),
239 Self::Int(i) => Some(*i),
240 Self::Bool(b) => Some(if *b { 1 } else { 0 }),
241 _ => None,
242 }
243 }
244
245 pub fn as_bool(&self) -> Option<bool> {
247 match self {
248 Self::Bool(b) => Some(*b),
249 Self::Float(f) => Some(*f > 0.5),
250 Self::Int(i) => Some(*i > 0),
251 _ => None,
252 }
253 }
254
255 pub fn as_str(&self) -> Option<&str> {
257 match self {
258 Self::String(s) | Self::Choice(s) => Some(s.as_str()),
259 _ => None,
260 }
261 }
262
263 pub fn as_bytes(&self) -> Option<&[u8]> {
265 match self {
266 Self::Bytes(v) => Some(v.as_slice()),
267 _ => None,
268 }
269 }
270}
271
272#[derive(Debug, Clone, PartialEq)]
278pub struct ParamRange {
279 pub min: Option<f32>,
281
282 pub max: Option<f32>,
284
285 pub step: Option<f32>,
287}
288
289impl ParamRange {
290 pub fn new() -> Self {
292 Self {
293 min: None,
294 max: None,
295 step: None,
296 }
297 }
298
299 pub fn with_min(mut self, min: f32) -> Self {
301 self.min = Some(min);
302 self
303 }
304
305 pub fn with_max(mut self, max: f32) -> Self {
307 self.max = Some(max);
308 self
309 }
310
311 pub fn with_step(mut self, step: f32) -> Self {
313 self.step = Some(step);
314 self
315 }
316
317 pub fn contains(&self, value: f32) -> bool {
319 if let Some(min) = self.min {
320 if value < min {
321 return false;
322 }
323 }
324 if let Some(max) = self.max {
325 if value > max {
326 return false;
327 }
328 }
329 true
330 }
331
332 pub fn clamp(&self, value: f32) -> f32 {
334 let mut value = value;
335 if let Some(min) = self.min {
336 value = value.max(min);
337 }
338 if let Some(max) = self.max {
339 value = value.min(max);
340 }
341 value
342 }
343}
344
345impl Default for ParamRange {
346 fn default() -> Self {
347 Self::new()
348 }
349}
350
351#[derive(Debug, Clone, PartialEq)]
357pub struct ParamMetadata {
358 pub name: String,
360
361 pub description: String,
363
364 pub typ: ParamType,
366
367 pub default: ParamValue,
369
370 pub range: ParamRange,
372
373 pub unit: Option<String>,
375
376 pub choices: Option<Vec<(String, f32)>>,
378}
379
380impl ParamMetadata {
381 pub fn new(name: impl Into<String>, typ: ParamType, default: ParamValue) -> Self {
383 Self {
384 name: name.into(),
385 description: String::new(),
386 typ,
387 default,
388 range: ParamRange::default(),
389 unit: None,
390 choices: None,
391 }
392 }
393
394 pub fn with_description(mut self, description: impl Into<String>) -> Self {
396 self.description = description.into();
397 self
398 }
399
400 pub fn with_range(mut self, min: f32, max: f32, step: f32) -> Self {
402 self.range = ParamRange::new()
403 .with_min(min)
404 .with_max(max)
405 .with_step(step);
406 self
407 }
408
409 pub fn with_unit(mut self, unit: impl Into<String>) -> Self {
411 self.unit = Some(unit.into());
412 self
413 }
414
415 pub fn with_choices(mut self, choices: Vec<(String, f32)>) -> Self {
417 self.choices = Some(choices);
418 self
419 }
420}
421
422#[derive(Debug, Clone, Default)]
434#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
435pub struct Params {
436 pub sample_rate: f32,
438
439 pub parameters: HashMap<String, ParamValue>,
441}
442
443impl Params {
444 pub fn new(sample_rate: f32) -> Self {
446 Self {
447 sample_rate,
448 parameters: HashMap::new(),
449 }
450 }
451
452 pub fn with(mut self, key: impl Into<String>, value: ParamValue) -> Self {
454 self.parameters.insert(key.into(), value);
455 self
456 }
457
458 pub fn get(&self, key: &str) -> Option<&ParamValue> {
460 self.parameters.get(key)
461 }
462
463 pub fn insert(&mut self, key: impl Into<String>, value: ParamValue) -> Option<ParamValue> {
465 self.parameters.insert(key.into(), value)
466 }
467
468 pub fn remove(&mut self, key: &str) -> Option<ParamValue> {
470 self.parameters.remove(key)
471 }
472
473 pub fn contains(&self, key: &str) -> bool {
475 self.parameters.contains_key(key)
476 }
477
478 pub fn len(&self) -> usize {
480 self.parameters.len()
481 }
482
483 pub fn is_empty(&self) -> bool {
485 self.parameters.is_empty()
486 }
487
488 pub fn get_f32(&self, key: &str, default: f32) -> f32 {
490 self.parameters
491 .get(key)
492 .and_then(|v| v.as_f32())
493 .unwrap_or(default)
494 }
495
496 pub fn get_i32(&self, key: &str, default: i32) -> i32 {
498 self.parameters
499 .get(key)
500 .and_then(|v| v.as_i32())
501 .unwrap_or(default)
502 }
503
504 pub fn get_bool(&self, key: &str, default: bool) -> bool {
506 self.parameters
507 .get(key)
508 .and_then(|v| v.as_bool())
509 .unwrap_or(default)
510 }
511}
512
513#[cfg(test)]
518mod tests {
519 use super::*;
520
521 #[test]
522 fn test_parameter_id_valid() {
523 assert!(ParameterId::new("gain").is_ok());
524 assert!(ParameterId::new("cutoff_freq").is_ok());
525 assert!(ParameterId::new("delay_time_2").is_ok());
526 }
527
528 #[test]
529 fn test_parameter_id_invalid() {
530 assert!(ParameterId::new("").is_err());
531 assert!(ParameterId::new("1gain").is_err());
532 assert!(ParameterId::new("_gain").is_err());
533
534 let long_name = "a".repeat(ParameterId::MAX_LEN + 1);
535 assert!(ParameterId::new(long_name).is_err());
536 }
537
538 #[test]
539 fn test_param_value_conversion() {
540 let f = ParamValue::Float(42.0);
541 assert_eq!(f.as_f32(), Some(42.0));
542 assert_eq!(f.as_i32(), Some(42));
543 assert_eq!(f.as_bool(), Some(true));
544
545 let i = ParamValue::Int(0);
546 assert_eq!(i.as_f32(), Some(0.0));
547 assert_eq!(i.as_i32(), Some(0));
548 assert_eq!(i.as_bool(), Some(false));
549 }
550}