memscope_rs/render_engine/
engine.rs1use crate::render_engine::renderer::{OutputFormat, RenderConfig, RenderResult, Renderer};
6use crate::snapshot::{MemorySnapshot, SharedSnapshotEngine};
7use serde_json;
8
9struct JsonRenderer;
11
12impl Renderer for JsonRenderer {
13 fn format(&self) -> OutputFormat {
14 OutputFormat::Json
15 }
16
17 fn render(
18 &self,
19 snapshot: &MemorySnapshot,
20 config: &RenderConfig,
21 ) -> Result<RenderResult, String> {
22 let data = if config.verbose {
23 serde_json::to_vec_pretty(&snapshot)
24 } else {
25 serde_json::to_vec(&snapshot)
26 }
27 .map_err(|e| e.to_string())?;
28
29 let size = data.len();
30
31 Ok(RenderResult {
32 data,
33 format: OutputFormat::Json,
34 size,
35 })
36 }
37}
38
39pub struct RenderEngine {
49 snapshot_engine: SharedSnapshotEngine,
51 renderers: Vec<Box<dyn Renderer>>,
53}
54
55impl RenderEngine {
56 pub fn new(snapshot_engine: SharedSnapshotEngine) -> Self {
58 let mut engine = Self {
59 snapshot_engine,
60 renderers: Vec::new(),
61 };
62
63 engine.register_renderer(Box::new(JsonRenderer));
65
66 engine
67 }
68
69 pub fn register_renderer(&mut self, renderer: Box<dyn Renderer>) {
74 self.renderers.push(renderer);
75 }
76
77 pub fn render(&self, config: &RenderConfig) -> Result<RenderResult, String> {
85 let snapshot = self.snapshot_engine.build_snapshot();
86 self.render_snapshot(&snapshot, config)
87 }
88
89 pub fn render_snapshot(
98 &self,
99 snapshot: &MemorySnapshot,
100 config: &RenderConfig,
101 ) -> Result<RenderResult, String> {
102 for renderer in &self.renderers {
104 if renderer.format() == config.format {
105 return renderer.render(snapshot, config);
106 }
107 }
108
109 Err(format!("No renderer found for format: {}", config.format))
110 }
111
112 pub fn render_json(
114 &self,
115 snapshot: &MemorySnapshot,
116 verbose: bool,
117 ) -> Result<RenderResult, String> {
118 let config = RenderConfig {
119 format: OutputFormat::Json,
120 output_path: None,
121 verbose,
122 include_timestamps: true,
123 };
124 self.render_snapshot(snapshot, &config)
125 }
126
127 pub fn has_renderer(&self, format: OutputFormat) -> bool {
132 self.renderers.iter().any(|r| r.format() == format)
133 }
134
135 pub fn renderer_count(&self) -> usize {
137 self.renderers.len()
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144 use crate::event_store::EventStore;
145 use crate::snapshot::SnapshotEngine;
146 use std::sync::Arc;
147
148 #[test]
149 fn test_render_engine_creation() {
150 let event_store = Arc::new(EventStore::new());
151 let snapshot_engine = Arc::new(SnapshotEngine::new(event_store));
152 let engine = RenderEngine::new(snapshot_engine);
153
154 assert!(engine.has_renderer(OutputFormat::Json));
155 assert_eq!(engine.renderer_count(), 1);
156 }
157
158 #[test]
159 fn test_render_json() {
160 let event_store = Arc::new(EventStore::new());
161 event_store.record(crate::event_store::MemoryEvent::allocate(0x1000, 1024, 1));
162
163 let snapshot_engine = Arc::new(SnapshotEngine::new(event_store));
164 let engine = RenderEngine::new(snapshot_engine);
165
166 let snapshot = engine.snapshot_engine.build_snapshot();
167 let result = engine.render_json(&snapshot, false);
168
169 assert!(result.is_ok());
170 let result = result.unwrap();
171 assert_eq!(result.format, OutputFormat::Json);
172 assert!(result.size > 0);
173 }
174
175 #[test]
176 fn test_render_with_config() {
177 let event_store = Arc::new(EventStore::new());
178 let snapshot_engine = Arc::new(SnapshotEngine::new(event_store));
179 let engine = RenderEngine::new(snapshot_engine);
180
181 let config = RenderConfig::default();
182 let result = engine.render(&config);
183
184 assert!(result.is_ok());
185 }
186
187 #[test]
188 fn test_has_renderer() {
189 let event_store = Arc::new(EventStore::new());
190 let snapshot_engine = Arc::new(SnapshotEngine::new(event_store));
191 let engine = RenderEngine::new(snapshot_engine);
192
193 assert!(engine.has_renderer(OutputFormat::Json));
194 assert!(!engine.has_renderer(OutputFormat::Html));
195 }
196}