use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VariableInfo {
pub var_name: String,
pub type_name: String,
pub timestamp: u64,
pub size: usize,
pub thread_id: usize,
pub memory_usage: u64,
}
#[derive(Debug)]
pub struct VariableRegistry {
variables: Arc<Mutex<HashMap<usize, VariableInfo>>>,
}
impl VariableRegistry {
pub fn new() -> Self {
Self {
variables: Arc::new(Mutex::new(HashMap::new())),
}
}
pub fn register_variable(
&self,
address: usize,
var_name: String,
type_name: String,
size: usize,
) {
let thread_id = self.hash_thread_id();
let timestamp = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_nanos() as u64;
let var_info = VariableInfo {
var_name,
type_name,
timestamp,
size,
thread_id,
memory_usage: size as u64,
};
if let Ok(mut vars) = self.variables.lock() {
vars.insert(address, var_info);
}
}
pub fn get_variable_info(&self, address: usize) -> Option<VariableInfo> {
if let Ok(vars) = self.variables.lock() {
vars.get(&address).cloned()
} else {
None
}
}
pub fn get_all_variables(&self) -> Vec<(usize, VariableInfo)> {
if let Ok(vars) = self.variables.lock() {
vars.iter().map(|(k, v)| (*k, v.clone())).collect()
} else {
Vec::new()
}
}
pub fn clear(&self) {
if let Ok(mut vars) = self.variables.lock() {
vars.clear();
}
}
pub fn len(&self) -> usize {
if let Ok(vars) = self.variables.lock() {
vars.len()
} else {
0
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
fn hash_thread_id(&self) -> usize {
crate::utils::current_thread_id_u64() as usize
}
}
impl Default for VariableRegistry {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_variable_registry_creation() {
let registry = VariableRegistry::new();
assert!(registry.is_empty());
assert_eq!(registry.len(), 0);
}
#[test]
fn test_register_variable() {
let registry = VariableRegistry::new();
registry.register_variable(0x1000, "test_var".to_string(), "i32".to_string(), 4);
assert_eq!(registry.len(), 1);
let info = registry.get_variable_info(0x1000);
assert!(info.is_some());
let info = info.unwrap();
assert_eq!(info.var_name, "test_var");
assert_eq!(info.type_name, "i32");
assert_eq!(info.size, 4);
}
#[test]
fn test_get_all_variables() {
let registry = VariableRegistry::new();
registry.register_variable(0x1000, "var1".to_string(), "i32".to_string(), 4);
registry.register_variable(0x2000, "var2".to_string(), "String".to_string(), 24);
let all = registry.get_all_variables();
assert_eq!(all.len(), 2);
}
#[test]
fn test_clear() {
let registry = VariableRegistry::new();
registry.register_variable(0x1000, "test".to_string(), "i32".to_string(), 4);
assert_eq!(registry.len(), 1);
registry.clear();
assert!(registry.is_empty());
}
}