Skip to main content

memscope_rs/metadata/
registry.rs

1//! Variable Registry - Variable metadata management
2//!
3//! This module provides variable registration and metadata tracking
4//! for the MetadataEngine.
5
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8use std::sync::{Arc, Mutex};
9
10/// Variable information stored in registry
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct VariableInfo {
13    /// User-defined variable name
14    pub var_name: String,
15    /// Type name of the variable
16    pub type_name: String,
17    /// Timestamp when variable was registered
18    pub timestamp: u64,
19    /// Estimated size of the variable
20    pub size: usize,
21    /// Thread ID that created this variable
22    pub thread_id: usize,
23    /// Memory usage of this variable
24    pub memory_usage: u64,
25}
26
27/// Variable Registry - manages variable address to name mappings
28#[derive(Debug)]
29pub struct VariableRegistry {
30    /// Internal storage for variable info
31    variables: Arc<Mutex<HashMap<usize, VariableInfo>>>,
32}
33
34impl VariableRegistry {
35    /// Create a new VariableRegistry
36    pub fn new() -> Self {
37        Self {
38            variables: Arc::new(Mutex::new(HashMap::new())),
39        }
40    }
41
42    /// Register a variable with its address and information
43    pub fn register_variable(
44        &self,
45        address: usize,
46        var_name: String,
47        type_name: String,
48        size: usize,
49    ) {
50        let thread_id = self.hash_thread_id();
51        let timestamp = std::time::SystemTime::now()
52            .duration_since(std::time::UNIX_EPOCH)
53            .unwrap_or_default()
54            .as_nanos() as u64;
55
56        let var_info = VariableInfo {
57            var_name,
58            type_name,
59            timestamp,
60            size,
61            thread_id,
62            memory_usage: size as u64,
63        };
64
65        if let Ok(mut vars) = self.variables.lock() {
66            vars.insert(address, var_info);
67        }
68    }
69
70    /// Get variable information by address
71    pub fn get_variable_info(&self, address: usize) -> Option<VariableInfo> {
72        if let Ok(vars) = self.variables.lock() {
73            vars.get(&address).cloned()
74        } else {
75            None
76        }
77    }
78
79    /// Get all variables
80    pub fn get_all_variables(&self) -> Vec<(usize, VariableInfo)> {
81        if let Ok(vars) = self.variables.lock() {
82            vars.iter().map(|(k, v)| (*k, v.clone())).collect()
83        } else {
84            Vec::new()
85        }
86    }
87
88    /// Clear all variables
89    pub fn clear(&self) {
90        if let Ok(mut vars) = self.variables.lock() {
91            vars.clear();
92        }
93    }
94
95    /// Get the number of registered variables
96    pub fn len(&self) -> usize {
97        if let Ok(vars) = self.variables.lock() {
98            vars.len()
99        } else {
100            0
101        }
102    }
103
104    /// Check if the registry is empty
105    pub fn is_empty(&self) -> bool {
106        self.len() == 0
107    }
108
109    /// Hash the current thread ID to a usize
110    fn hash_thread_id(&self) -> usize {
111        crate::utils::current_thread_id_u64() as usize
112    }
113}
114
115impl Default for VariableRegistry {
116    fn default() -> Self {
117        Self::new()
118    }
119}
120
121#[cfg(test)]
122mod tests {
123    use super::*;
124
125    #[test]
126    fn test_variable_registry_creation() {
127        let registry = VariableRegistry::new();
128        assert!(registry.is_empty());
129        assert_eq!(registry.len(), 0);
130    }
131
132    #[test]
133    fn test_register_variable() {
134        let registry = VariableRegistry::new();
135        registry.register_variable(0x1000, "test_var".to_string(), "i32".to_string(), 4);
136        assert_eq!(registry.len(), 1);
137
138        let info = registry.get_variable_info(0x1000);
139        assert!(info.is_some());
140        let info = info.unwrap();
141        assert_eq!(info.var_name, "test_var");
142        assert_eq!(info.type_name, "i32");
143        assert_eq!(info.size, 4);
144    }
145
146    #[test]
147    fn test_get_all_variables() {
148        let registry = VariableRegistry::new();
149        registry.register_variable(0x1000, "var1".to_string(), "i32".to_string(), 4);
150        registry.register_variable(0x2000, "var2".to_string(), "String".to_string(), 24);
151
152        let all = registry.get_all_variables();
153        assert_eq!(all.len(), 2);
154    }
155
156    #[test]
157    fn test_clear() {
158        let registry = VariableRegistry::new();
159        registry.register_variable(0x1000, "test".to_string(), "i32".to_string(), 4);
160        assert_eq!(registry.len(), 1);
161
162        registry.clear();
163        assert!(registry.is_empty());
164    }
165}