Skip to main content

memscope_rs/analysis/generic/
types.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize)]
4pub struct GenericInstance {
5    pub name: String,
6    pub base_type: String,
7    pub underlying_type: String,
8    pub type_parameters: Vec<String>,
9    pub ptr: usize,
10    pub size: usize,
11    pub constraints: Vec<GenericConstraint>,
12    pub is_type_alias: bool,
13}
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct GenericConstraint {
17    pub parameter_name: String,
18    pub constraint_type: ConstraintType,
19    pub description: String,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
23pub enum ConstraintType {
24    Trait(String),
25    Lifetime,
26    Sized,
27    Send,
28    Sync,
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct InstantiationEvent {
33    pub base_type: String,
34    pub type_parameters: Vec<String>,
35    pub ptr: usize,
36    pub timestamp: u64,
37    pub thread_id: String,
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct ConstraintViolation {
42    pub constraint: GenericConstraint,
43    pub actual_type: String,
44    pub violation_type: ViolationType,
45    pub timestamp: u64,
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize)]
49pub enum ViolationType {
50    ConstraintNotSatisfied,
51    LifetimeMismatch,
52    MissingTraitImpl,
53}
54
55#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct GenericStatistics {
57    pub total_instances: usize,
58    pub unique_base_types: usize,
59    pub total_instantiations: usize,
60    pub constraint_violations: usize,
61    pub most_used_types: Vec<(String, usize)>,
62    pub type_aliases_count: usize,
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct TypeAliasInfo {
67    pub alias_name: String,
68    pub underlying_type: String,
69    pub base_type: String,
70    pub type_parameters: Vec<String>,
71    pub usage_count: usize,
72}
73
74#[cfg(test)]
75mod tests {
76    use super::*;
77
78    #[test]
79    fn test_generic_instance_creation() {
80        let instance = GenericInstance {
81            name: "Vec<i32>".to_string(),
82            base_type: "Vec".to_string(),
83            underlying_type: "Vec<i32>".to_string(),
84            type_parameters: vec!["i32".to_string()],
85            ptr: 0x1000,
86            size: 24,
87            constraints: vec![],
88            is_type_alias: false,
89        };
90
91        assert_eq!(instance.name, "Vec<i32>");
92        assert_eq!(instance.base_type, "Vec");
93        assert_eq!(instance.type_parameters.len(), 1);
94        assert!(!instance.is_type_alias);
95    }
96
97    #[test]
98    fn test_generic_instance_with_constraints() {
99        let constraint = GenericConstraint {
100            parameter_name: "T".to_string(),
101            constraint_type: ConstraintType::Trait("Clone".to_string()),
102            description: "T must be Clone".to_string(),
103        };
104
105        let instance = GenericInstance {
106            name: "HashMap<String, i32>".to_string(),
107            base_type: "HashMap".to_string(),
108            underlying_type: "HashMap<String, i32>".to_string(),
109            type_parameters: vec!["String".to_string(), "i32".to_string()],
110            ptr: 0x2000,
111            size: 48,
112            constraints: vec![constraint],
113            is_type_alias: false,
114        };
115
116        assert_eq!(instance.constraints.len(), 1);
117        assert_eq!(instance.constraints[0].parameter_name, "T");
118    }
119
120    #[test]
121    fn test_generic_constraint_creation() {
122        let constraint = GenericConstraint {
123            parameter_name: "T".to_string(),
124            constraint_type: ConstraintType::Send,
125            description: "T must be Send".to_string(),
126        };
127
128        assert_eq!(constraint.parameter_name, "T");
129        assert!(matches!(constraint.constraint_type, ConstraintType::Send));
130    }
131
132    #[test]
133    fn test_constraint_type_variants() {
134        let trait_constraint = ConstraintType::Trait("Debug".to_string());
135        let lifetime_constraint = ConstraintType::Lifetime;
136        let sized_constraint = ConstraintType::Sized;
137        let send_constraint = ConstraintType::Send;
138        let sync_constraint = ConstraintType::Sync;
139
140        assert!(matches!(trait_constraint, ConstraintType::Trait(_)));
141        assert!(matches!(lifetime_constraint, ConstraintType::Lifetime));
142        assert!(matches!(sized_constraint, ConstraintType::Sized));
143        assert!(matches!(send_constraint, ConstraintType::Send));
144        assert!(matches!(sync_constraint, ConstraintType::Sync));
145    }
146
147    #[test]
148    fn test_instantiation_event_creation() {
149        let event = InstantiationEvent {
150            base_type: "Vec".to_string(),
151            type_parameters: vec!["u8".to_string()],
152            ptr: 0x3000,
153            timestamp: 1000,
154            thread_id: "main".to_string(),
155        };
156
157        assert_eq!(event.base_type, "Vec");
158        assert_eq!(event.timestamp, 1000);
159        assert_eq!(event.thread_id, "main");
160    }
161
162    #[test]
163    fn test_constraint_violation_creation() {
164        let constraint = GenericConstraint {
165            parameter_name: "T".to_string(),
166            constraint_type: ConstraintType::Trait("Clone".to_string()),
167            description: "T must be Clone".to_string(),
168        };
169
170        let violation = ConstraintViolation {
171            constraint,
172            actual_type: "MyType".to_string(),
173            violation_type: ViolationType::MissingTraitImpl,
174            timestamp: 2000,
175        };
176
177        assert_eq!(violation.actual_type, "MyType");
178        assert!(matches!(
179            violation.violation_type,
180            ViolationType::MissingTraitImpl
181        ));
182    }
183
184    #[test]
185    fn test_violation_type_variants() {
186        let not_satisfied = ViolationType::ConstraintNotSatisfied;
187        let lifetime_mismatch = ViolationType::LifetimeMismatch;
188        let missing_trait = ViolationType::MissingTraitImpl;
189
190        assert!(matches!(
191            not_satisfied,
192            ViolationType::ConstraintNotSatisfied
193        ));
194        assert!(matches!(lifetime_mismatch, ViolationType::LifetimeMismatch));
195        assert!(matches!(missing_trait, ViolationType::MissingTraitImpl));
196    }
197
198    #[test]
199    fn test_generic_statistics_creation() {
200        let stats = GenericStatistics {
201            total_instances: 100,
202            unique_base_types: 10,
203            total_instantiations: 500,
204            constraint_violations: 5,
205            most_used_types: vec![("Vec<u8>".to_string(), 50)],
206            type_aliases_count: 3,
207        };
208
209        assert_eq!(stats.total_instances, 100);
210        assert_eq!(stats.unique_base_types, 10);
211        assert_eq!(stats.most_used_types.len(), 1);
212    }
213
214    #[test]
215    fn test_generic_statistics_default_values() {
216        let stats = GenericStatistics {
217            total_instances: 0,
218            unique_base_types: 0,
219            total_instantiations: 0,
220            constraint_violations: 0,
221            most_used_types: vec![],
222            type_aliases_count: 0,
223        };
224
225        assert_eq!(stats.total_instances, 0);
226        assert!(stats.most_used_types.is_empty());
227    }
228
229    #[test]
230    fn test_type_alias_info_creation() {
231        let alias = TypeAliasInfo {
232            alias_name: "MyResult".to_string(),
233            underlying_type: "Result<T, MyError>".to_string(),
234            base_type: "Result".to_string(),
235            type_parameters: vec!["T".to_string()],
236            usage_count: 25,
237        };
238
239        assert_eq!(alias.alias_name, "MyResult");
240        assert_eq!(alias.usage_count, 25);
241    }
242
243    #[test]
244    fn test_serialization() {
245        let instance = GenericInstance {
246            name: "Option<i32>".to_string(),
247            base_type: "Option".to_string(),
248            underlying_type: "Option<i32>".to_string(),
249            type_parameters: vec!["i32".to_string()],
250            ptr: 0x1000,
251            size: 4,
252            constraints: vec![],
253            is_type_alias: false,
254        };
255
256        let json = serde_json::to_string(&instance);
257        assert!(json.is_ok());
258
259        let deserialized: Result<GenericInstance, _> = serde_json::from_str(&json.unwrap());
260        assert!(deserialized.is_ok());
261    }
262
263    #[test]
264    fn test_constraint_serialization() {
265        let constraint = GenericConstraint {
266            parameter_name: "T".to_string(),
267            constraint_type: ConstraintType::Trait("Debug".to_string()),
268            description: "Test constraint".to_string(),
269        };
270
271        let json = serde_json::to_string(&constraint);
272        assert!(json.is_ok());
273
274        let deserialized: Result<GenericConstraint, _> = serde_json::from_str(&json.unwrap());
275        assert!(deserialized.is_ok());
276    }
277
278    #[test]
279    fn test_statistics_serialization() {
280        let stats = GenericStatistics {
281            total_instances: 10,
282            unique_base_types: 5,
283            total_instantiations: 20,
284            constraint_violations: 1,
285            most_used_types: vec![("String".to_string(), 100)],
286            type_aliases_count: 2,
287        };
288
289        let json = serde_json::to_string(&stats);
290        assert!(json.is_ok());
291
292        let deserialized: Result<GenericStatistics, _> = serde_json::from_str(&json.unwrap());
293        assert!(deserialized.is_ok());
294    }
295
296    #[test]
297    fn test_instantiation_event_serialization() {
298        let event = InstantiationEvent {
299            base_type: "Box".to_string(),
300            type_parameters: vec!["dyn Any".to_string()],
301            ptr: 0x5000,
302            timestamp: 9999,
303            thread_id: "worker-1".to_string(),
304        };
305
306        let json = serde_json::to_string(&event);
307        assert!(json.is_ok());
308
309        let deserialized: Result<InstantiationEvent, _> = serde_json::from_str(&json.unwrap());
310        assert!(deserialized.is_ok());
311    }
312
313    #[test]
314    fn test_violation_serialization() {
315        let violation = ConstraintViolation {
316            constraint: GenericConstraint {
317                parameter_name: "T".to_string(),
318                constraint_type: ConstraintType::Sync,
319                description: "Must be Sync".to_string(),
320            },
321            actual_type: "Rc<i32>".to_string(),
322            violation_type: ViolationType::ConstraintNotSatisfied,
323            timestamp: 5000,
324        };
325
326        let json = serde_json::to_string(&violation);
327        assert!(json.is_ok());
328
329        let deserialized: Result<ConstraintViolation, _> = serde_json::from_str(&json.unwrap());
330        assert!(deserialized.is_ok());
331    }
332
333    #[test]
334    fn test_type_alias_serialization() {
335        let alias = TypeAliasInfo {
336            alias_name: "IntList".to_string(),
337            underlying_type: "Vec<i32>".to_string(),
338            base_type: "Vec".to_string(),
339            type_parameters: vec!["i32".to_string()],
340            usage_count: 10,
341        };
342
343        let json = serde_json::to_string(&alias);
344        assert!(json.is_ok());
345
346        let deserialized: Result<TypeAliasInfo, _> = serde_json::from_str(&json.unwrap());
347        assert!(deserialized.is_ok());
348    }
349
350    #[test]
351    fn test_generic_instance_debug() {
352        let instance = GenericInstance {
353            name: "Test".to_string(),
354            base_type: "Base".to_string(),
355            underlying_type: "Underlying".to_string(),
356            type_parameters: vec![],
357            ptr: 0,
358            size: 0,
359            constraints: vec![],
360            is_type_alias: false,
361        };
362
363        let debug_str = format!("{:?}", instance);
364        assert!(debug_str.contains("GenericInstance"));
365    }
366
367    #[test]
368    fn test_generic_instance_clone() {
369        let instance = GenericInstance {
370            name: "Original".to_string(),
371            base_type: "Base".to_string(),
372            underlying_type: "Underlying".to_string(),
373            type_parameters: vec!["T".to_string()],
374            ptr: 0x1000,
375            size: 8,
376            constraints: vec![],
377            is_type_alias: true,
378        };
379
380        let cloned = instance.clone();
381        assert_eq!(cloned.name, instance.name);
382        assert_eq!(cloned.ptr, instance.ptr);
383    }
384
385    #[test]
386    fn test_empty_type_parameters() {
387        let instance = GenericInstance {
388            name: "String".to_string(),
389            base_type: "String".to_string(),
390            underlying_type: "String".to_string(),
391            type_parameters: vec![],
392            ptr: 0x1000,
393            size: 24,
394            constraints: vec![],
395            is_type_alias: false,
396        };
397
398        assert!(instance.type_parameters.is_empty());
399    }
400
401    #[test]
402    fn test_multiple_type_parameters() {
403        let instance = GenericInstance {
404            name: "HashMap<K, V>".to_string(),
405            base_type: "HashMap".to_string(),
406            underlying_type: "HashMap<String, i32>".to_string(),
407            type_parameters: vec!["String".to_string(), "i32".to_string()],
408            ptr: 0x2000,
409            size: 48,
410            constraints: vec![],
411            is_type_alias: false,
412        };
413
414        assert_eq!(instance.type_parameters.len(), 2);
415    }
416}