glitcher_core/
debug.rs

1//! Debug Information Types
2//!
3//! Types for exposing internal engine state to UI inspectors.
4//! These are designed for debugging and visualization, not for runtime use.
5
6/// Debug information for a parameter
7#[derive(Debug, Clone)]
8pub struct ParamDebugInfo {
9    /// Parameter name
10    pub name: String,
11    /// Parameter type (f32, vec2, vec4, etc.)
12    pub param_type: String,
13    /// Widget type (slider, button, button_group, etc.)
14    pub widget: String,
15    /// Current value as string
16    pub current_value: String,
17    /// Byte offset in param buffer
18    pub offset: u64,
19    /// Size in bytes
20    pub size: u64,
21}
22
23/// Debug information for a port
24#[derive(Debug, Clone)]
25pub struct PortDebugInfo {
26    /// Port name
27    pub name: String,
28    /// Port direction (input/output)
29    pub direction: String,
30    /// Port type (texture, storage, etc.)
31    pub port_type: String,
32    /// Binding slot
33    pub binding: u32,
34    /// Format (for storage textures)
35    pub format: Option<String>,
36    /// Whether the port is connected
37    pub is_connected: bool,
38}
39
40/// Debug information for an action
41#[derive(Debug, Clone)]
42pub struct ActionDebugInfo {
43    /// Action ID
44    pub id: String,
45    /// Display label
46    pub label: String,
47    /// Action type (Trigger, BeatSync, etc.)
48    pub action_type: String,
49}
50
51/// Debug information for a node in the graph
52#[derive(Debug, Clone)]
53pub struct NodeDebugInfo {
54    /// Node ID (as string for display)
55    pub id: String,
56    /// Definition ID (plugin name)
57    pub def_id: String,
58    /// Display name
59    pub name: String,
60    /// Node kind (Shader/TextureSource)
61    pub kind: String,
62    /// Input connections: (input_index, source_node_id)
63    pub inputs: Vec<(usize, String)>,
64    /// Output texture info (if applicable)
65    pub output_texture: Option<TextureDebugInfo>,
66    /// Buffer offset in parameter buffer
67    pub buffer_offset: Option<u64>,
68    /// Buffer size in parameter buffer
69    pub buffer_size: Option<u64>,
70    /// Actions available for this node
71    pub actions: Vec<ActionDebugInfo>,
72    /// Parameters defined for this node
73    pub params: Vec<ParamDebugInfo>,
74    /// Ports defined for this node
75    pub ports: Vec<PortDebugInfo>,
76}
77
78/// Debug information for a texture
79#[derive(Debug, Clone)]
80pub struct TextureDebugInfo {
81    /// Texture name (for external textures) or index (for intermediates)
82    pub name: String,
83    /// Width in pixels
84    pub width: u32,
85    /// Height in pixels
86    pub height: u32,
87    /// Texture format as string
88    pub format: String,
89    /// Whether this is an external texture
90    pub is_external: bool,
91}
92
93/// Complete graph debug information
94#[derive(Debug, Clone, Default)]
95pub struct GraphDebugInfo {
96    /// All nodes in the graph
97    pub nodes: Vec<NodeDebugInfo>,
98    /// External textures registered in the engine
99    pub external_textures: Vec<TextureDebugInfo>,
100    /// Intermediate textures created during compilation
101    pub intermediate_textures: Vec<TextureDebugInfo>,
102    /// Whether the graph is compiled
103    pub is_compiled: bool,
104    /// Total parameter buffer size
105    pub param_buffer_size: Option<u64>,
106    /// Number of execution steps
107    pub execution_steps: usize,
108}
109
110impl GraphDebugInfo {
111    /// Create empty debug info
112    pub fn empty() -> Self {
113        Self::default()
114    }
115}
116
117#[cfg(test)]
118mod tests {
119    use super::*;
120
121    #[test]
122    fn test_node_debug_info_creation() {
123        let info = NodeDebugInfo {
124            id: "node_1".to_string(),
125            def_id: "solid-color".to_string(),
126            name: "Solid Color".to_string(),
127            kind: "Shader(Fragment)".to_string(),
128            inputs: vec![(0, "node_0".to_string())],
129            output_texture: None,
130            buffer_offset: Some(0),
131            buffer_size: Some(16),
132            actions: vec![ActionDebugInfo {
133                id: "flash".to_string(),
134                label: "Flash".to_string(),
135                action_type: "BeatSync".to_string(),
136            }],
137            params: vec![ParamDebugInfo {
138                name: "intensity".to_string(),
139                param_type: "f32".to_string(),
140                widget: "slider".to_string(),
141                current_value: "0.5".to_string(),
142                offset: 0,
143                size: 4,
144            }],
145            ports: vec![PortDebugInfo {
146                name: "output".to_string(),
147                direction: "output".to_string(),
148                port_type: "texture".to_string(),
149                binding: 0,
150                format: None,
151                is_connected: true,
152            }],
153        };
154
155        assert_eq!(info.id, "node_1");
156        assert_eq!(info.def_id, "solid-color");
157        assert_eq!(info.inputs.len(), 1);
158        assert_eq!(info.buffer_offset, Some(0));
159        assert_eq!(info.actions.len(), 1);
160        assert_eq!(info.actions[0].id, "flash");
161        assert_eq!(info.params.len(), 1);
162        assert_eq!(info.params[0].name, "intensity");
163        assert_eq!(info.ports.len(), 1);
164    }
165
166    #[test]
167    fn test_texture_debug_info_creation() {
168        let info = TextureDebugInfo {
169            name: "intermediate_0".to_string(),
170            width: 1920,
171            height: 1080,
172            format: "Rgba8Unorm".to_string(),
173            is_external: false,
174        };
175
176        assert_eq!(info.width, 1920);
177        assert_eq!(info.height, 1080);
178        assert!(!info.is_external);
179    }
180
181    #[test]
182    fn test_graph_debug_info_empty() {
183        let info = GraphDebugInfo::empty();
184
185        assert!(info.nodes.is_empty());
186        assert!(info.external_textures.is_empty());
187        assert!(info.intermediate_textures.is_empty());
188        assert!(!info.is_compiled);
189        assert_eq!(info.param_buffer_size, None);
190        assert_eq!(info.execution_steps, 0);
191    }
192
193    #[test]
194    fn test_graph_debug_info_with_nodes() {
195        let mut info = GraphDebugInfo::empty();
196
197        info.nodes.push(NodeDebugInfo {
198            id: "1v1".to_string(),
199            def_id: "empty".to_string(),
200            name: "Empty".to_string(),
201            kind: "Shader(Fragment)".to_string(),
202            inputs: vec![],
203            output_texture: Some(TextureDebugInfo {
204                name: "intermediate_0".to_string(),
205                width: 1920,
206                height: 1080,
207                format: "Rgba8Unorm".to_string(),
208                is_external: false,
209            }),
210            buffer_offset: None,
211            buffer_size: None,
212            actions: vec![],
213            params: vec![],
214            ports: vec![],
215        });
216
217        info.is_compiled = true;
218        info.execution_steps = 2;
219
220        assert_eq!(info.nodes.len(), 1);
221        assert!(info.is_compiled);
222        assert_eq!(info.execution_steps, 2);
223        assert!(info.nodes[0].output_texture.is_some());
224    }
225
226    #[test]
227    fn test_debug_info_clone() {
228        let info = NodeDebugInfo {
229            id: "test".to_string(),
230            def_id: "test-def".to_string(),
231            name: "Test".to_string(),
232            kind: "Shader".to_string(),
233            inputs: vec![(0, "other".to_string())],
234            output_texture: None,
235            buffer_offset: Some(256),
236            buffer_size: Some(32),
237            actions: vec![],
238            params: vec![],
239            ports: vec![],
240        };
241
242        let cloned = info.clone();
243        assert_eq!(info.id, cloned.id);
244        assert_eq!(info.buffer_offset, cloned.buffer_offset);
245    }
246}