1use crate::language_parser::GenericTypeDef;
2use crate::structure_comparator::{
3 ComparisonOptions, SourceLocation, Structure, StructureComparator, StructureComparisonResult,
4 StructureIdentifier, StructureKind, StructureMember, StructureMetadata,
5};
6
7impl From<GenericTypeDef> for Structure {
9 fn from(type_def: GenericTypeDef) -> Self {
10 let kind = match type_def.kind.as_str() {
11 "struct" => StructureKind::RustStruct,
12 "enum" => StructureKind::RustEnum,
13 _ => StructureKind::Generic(type_def.kind.clone()),
14 };
15
16 let members = type_def
17 .fields
18 .into_iter()
19 .map(|field| {
20 let (name, value_type) = if type_def.kind == "enum" {
23 (field.clone(), "variant".to_string())
25 } else {
26 (field.clone(), "unknown".to_string())
29 };
30
31 StructureMember { name, value_type, modifiers: vec![], nested: None }
32 })
33 .collect();
34
35 Structure {
36 identifier: StructureIdentifier {
37 name: type_def.name.clone(),
38 kind,
39 namespace: None, },
41 members,
42 metadata: StructureMetadata {
43 location: SourceLocation {
44 file_path: String::new(), start_line: type_def.start_line as usize,
46 end_line: type_def.end_line as usize,
47 },
48 generics: Vec::new(), extends: Vec::new(), visibility: None, },
52 }
53 }
54}
55
56#[derive(Debug, Clone)]
58pub struct RustStructDef {
59 pub name: String,
60 pub fields: Vec<RustFieldDef>,
61 pub generics: Vec<String>,
62 pub derives: Vec<String>,
63 pub attributes: Vec<String>, pub visibility: Option<String>,
65 pub is_tuple_struct: bool,
66 pub start_line: usize,
67 pub end_line: usize,
68 pub file_path: String,
69}
70
71#[derive(Debug, Clone)]
72pub struct RustFieldDef {
73 pub name: String,
74 pub field_type: String,
75 pub visibility: Option<String>,
76}
77
78#[derive(Debug, Clone)]
80pub struct RustEnumDef {
81 pub name: String,
82 pub variants: Vec<RustVariantDef>,
83 pub generics: Vec<String>,
84 pub derives: Vec<String>,
85 pub attributes: Vec<String>, pub visibility: Option<String>,
87 pub start_line: usize,
88 pub end_line: usize,
89 pub file_path: String,
90}
91
92#[derive(Debug, Clone)]
93pub struct RustVariantDef {
94 pub name: String,
95 pub variant_type: RustVariantType,
96}
97
98#[derive(Debug, Clone)]
99pub enum RustVariantType {
100 Unit,
101 Tuple(Vec<String>),
102 Struct(Vec<RustFieldDef>),
103}
104
105impl From<RustStructDef> for Structure {
107 fn from(struct_def: RustStructDef) -> Self {
108 let mut members: Vec<StructureMember> = struct_def
109 .fields
110 .into_iter()
111 .map(|field| StructureMember {
112 name: field.name,
113 value_type: field.field_type,
114 modifiers: field.visibility.map(|v| vec![v]).unwrap_or_default(),
115 nested: None,
116 })
117 .collect();
118
119 if !struct_def.derives.is_empty() {
121 members.push(StructureMember {
122 name: "@derives".to_string(),
123 value_type: struct_def.derives.join(", "),
124 modifiers: vec!["attribute".to_string()],
125 nested: None,
126 });
127 }
128
129 if !struct_def.attributes.is_empty() {
131 members.push(StructureMember {
132 name: "@attributes".to_string(),
133 value_type: struct_def.attributes.join(", "),
134 modifiers: vec!["attribute".to_string()],
135 nested: None,
136 });
137 }
138
139 Structure {
140 identifier: StructureIdentifier {
141 name: struct_def.name.clone(),
142 kind: StructureKind::RustStruct,
143 namespace: Some(struct_def.file_path.clone()),
144 },
145 members,
146 metadata: StructureMetadata {
147 location: SourceLocation {
148 file_path: struct_def.file_path,
149 start_line: struct_def.start_line,
150 end_line: struct_def.end_line,
151 },
152 generics: struct_def.generics,
153 extends: vec![], visibility: struct_def.visibility,
155 },
156 }
157 }
158}
159
160impl From<RustEnumDef> for Structure {
162 fn from(enum_def: RustEnumDef) -> Self {
163 let mut members: Vec<StructureMember> = enum_def
164 .variants
165 .into_iter()
166 .map(|variant| {
167 let value_type = match variant.variant_type {
168 RustVariantType::Unit => "unit".to_string(),
169 RustVariantType::Tuple(ref types) => format!("({})", types.join(", ")),
170 RustVariantType::Struct(ref fields) => {
171 let field_strs: Vec<String> = fields
172 .iter()
173 .map(|f| format!("{}: {}", f.name, f.field_type))
174 .collect();
175 format!("{{ {} }}", field_strs.join(", "))
176 }
177 };
178
179 StructureMember {
180 name: variant.name,
181 value_type,
182 modifiers: vec!["variant".to_string()],
183 nested: None,
184 }
185 })
186 .collect();
187
188 if !enum_def.derives.is_empty() {
190 members.push(StructureMember {
191 name: "@derives".to_string(),
192 value_type: enum_def.derives.join(", "),
193 modifiers: vec!["attribute".to_string()],
194 nested: None,
195 });
196 }
197
198 if !enum_def.attributes.is_empty() {
200 members.push(StructureMember {
201 name: "@attributes".to_string(),
202 value_type: enum_def.attributes.join(", "),
203 modifiers: vec!["attribute".to_string()],
204 nested: None,
205 });
206 }
207
208 Structure {
209 identifier: StructureIdentifier {
210 name: enum_def.name.clone(),
211 kind: StructureKind::RustEnum,
212 namespace: Some(enum_def.file_path.clone()),
213 },
214 members,
215 metadata: StructureMetadata {
216 location: SourceLocation {
217 file_path: enum_def.file_path,
218 start_line: enum_def.start_line,
219 end_line: enum_def.end_line,
220 },
221 generics: enum_def.generics,
222 extends: vec![], visibility: enum_def.visibility,
224 },
225 }
226 }
227}
228
229pub struct RustStructureComparator {
231 pub comparator: StructureComparator,
232}
233
234impl Default for RustStructureComparator {
235 fn default() -> Self {
236 Self::new()
237 }
238}
239
240impl RustStructureComparator {
241 pub fn new() -> Self {
242 let options = ComparisonOptions {
243 name_weight: 0.3,
244 structure_weight: 0.7,
245 threshold: 0.7,
246 ..Default::default()
247 };
248
249 Self { comparator: StructureComparator::new(options) }
250 }
251
252 pub fn with_options(options: ComparisonOptions) -> Self {
253 Self { comparator: StructureComparator::new(options) }
254 }
255
256 pub fn compare_structs(
258 &mut self,
259 struct1: &RustStructDef,
260 struct2: &RustStructDef,
261 ) -> StructureComparisonResult {
262 let s1 = Structure::from(struct1.clone());
263 let s2 = Structure::from(struct2.clone());
264 self.comparator.compare(&s1, &s2)
265 }
266
267 pub fn compare_enums(
269 &mut self,
270 enum1: &RustEnumDef,
271 enum2: &RustEnumDef,
272 ) -> StructureComparisonResult {
273 let s1 = Structure::from(enum1.clone());
274 let s2 = Structure::from(enum2.clone());
275 self.comparator.compare(&s1, &s2)
276 }
277
278 pub fn compare_generic_types(
280 &mut self,
281 type1: &GenericTypeDef,
282 type2: &GenericTypeDef,
283 ) -> StructureComparisonResult {
284 let s1 = Structure::from(type1.clone());
285 let s2 = Structure::from(type2.clone());
286 self.comparator.compare(&s1, &s2)
287 }
288}
289
290#[cfg(test)]
291mod tests {
292 use super::*;
293
294 #[test]
295 fn test_struct_to_structure_conversion() {
296 let rust_struct = RustStructDef {
297 name: "User".to_string(),
298 fields: vec![
299 RustFieldDef {
300 name: "id".to_string(),
301 field_type: "u64".to_string(),
302 visibility: Some("pub".to_string()),
303 },
304 RustFieldDef {
305 name: "name".to_string(),
306 field_type: "String".to_string(),
307 visibility: Some("pub".to_string()),
308 },
309 ],
310 generics: vec![],
311 derives: vec!["Debug".to_string(), "Clone".to_string()],
312 attributes: vec![],
313 visibility: Some("pub".to_string()),
314 is_tuple_struct: false,
315 start_line: 1,
316 end_line: 5,
317 file_path: "user.rs".to_string(),
318 };
319
320 let structure = Structure::from(rust_struct);
321
322 assert_eq!(structure.identifier.name, "User");
323 assert_eq!(structure.identifier.kind, StructureKind::RustStruct);
324 assert_eq!(structure.members.len(), 3); assert_eq!(structure.members[0].name, "id");
326 assert_eq!(structure.members[0].value_type, "u64");
327 assert_eq!(structure.members[2].name, "@derives");
329 assert_eq!(structure.members[2].value_type, "Debug, Clone");
330 }
331
332 #[test]
333 fn test_enum_to_structure_conversion() {
334 let rust_enum = RustEnumDef {
335 name: "Result".to_string(),
336 variants: vec![
337 RustVariantDef {
338 name: "Ok".to_string(),
339 variant_type: RustVariantType::Tuple(vec!["T".to_string()]),
340 },
341 RustVariantDef {
342 name: "Err".to_string(),
343 variant_type: RustVariantType::Tuple(vec!["E".to_string()]),
344 },
345 ],
346 generics: vec!["T".to_string(), "E".to_string()],
347 derives: vec!["Debug".to_string()],
348 attributes: vec![],
349 visibility: Some("pub".to_string()),
350 start_line: 1,
351 end_line: 4,
352 file_path: "result.rs".to_string(),
353 };
354
355 let structure = Structure::from(rust_enum);
356
357 assert_eq!(structure.identifier.name, "Result");
358 assert_eq!(structure.identifier.kind, StructureKind::RustEnum);
359 assert_eq!(structure.members.len(), 3); assert_eq!(structure.members[0].name, "Ok");
361 assert_eq!(structure.members[0].value_type, "(T)");
362 assert_eq!(structure.members[2].name, "@derives");
364 assert_eq!(structure.members[2].value_type, "Debug");
365 }
366
367 #[test]
368 fn test_rust_comparator() {
369 let mut comparator = RustStructureComparator::new();
370
371 let struct1 = RustStructDef {
372 name: "User".to_string(),
373 fields: vec![
374 RustFieldDef {
375 name: "id".to_string(),
376 field_type: "u64".to_string(),
377 visibility: Some("pub".to_string()),
378 },
379 RustFieldDef {
380 name: "name".to_string(),
381 field_type: "String".to_string(),
382 visibility: Some("pub".to_string()),
383 },
384 ],
385 generics: vec![],
386 derives: vec![],
387 attributes: vec![],
388 visibility: Some("pub".to_string()),
389 is_tuple_struct: false,
390 start_line: 1,
391 end_line: 5,
392 file_path: "user.rs".to_string(),
393 };
394
395 let struct2 = RustStructDef {
396 name: "Person".to_string(),
397 fields: vec![
398 RustFieldDef {
399 name: "id".to_string(),
400 field_type: "u64".to_string(),
401 visibility: Some("pub".to_string()),
402 },
403 RustFieldDef {
404 name: "name".to_string(),
405 field_type: "String".to_string(),
406 visibility: Some("pub".to_string()),
407 },
408 ],
409 generics: vec![],
410 derives: vec![],
411 attributes: vec![],
412 visibility: Some("pub".to_string()),
413 is_tuple_struct: false,
414 start_line: 10,
415 end_line: 15,
416 file_path: "person.rs".to_string(),
417 };
418
419 let result = comparator.compare_structs(&struct1, &struct2);
420
421 assert!(result.member_similarity > 0.9);
423 assert!(result.identifier_similarity < 0.5);
424 assert!(result.overall_similarity > 0.6);
425 }
426
427 #[test]
428 fn test_struct_comparison_with_derives() {
429 let mut comparator = RustStructureComparator::new();
430
431 let struct1 = RustStructDef {
432 name: "User".to_string(),
433 fields: vec![RustFieldDef {
434 name: "id".to_string(),
435 field_type: "u64".to_string(),
436 visibility: Some("pub".to_string()),
437 }],
438 generics: vec![],
439 derives: vec!["Debug".to_string(), "Clone".to_string(), "Serialize".to_string()],
440 attributes: vec![],
441 visibility: Some("pub".to_string()),
442 is_tuple_struct: false,
443 start_line: 1,
444 end_line: 5,
445 file_path: "user.rs".to_string(),
446 };
447
448 let struct2 = RustStructDef {
450 name: "User".to_string(),
451 fields: vec![RustFieldDef {
452 name: "id".to_string(),
453 field_type: "u64".to_string(),
454 visibility: Some("pub".to_string()),
455 }],
456 generics: vec![],
457 derives: vec!["Debug".to_string(), "PartialEq".to_string()],
458 attributes: vec![],
459 visibility: Some("pub".to_string()),
460 is_tuple_struct: false,
461 start_line: 10,
462 end_line: 14,
463 file_path: "user.rs".to_string(),
464 };
465
466 let result1 = comparator.compare_structs(&struct1, &struct2);
467
468 let struct3 = RustStructDef {
470 name: "User".to_string(),
471 fields: vec![RustFieldDef {
472 name: "id".to_string(),
473 field_type: "u64".to_string(),
474 visibility: Some("pub".to_string()),
475 }],
476 generics: vec![],
477 derives: vec!["Debug".to_string(), "Clone".to_string(), "Serialize".to_string()],
478 attributes: vec![],
479 visibility: Some("pub".to_string()),
480 is_tuple_struct: false,
481 start_line: 20,
482 end_line: 24,
483 file_path: "user.rs".to_string(),
484 };
485
486 let result2 = comparator.compare_structs(&struct1, &struct3);
487
488 assert!(result2.overall_similarity >= result1.overall_similarity);
491
492 let derives_match_result2 =
495 result2.member_matches.iter().find(|m| m.member1 == "@derives").map(|m| m.similarity);
496 assert_eq!(derives_match_result2, Some(1.0));
497
498 let derives_match_result1 =
500 result1.member_matches.iter().find(|m| m.member1 == "@derives").map(|m| m.similarity);
501 assert!(derives_match_result1.unwrap_or(0.0) < 1.0);
503
504 assert_eq!(result2.member_matches.len(), 2);
506 assert_eq!(result1.member_matches.len(), 2);
507 }
508}