mod context;
mod helpers;
mod render_methods;
mod system_info;
mod types;
pub use types::*;
pub use context::rebuild_allocations_from_events;
use crate::analysis::memory_passport_tracker::MemoryPassportTracker;
use crate::tracker::Tracker;
use handlebars::Handlebars;
use std::sync::Arc;
pub struct DashboardRenderer {
handlebars: Handlebars<'static>,
}
impl DashboardRenderer {
pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
let mut handlebars = Handlebars::new();
let template_path = format!(
"{}/src/render_engine/dashboard/templates/dashboard_unified.html",
env!("CARGO_MANIFEST_DIR")
);
handlebars.register_template_file("dashboard_unified", &template_path)?;
let final_path = format!(
"{}/src/render_engine/dashboard/templates/dashboard_final.html",
env!("CARGO_MANIFEST_DIR")
);
handlebars.register_template_file("dashboard_final", &final_path)?;
helpers::register_helpers(&mut handlebars);
Ok(Self { handlebars })
}
pub fn build_context_from_tracker(
&self,
tracker: &Tracker,
passport_tracker: &Arc<MemoryPassportTracker>,
) -> Result<DashboardContext, Box<dyn std::error::Error>> {
self.build_context_from_tracker_with_async(tracker, passport_tracker, None)
}
pub fn build_context_from_tracker_with_async(
&self,
tracker: &Tracker,
passport_tracker: &Arc<MemoryPassportTracker>,
async_tracker: Option<&Arc<crate::capture::backends::async_tracker::AsyncTracker>>,
) -> Result<DashboardContext, Box<dyn std::error::Error>> {
context::build_context_from_tracker_with_async(tracker, passport_tracker, async_tracker)
}
pub fn render_from_tracker(
&self,
tracker: &Tracker,
passport_tracker: &Arc<MemoryPassportTracker>,
) -> Result<String, Box<dyn std::error::Error>> {
let context = self.build_context_from_tracker(tracker, passport_tracker)?;
self.render_dashboard(&context)
}
pub fn render_dashboard(
&self,
context: &DashboardContext,
) -> Result<String, Box<dyn std::error::Error>> {
self.render_unified_dashboard(context)
}
pub fn render_standalone_dashboard(
&self,
context: &DashboardContext,
) -> Result<String, Box<dyn std::error::Error>> {
self.render_unified_dashboard(context)
}
pub fn render_unified_dashboard(
&self,
context: &DashboardContext,
) -> Result<String, Box<dyn std::error::Error>> {
render_methods::render_unified_dashboard(&self.handlebars, context)
}
pub fn render_final_dashboard(
&self,
context: &DashboardContext,
) -> Result<String, Box<dyn std::error::Error>> {
render_methods::render_final_dashboard(&self.handlebars, context)
}
pub fn render_binary_dashboard(
&self,
context: &DashboardContext,
) -> Result<String, Box<dyn std::error::Error>> {
render_methods::render_binary_dashboard(&self.handlebars, context)
}
pub fn render_clean_dashboard(
&self,
context: &DashboardContext,
) -> Result<String, Box<dyn std::error::Error>> {
render_methods::render_clean_dashboard(&self.handlebars, context)
}
pub fn render_hybrid_dashboard(
&self,
context: &DashboardContext,
) -> Result<String, Box<dyn std::error::Error>> {
render_methods::render_hybrid_dashboard(&self.handlebars, context)
}
pub fn render_performance_dashboard(
&self,
context: &DashboardContext,
) -> Result<String, Box<dyn std::error::Error>> {
render_methods::render_performance_dashboard(&self.handlebars, context)
}
}
impl Default for DashboardRenderer {
fn default() -> Self {
Self::new().expect("Failed to create dashboard renderer")
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::render_engine::dashboard::renderer::types::{
AsyncSummary, CircularReferenceReport, DashboardContext, OwnershipGraphInfo,
SystemResources,
};
fn create_empty_context() -> DashboardContext {
DashboardContext {
title: "Test".to_string(),
export_timestamp: "2024-01-01".to_string(),
total_memory: "0 B".to_string(),
total_allocations: 0,
active_allocations: 0,
peak_memory: "0 B".to_string(),
thread_count: 0,
passport_count: 0,
leak_count: 0,
unsafe_count: 0,
ffi_count: 0,
allocations: vec![],
relationships: vec![],
unsafe_reports: vec![],
passport_details: vec![],
allocations_count: 0,
relationships_count: 0,
unsafe_reports_count: 0,
json_data: "{}".to_string(),
os_name: "test".to_string(),
architecture: "test".to_string(),
cpu_cores: 1,
system_resources: SystemResources {
os_name: "test".to_string(),
os_version: "1.0".to_string(),
architecture: "test".to_string(),
cpu_cores: 1,
total_physical: "0 B".to_string(),
available_physical: "0 B".to_string(),
used_physical: "0 B".to_string(),
page_size: 4096,
},
threads: vec![],
async_tasks: vec![],
async_summary: AsyncSummary {
total_tasks: 0,
active_tasks: 0,
total_allocations: 0,
total_memory_bytes: 0,
peak_memory_bytes: 0,
},
health_score: 100,
health_status: "Good".to_string(),
safe_ops_count: 0,
high_risk_count: 0,
clean_passport_count: 0,
active_passport_count: 0,
leaked_passport_count: 0,
ffi_tracked_count: 0,
safe_code_percent: 100,
ownership_graph: OwnershipGraphInfo {
total_nodes: 0,
total_edges: 0,
total_cycles: 0,
rc_clone_count: 0,
arc_clone_count: 0,
has_issues: false,
issues: vec![],
root_cause: None,
},
top_allocation_sites: vec![],
top_leaked_allocations: vec![],
top_temporary_churn: vec![],
circular_references: CircularReferenceReport {
count: 0,
total_leaked_memory: 0,
pointers_in_cycles: 0,
total_smart_pointers: 0,
has_cycles: false,
},
task_graph_json: "{}".to_string(),
}
}
#[test]
fn test_dashboard_renderer_creation() {
let result = DashboardRenderer::new();
assert!(
result.is_ok(),
"DashboardRenderer should create successfully"
);
}
#[test]
fn test_dashboard_renderer_default() {
let renderer = DashboardRenderer::default();
let _ = &renderer;
}
#[test]
fn test_render_unified_dashboard() {
let renderer = DashboardRenderer::new().expect("Should create renderer");
let context = create_empty_context();
let result = renderer.render_unified_dashboard(&context);
assert!(
result.is_ok(),
"Should render unified dashboard successfully"
);
}
#[test]
fn test_render_final_dashboard() {
let renderer = DashboardRenderer::new().expect("Should create renderer");
let context = create_empty_context();
let result = renderer.render_final_dashboard(&context);
assert!(result.is_ok(), "Should render final dashboard successfully");
}
#[test]
fn test_render_dashboard() {
let renderer = DashboardRenderer::new().expect("Should create renderer");
let context = create_empty_context();
let result = renderer.render_dashboard(&context);
assert!(result.is_ok(), "Should render dashboard successfully");
}
#[test]
fn test_render_standalone_dashboard() {
let renderer = DashboardRenderer::new().expect("Should create renderer");
let context = create_empty_context();
let result = renderer.render_standalone_dashboard(&context);
assert!(
result.is_ok(),
"Should render standalone dashboard successfully"
);
}
}