use crate::render_engine::renderer::{OutputFormat, RenderConfig, RenderResult, Renderer};
use crate::snapshot::{MemorySnapshot, SharedSnapshotEngine};
use serde_json;
struct JsonRenderer;
impl Renderer for JsonRenderer {
fn format(&self) -> OutputFormat {
OutputFormat::Json
}
fn render(
&self,
snapshot: &MemorySnapshot,
config: &RenderConfig,
) -> Result<RenderResult, String> {
let data = if config.verbose {
serde_json::to_vec_pretty(&snapshot)
} else {
serde_json::to_vec(&snapshot)
}
.map_err(|e| e.to_string())?;
let size = data.len();
Ok(RenderResult {
data,
format: OutputFormat::Json,
size,
})
}
}
pub struct RenderEngine {
snapshot_engine: SharedSnapshotEngine,
renderers: Vec<Box<dyn Renderer>>,
}
impl RenderEngine {
pub fn new(snapshot_engine: SharedSnapshotEngine) -> Self {
let mut engine = Self {
snapshot_engine,
renderers: Vec::new(),
};
engine.register_renderer(Box::new(JsonRenderer));
engine
}
pub fn register_renderer(&mut self, renderer: Box<dyn Renderer>) {
self.renderers.push(renderer);
}
pub fn render(&self, config: &RenderConfig) -> Result<RenderResult, String> {
let snapshot = self.snapshot_engine.build_snapshot();
self.render_snapshot(&snapshot, config)
}
pub fn render_snapshot(
&self,
snapshot: &MemorySnapshot,
config: &RenderConfig,
) -> Result<RenderResult, String> {
for renderer in &self.renderers {
if renderer.format() == config.format {
return renderer.render(snapshot, config);
}
}
Err(format!("No renderer found for format: {}", config.format))
}
pub fn render_json(
&self,
snapshot: &MemorySnapshot,
verbose: bool,
) -> Result<RenderResult, String> {
let config = RenderConfig {
format: OutputFormat::Json,
output_path: None,
verbose,
include_timestamps: true,
};
self.render_snapshot(snapshot, &config)
}
pub fn has_renderer(&self, format: OutputFormat) -> bool {
self.renderers.iter().any(|r| r.format() == format)
}
pub fn renderer_count(&self) -> usize {
self.renderers.len()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::event_store::EventStore;
use crate::snapshot::SnapshotEngine;
use std::sync::Arc;
#[test]
fn test_render_engine_creation() {
let event_store = Arc::new(EventStore::new());
let snapshot_engine = Arc::new(SnapshotEngine::new(event_store));
let engine = RenderEngine::new(snapshot_engine);
assert!(engine.has_renderer(OutputFormat::Json));
assert_eq!(engine.renderer_count(), 1);
}
#[test]
fn test_render_json() {
let event_store = Arc::new(EventStore::new());
event_store.record(crate::event_store::MemoryEvent::allocate(0x1000, 1024, 1));
let snapshot_engine = Arc::new(SnapshotEngine::new(event_store));
let engine = RenderEngine::new(snapshot_engine);
let snapshot = engine.snapshot_engine.build_snapshot();
let result = engine.render_json(&snapshot, false);
assert!(result.is_ok());
let result = result.unwrap();
assert_eq!(result.format, OutputFormat::Json);
assert!(result.size > 0);
}
#[test]
fn test_render_with_config() {
let event_store = Arc::new(EventStore::new());
let snapshot_engine = Arc::new(SnapshotEngine::new(event_store));
let engine = RenderEngine::new(snapshot_engine);
let config = RenderConfig::default();
let result = engine.render(&config);
assert!(result.is_ok());
}
#[test]
fn test_has_renderer() {
let event_store = Arc::new(EventStore::new());
let snapshot_engine = Arc::new(SnapshotEngine::new(event_store));
let engine = RenderEngine::new(snapshot_engine);
assert!(engine.has_renderer(OutputFormat::Json));
assert!(!engine.has_renderer(OutputFormat::Html));
}
}