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