Skip to main content

rill_core/traits/
mod.rs

1//! # Core Traits for Rill
2//!
3//! This module defines the fundamental traits that form the backbone
4//! of the Rill ecosystem.
5
6pub mod action;
7pub mod algorithm;
8mod error;
9pub mod node;
10pub mod param;
11pub mod port;
12pub mod processable;
13
14// Re-export all public items
15pub use action::*;
16pub use algorithm::*;
17pub use error::*;
18pub use node::*;
19pub use param::*;
20pub use port::*;
21pub use processable::*;
22
23// ============================================================================
24// Common Type Aliases
25// ============================================================================
26
27/// Default block size for signal processing
28pub const DEFAULT_BLOCK_SIZE: usize = 64;
29
30/// Type alias for a mono signal block
31pub type MonoBlock<T, const BUF_SIZE: usize> = [T; BUF_SIZE];
32
33/// Type alias for a stereo signal block (left, right)
34pub type StereoBlock<T, const BUF_SIZE: usize> = [MonoBlock<T, BUF_SIZE>; 2];
35
36/// Type alias for a control signal value
37pub type ControlValue<T> = T;
38
39// ============================================================================
40// Prelude - Convenient imports for common use
41// ============================================================================
42
43/// Prelude module for convenient importing of common traits and types
44pub mod prelude {
45    // Re-export from parent modules
46    pub use super::{
47        // Core traits
48        SignalNode,
49        NodeCategory,
50        // Node types
51        NodeId,
52        NodeMetadata,
53        NodeState,
54
55        NodeTypeId,
56        ParamMetadata,
57
58        ParamRange,
59        ParamType,
60        ParamValue,
61        ParameterError,
62
63        // Parameter handling
64        ParameterId,
65        ParameterResult,
66        Port,
67
68        PortDirection,
69        // Ports
70        PortId,
71        PortType,
72        ProcessError,
73        // Error types
74        ProcessResult,
75        Processor,
76        Sink,
77
78        Source,
79        // Constants
80        DEFAULT_BLOCK_SIZE,
81    };
82
83    // Re-export Transcendental from math module for convenience
84    pub use crate::math::Transcendental;
85}
86
87// ============================================================================
88// Common Helper Traits
89// ============================================================================
90
91/// Trait for types that can be converted to/from `ParamValue`
92pub trait IntoParamValue: Sized {
93    /// Convert this value into a `ParamValue`
94    fn into_param_value(self) -> ParamValue;
95
96    /// Try to convert a `ParamValue` back into this type
97    fn from_param_value(value: ParamValue) -> Option<Self>;
98}
99
100impl IntoParamValue for f32 {
101    fn into_param_value(self) -> ParamValue {
102        ParamValue::Float(self)
103    }
104
105    fn from_param_value(value: ParamValue) -> Option<Self> {
106        value.as_f32()
107    }
108}
109
110impl IntoParamValue for i32 {
111    fn into_param_value(self) -> ParamValue {
112        ParamValue::Int(self)
113    }
114
115    fn from_param_value(value: ParamValue) -> Option<Self> {
116        value.as_i32()
117    }
118}
119
120impl IntoParamValue for bool {
121    fn into_param_value(self) -> ParamValue {
122        ParamValue::Bool(self)
123    }
124
125    fn from_param_value(value: ParamValue) -> Option<Self> {
126        value.as_bool()
127    }
128}
129
130impl IntoParamValue for String {
131    fn into_param_value(self) -> ParamValue {
132        ParamValue::String(self)
133    }
134
135    fn from_param_value(value: ParamValue) -> Option<Self> {
136        match value {
137            ParamValue::String(s) => Some(s),
138            ParamValue::Choice(s) => Some(s),
139            _ => None,
140        }
141    }
142}
143
144// ============================================================================
145// Blanket Implementations
146// ============================================================================
147
148/// Helper trait for downcasting to concrete types
149pub trait AsAny: 'static {
150    /// Convert to `&dyn std::any::Any`
151    fn as_any(&self) -> &dyn std::any::Any;
152
153    /// Convert to `&mut dyn std::any::Any`
154    fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
155}
156
157impl<T: 'static> AsAny for T {
158    fn as_any(&self) -> &dyn std::any::Any {
159        self
160    }
161
162    fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
163        self
164    }
165}
166
167// ============================================================================
168// Tests
169// ============================================================================
170
171#[cfg(test)]
172mod tests {
173    use super::prelude::*;
174    use crate::traits::IntoParamValue;
175
176    #[test]
177    fn test_prelude_imports() {
178        // Verify that all expected types are accessible
179        let _node_id = NodeId(0);
180        let _port_id = PortId::audio_in(_node_id, 0);
181        let _param_id = ParameterId::new("test").unwrap();
182
183        // Test IntoParamValue
184        let f: f32 = 42.0;
185        let pv = f.into_param_value();
186        assert_eq!(pv.as_f32(), Some(42.0));
187
188        let back = f32::from_param_value(pv);
189        assert_eq!(back, Some(42.0));
190    }
191
192    #[test]
193    fn test_param_value_conversions() {
194        let f = ParamValue::Float(42.0);
195        assert_eq!(f.as_f32(), Some(42.0));
196        assert_eq!(f.as_i32(), Some(42));
197        assert_eq!(f.as_bool(), Some(true));
198
199        let i = ParamValue::Int(0);
200        assert_eq!(i.as_f32(), Some(0.0));
201        assert_eq!(i.as_i32(), Some(0));
202        assert_eq!(i.as_bool(), Some(false));
203
204        let b = ParamValue::Bool(true);
205        assert_eq!(b.as_f32(), Some(1.0));
206        assert_eq!(b.as_i32(), Some(1));
207        assert_eq!(b.as_bool(), Some(true));
208    }
209
210    #[test]
211    fn test_parameter_id_validation() {
212        assert!(ParameterId::new("gain").is_ok());
213        assert!(ParameterId::new("cutoff_freq").is_ok());
214        assert!(ParameterId::new("delay_time_2").is_ok());
215
216        assert!(ParameterId::new("").is_err());
217        assert!(ParameterId::new("1gain").is_err());
218        assert!(ParameterId::new("_gain").is_err());
219        assert!(ParameterId::new("gain.value").is_err());
220    }
221
222    #[test]
223    fn test_port_id_creation() {
224        let node = NodeId(42);
225
226        let audio_in = PortId::audio_in(node, 0);
227        assert_eq!(audio_in.node_id(), node);
228        assert_eq!(audio_in.port_type(), PortType::Signal);
229        assert_eq!(audio_in.direction(), PortDirection::Input);
230        assert_eq!(audio_in.index(), 0);
231        assert!(audio_in.is_input());
232        assert!(audio_in.is_audio());
233
234        let clock_out = PortId::clock_out(node, 0);
235        assert_eq!(clock_out.port_type(), PortType::Clock);
236        assert!(clock_out.is_output());
237        assert!(clock_out.is_clock());
238
239        let feedback_in = PortId::feedback_in(node, 0);
240        assert_eq!(feedback_in.port_type(), PortType::Feedback);
241        assert!(feedback_in.is_input());
242        assert!(feedback_in.is_feedback());
243    }
244
245    #[test]
246    fn test_node_metadata() {
247        let metadata = NodeMetadata {
248            name: "TestNode".to_string(),
249            type_name: None,
250            category: NodeCategory::Processor,
251            description: "A test node".to_string(),
252            author: "Rill".to_string(),
253            version: "1.0".to_string(),
254            signal_inputs: 2,
255            signal_outputs: 2,
256            control_inputs: 1,
257            control_outputs: 0,
258            clock_inputs: 1,
259            clock_outputs: 0,
260            feedback_ports: 0,
261            parameters: vec![],
262        };
263
264        assert_eq!(metadata.name, "TestNode");
265        assert_eq!(metadata.category, NodeCategory::Processor);
266        assert_eq!(metadata.signal_inputs, 2);
267    }
268
269    #[test]
270    fn test_param_range() {
271        let range = ParamRange::new().with_min(0.0).with_max(1.0).with_step(0.1);
272
273        assert!(range.contains(0.5));
274        assert!(!range.contains(1.5));
275        assert_eq!(range.clamp(1.5), 1.0);
276        assert_eq!(range.clamp(-0.5), 0.0);
277    }
278
279    #[test]
280    fn test_default_block_size() {
281        assert_eq!(DEFAULT_BLOCK_SIZE, 64);
282    }
283}