use super::AccessibilityError;
use std::collections::HashMap;
use std::time::{Duration, Instant};
#[derive(Debug, Clone)]
pub struct PerformanceConfig {
pub max_execution_time: Duration,
pub memory_limit: usize,
pub enable_monitoring: bool,
}
pub struct PerformanceMonitor {
config: PerformanceConfig,
metrics: HashMap<String, PerformanceMetric>,
active_operations: HashMap<String, Instant>,
}
#[derive(Debug, Clone)]
pub struct PerformanceMetric {
pub operation_name: String,
pub duration_ms: u64,
pub memory_usage_mb: f64,
pub timestamp: Instant,
pub success: bool,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct CachingConfig {
pub enabled: bool,
pub max_cache_size_mb: u64,
pub ttl_seconds: u64,
pub cache_strategy: CacheStrategy,
pub preload_common_queries: bool,
}
impl Default for CachingConfig {
fn default() -> Self {
Self {
enabled: true,
max_cache_size_mb: 100,
ttl_seconds: 300, cache_strategy: CacheStrategy::LRU,
preload_common_queries: true,
}
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub enum CacheStrategy {
LRU,
FIFO,
TTL,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct MonitoringConfig {
pub enabled: bool,
pub sample_rate: f64, pub alert_threshold_ms: u64,
pub memory_alert_threshold_mb: u64,
pub log_performance: bool,
}
impl Default for MonitoringConfig {
fn default() -> Self {
Self {
enabled: true,
sample_rate: 1.0,
alert_threshold_ms: 100,
memory_alert_threshold_mb: 50,
log_performance: true,
}
}
}
impl PerformanceMonitor {
pub fn new(config: PerformanceConfig) -> Self {
Self {
config,
metrics: HashMap::new(),
active_operations: HashMap::new(),
}
}
pub fn start_monitoring(&mut self, operation_name: &str) -> PerformanceMonitor {
if !self.config.enable_monitoring {
return PerformanceMonitor {
config: self.config.clone(),
metrics: HashMap::new(),
active_operations: HashMap::new(),
};
}
self.active_operations
.insert(operation_name.to_string(), Instant::now());
PerformanceMonitor {
config: self.config.clone(),
metrics: HashMap::new(),
active_operations: HashMap::new(),
}
}
pub fn end_monitoring(
&mut self,
operation_name: &str,
success: bool,
) -> Result<PerformanceMetric, AccessibilityError> {
if !self.config.enable_monitoring {
return Err(AccessibilityError::PerformanceBudgetExceeded(
"Performance monitoring is disabled".to_string(),
));
}
let start_time = self
.active_operations
.remove(operation_name)
.ok_or_else(|| {
AccessibilityError::PerformanceBudgetExceeded(format!(
"No active operation found for: {}",
operation_name
))
})?;
let duration = start_time.elapsed();
let duration_ms = duration.as_millis() as u64;
if duration_ms > self.config.max_execution_time.as_millis() as u64 {
return Err(AccessibilityError::PerformanceBudgetExceeded(format!(
"Operation '{}' exceeded budget: {}ms > {}ms",
operation_name,
duration_ms,
self.config.max_execution_time.as_millis()
)));
}
let metric = PerformanceMetric {
operation_name: operation_name.to_string(),
duration_ms,
memory_usage_mb: self.get_memory_usage(),
timestamp: Instant::now(),
success,
};
self.metrics
.insert(operation_name.to_string(), metric.clone());
if self.config.enable_monitoring {
self.log_performance(&metric);
}
Ok(metric)
}
pub fn get_metrics(&self) -> &HashMap<String, PerformanceMetric> {
&self.metrics
}
pub fn get_average_performance(&self, operation_name: &str) -> Option<f64> {
let metrics: Vec<&PerformanceMetric> = self
.metrics
.values()
.filter(|m| m.operation_name == operation_name)
.collect();
if metrics.is_empty() {
return None;
}
let total_duration: u64 = metrics.iter().map(|m| m.duration_ms).sum();
Some(total_duration as f64 / metrics.len() as f64)
}
pub fn check_budget_compliance(&self) -> BudgetComplianceReport {
let mut report = BudgetComplianceReport {
overall_compliant: true,
violations: Vec::new(),
warnings: Vec::new(),
recommendations: Vec::new(),
};
for metric in self.metrics.values() {
if metric.duration_ms > self.config.max_execution_time.as_millis() as u64 {
report.overall_compliant = false;
report.violations.push(BudgetViolation {
operation: metric.operation_name.clone(),
actual_ms: metric.duration_ms,
budget_ms: self.config.max_execution_time.as_millis() as u64,
severity: if metric.duration_ms
> self.config.max_execution_time.as_millis() as u64 * 2
{
PerformanceViolationSeverity::Critical
} else {
PerformanceViolationSeverity::High
},
});
} else if metric.duration_ms
> (self.config.max_execution_time.as_millis() as u64 * 8) / 10
{
report.warnings.push(format!(
"Operation '{}' is approaching budget limit: {}ms / {}ms",
metric.operation_name,
metric.duration_ms,
self.config.max_execution_time.as_millis()
));
}
}
if !report.overall_compliant {
report
.recommendations
.push("Consider optimizing slow operations".to_string());
report
.recommendations
.push("Enable caching for frequently accessed data".to_string());
report
.recommendations
.push("Implement lazy loading for large datasets".to_string());
}
report
}
fn get_memory_usage(&self) -> f64 {
0.0
}
fn log_performance(&self, metric: &PerformanceMetric) {
println!(
"Performance: {} took {}ms (success: {})",
metric.operation_name, metric.duration_ms, metric.success
);
}
}
#[derive(Debug, Clone)]
pub struct BudgetComplianceReport {
pub overall_compliant: bool,
pub violations: Vec<BudgetViolation>,
pub warnings: Vec<String>,
pub recommendations: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct BudgetViolation {
pub operation: String,
pub actual_ms: u64,
pub budget_ms: u64,
pub severity: PerformanceViolationSeverity,
}
#[derive(Debug, Clone)]
pub enum PerformanceViolationSeverity {
Low,
Medium,
High,
Critical,
}
pub struct PerformanceOptimizer {
cache: HashMap<String, CachedResult>,
config: CachingConfig,
}
#[derive(Debug, Clone)]
pub struct CachedResult {
pub data: String,
pub timestamp: Instant,
pub ttl: Duration,
}
impl PerformanceOptimizer {
pub fn new(config: CachingConfig) -> Self {
Self {
cache: HashMap::new(),
config,
}
}
pub fn get_cached(&self, key: &str) -> Option<&String> {
if !self.config.enabled {
return None;
}
if let Some(cached) = self.cache.get(key) {
if cached.timestamp.elapsed() < cached.ttl {
return Some(&cached.data);
}
}
None
}
pub fn cache_result(&mut self, key: String, data: String) {
if !self.config.enabled {
return;
}
let ttl = Duration::from_secs(self.config.ttl_seconds);
let cached = CachedResult {
data,
timestamp: Instant::now(),
ttl,
};
self.cache.insert(key, cached);
self.cleanup_expired();
}
fn cleanup_expired(&mut self) {
let now = Instant::now();
self.cache
.retain(|_, cached| now.duration_since(cached.timestamp) < cached.ttl);
}
pub fn clear_cache(&mut self) {
self.cache.clear();
}
pub fn get_cache_stats(&self) -> CacheStats {
let total_entries = self.cache.len();
let total_size_mb = self
.cache
.values()
.map(|c| c.data.len() as f64 / 1024.0 / 1024.0)
.sum();
CacheStats {
total_entries,
total_size_mb,
hit_rate: 0.0, }
}
}
#[derive(Debug, Clone)]
pub struct CacheStats {
pub total_entries: usize,
pub total_size_mb: f64,
pub hit_rate: f64,
}