1use std::collections::{HashMap, HashSet};
7
8#[derive(Debug, Clone, PartialEq, Eq, Hash)]
10pub struct Lifetime {
11 pub name: String,
12}
13
14impl Lifetime {
15 pub fn new(name: impl Into<String>) -> Self {
16 Self { name: name.into() }
17 }
18
19 pub fn anonymous() -> Self {
20 Self::new("_")
21 }
22
23 pub fn static_lifetime() -> Self {
24 Self::new("static")
25 }
26
27 pub fn to_string(&self) -> String {
28 format!("'{}", self.name)
29 }
30}
31
32#[derive(Debug, Clone)]
34pub struct TypeWithLifetime {
35 pub base_type: String,
36 pub lifetimes: Vec<Lifetime>,
37 pub is_reference: bool,
38 pub is_mutable: bool,
39}
40
41impl TypeWithLifetime {
42 pub fn new(base_type: impl Into<String>) -> Self {
43 Self {
44 base_type: base_type.into(),
45 lifetimes: vec![],
46 is_reference: false,
47 is_mutable: false,
48 }
49 }
50
51 pub fn with_lifetime(mut self, lifetime: Lifetime) -> Self {
52 self.lifetimes.push(lifetime);
53 self
54 }
55
56 pub fn as_reference(mut self) -> Self {
57 self.is_reference = true;
58 self
59 }
60
61 pub fn as_mut_reference(mut self) -> Self {
62 self.is_reference = true;
63 self.is_mutable = true;
64 self
65 }
66
67 pub fn to_rust_string(&self) -> String {
68 let mut result = String::new();
69
70 if self.is_reference {
71 result.push('&');
72 if !self.lifetimes.is_empty() {
73 result.push_str(&self.lifetimes[0].to_string());
74 result.push(' ');
75 }
76 if self.is_mutable {
77 result.push_str("mut ");
78 }
79 }
80
81 result.push_str(&self.base_type);
82
83 if !self.is_reference && !self.lifetimes.is_empty() {
85 result.push('<');
86 let lifetime_strs: Vec<_> = self.lifetimes.iter().map(|l| l.to_string()).collect();
87 result.push_str(&lifetime_strs.join(", "));
88 result.push('>');
89 }
90
91 result
92 }
93}
94
95#[derive(Debug, Clone)]
97pub enum LifetimeConstraint {
98 Outlives(Lifetime, Lifetime),
100 Equal(Lifetime, Lifetime),
102 Static(Lifetime),
104}
105
106#[derive(Debug, Clone)]
108pub struct FunctionSignature {
109 pub name: String,
110 pub lifetime_params: Vec<Lifetime>,
111 pub params: Vec<(String, TypeWithLifetime)>,
112 pub return_type: Option<TypeWithLifetime>,
113 pub constraints: Vec<LifetimeConstraint>,
114}
115
116impl FunctionSignature {
117 pub fn new(name: impl Into<String>) -> Self {
118 Self {
119 name: name.into(),
120 lifetime_params: vec![],
121 params: vec![],
122 return_type: None,
123 constraints: vec![],
124 }
125 }
126
127 pub fn add_lifetime_param(&mut self, lifetime: Lifetime) {
128 if !self.lifetime_params.contains(&lifetime) {
129 self.lifetime_params.push(lifetime);
130 }
131 }
132
133 pub fn add_param(&mut self, name: String, ty: TypeWithLifetime) {
134 for lifetime in &ty.lifetimes {
136 self.add_lifetime_param(lifetime.clone());
137 }
138 self.params.push((name, ty));
139 }
140
141 pub fn set_return_type(&mut self, ty: TypeWithLifetime) {
142 for lifetime in &ty.lifetimes {
144 self.add_lifetime_param(lifetime.clone());
145 }
146 self.return_type = Some(ty);
147 }
148
149 pub fn to_rust_string(&self) -> String {
150 let mut result = format!("fn {}", self.name);
151
152 if !self.lifetime_params.is_empty() {
154 result.push('<');
155 let lifetime_strs: Vec<_> = self
156 .lifetime_params
157 .iter()
158 .map(|l| l.to_string())
159 .collect();
160 result.push_str(&lifetime_strs.join(", "));
161 result.push('>');
162 }
163
164 result.push('(');
166 let param_strs: Vec<_> = self
167 .params
168 .iter()
169 .map(|(name, ty)| format!("{}: {}", name, ty.to_rust_string()))
170 .collect();
171 result.push_str(¶m_strs.join(", "));
172 result.push(')');
173
174 if let Some(ret_ty) = &self.return_type {
176 result.push_str(" -> ");
177 result.push_str(&ret_ty.to_rust_string());
178 }
179
180 result
181 }
182}
183
184#[derive(Debug, Clone)]
186pub struct StructDefinition {
187 pub name: String,
188 pub lifetime_params: Vec<Lifetime>,
189 pub fields: Vec<(String, TypeWithLifetime)>,
190}
191
192impl StructDefinition {
193 pub fn new(name: impl Into<String>) -> Self {
194 Self {
195 name: name.into(),
196 lifetime_params: vec![],
197 fields: vec![],
198 }
199 }
200
201 pub fn add_field(&mut self, name: String, ty: TypeWithLifetime) {
202 for lifetime in &ty.lifetimes {
204 if !self.lifetime_params.contains(lifetime) {
205 self.lifetime_params.push(lifetime.clone());
206 }
207 }
208 self.fields.push((name, ty));
209 }
210
211 pub fn to_rust_string(&self) -> String {
212 let mut result = format!("struct {}", self.name);
213
214 if !self.lifetime_params.is_empty() {
216 result.push('<');
217 let lifetime_strs: Vec<_> = self
218 .lifetime_params
219 .iter()
220 .map(|l| l.to_string())
221 .collect();
222 result.push_str(&lifetime_strs.join(", "));
223 result.push('>');
224 }
225
226 result.push_str(" {\n");
227
228 for (name, ty) in &self.fields {
230 result.push_str(&format!(" {}: {},\n", name, ty.to_rust_string()));
231 }
232
233 result.push('}');
234 result
235 }
236}
237
238pub struct LifetimeAnalyzer {
240 lifetime_counter: usize,
242 scope_lifetimes: HashMap<String, Lifetime>,
244 reference_patterns: Vec<ReferencePattern>,
246}
247
248#[derive(Debug, Clone)]
250pub enum ReferencePattern {
251 Borrow { var: String, is_mutable: bool },
253 ReturnRef { param: String },
255 StructRef { field: String, source: String },
257 CollectionRef { container: String, element: String },
259}
260
261impl LifetimeAnalyzer {
262 pub fn new() -> Self {
263 Self {
264 lifetime_counter: 0,
265 scope_lifetimes: HashMap::new(),
266 reference_patterns: Vec::new(),
267 }
268 }
269
270 pub fn fresh_lifetime(&mut self) -> Lifetime {
272 let name = format!("a{}", self.lifetime_counter);
273 self.lifetime_counter += 1;
274 Lifetime::new(name)
275 }
276
277 pub fn analyze_function(
279 &mut self,
280 params: &[(String, String, bool)], return_type: Option<(&str, bool)>, returns_param: Option<&str>, ) -> FunctionSignature {
284 let mut sig = FunctionSignature::new("function");
285
286 if let Some(elided) = self.try_elision(params, return_type, returns_param) {
288 return elided;
289 }
290
291 let mut param_lifetimes: HashMap<String, Lifetime> = HashMap::new();
293
294 for (name, ty, is_ref) in params {
295 let param_ty = if *is_ref {
296 let lifetime = self.fresh_lifetime();
297 param_lifetimes.insert(name.clone(), lifetime.clone());
298 TypeWithLifetime::new(ty.clone())
299 .as_reference()
300 .with_lifetime(lifetime)
301 } else {
302 TypeWithLifetime::new(ty.clone())
303 };
304
305 sig.add_param(name.clone(), param_ty);
306 }
307
308 if let Some((ret_ty, is_ref)) = return_type {
310 if is_ref {
311 if let Some(param_name) = returns_param {
313 if let Some(lifetime) = param_lifetimes.get(param_name) {
314 let return_ty = TypeWithLifetime::new(ret_ty)
315 .as_reference()
316 .with_lifetime(lifetime.clone());
317 sig.set_return_type(return_ty);
318 }
319 } else {
320 let lifetime = self.fresh_lifetime();
322 let return_ty = TypeWithLifetime::new(ret_ty)
323 .as_reference()
324 .with_lifetime(lifetime);
325 sig.set_return_type(return_ty);
326 }
327 } else {
328 sig.set_return_type(TypeWithLifetime::new(ret_ty));
329 }
330 }
331
332 sig
333 }
334
335 fn try_elision(
337 &mut self,
338 params: &[(String, String, bool)],
339 return_type: Option<(&str, bool)>,
340 returns_param: Option<&str>,
341 ) -> Option<FunctionSignature> {
342 let ref_params: Vec<_> = params.iter().filter(|(_, _, is_ref)| *is_ref).collect();
343
344 if ref_params.is_empty() {
349 let mut sig = FunctionSignature::new("function");
351 for (name, ty, _) in params {
352 sig.add_param(name.clone(), TypeWithLifetime::new(ty.clone()));
353 }
354 if let Some((ret_ty, _)) = return_type {
355 sig.set_return_type(TypeWithLifetime::new(ret_ty));
356 }
357 return Some(sig);
358 }
359
360 if ref_params.len() == 1 {
361 if let Some((ret_ty, true)) = return_type {
363 let mut sig = FunctionSignature::new("function");
364
365 for (name, ty, is_ref) in params {
367 if *is_ref {
368 sig.add_param(name.clone(), TypeWithLifetime::new(ty.clone()).as_reference());
369 } else {
370 sig.add_param(name.clone(), TypeWithLifetime::new(ty.clone()));
371 }
372 }
373
374 sig.set_return_type(TypeWithLifetime::new(ret_ty).as_reference());
375 return Some(sig);
376 }
377 }
378
379 None
380 }
381
382 pub fn analyze_struct(&mut self, fields: &[(String, String, bool)]) -> StructDefinition {
384 let mut struct_def = StructDefinition::new("Struct");
385
386 let mut has_references = false;
388 let lifetime = self.fresh_lifetime();
389
390 for (name, ty, is_ref) in fields {
391 let field_ty = if *is_ref {
392 has_references = true;
393 TypeWithLifetime::new(ty.clone())
394 .as_reference()
395 .with_lifetime(lifetime.clone())
396 } else {
397 TypeWithLifetime::new(ty.clone())
398 };
399
400 struct_def.add_field(name.clone(), field_ty);
401 }
402
403 struct_def
404 }
405
406 pub fn generate_trait_bounds(&self, lifetimes: &[Lifetime]) -> Vec<String> {
408 let mut bounds = Vec::new();
409
410 for lifetime in lifetimes {
411 bounds.push(format!("{}: 'static", lifetime.to_string()));
414 }
415
416 bounds
417 }
418
419 pub fn detect_pattern(&mut self, pattern: ReferencePattern) {
421 self.reference_patterns.push(pattern);
422 }
423
424 pub fn generate_annotations(&self) -> Vec<String> {
426 let mut annotations = Vec::new();
427
428 for pattern in &self.reference_patterns {
429 match pattern {
430 ReferencePattern::Borrow { var, is_mutable } => {
431 let mutability = if *is_mutable { "mut " } else { "" };
432 annotations.push(format!("&{}{}", mutability, var));
433 }
434 ReferencePattern::ReturnRef { param } => {
435 annotations.push(format!("// Returns reference to {}", param));
436 }
437 ReferencePattern::StructRef { field, source } => {
438 annotations.push(format!("// {} references {}", field, source));
439 }
440 ReferencePattern::CollectionRef { container, element } => {
441 annotations.push(format!("// {} contains references to {}", container, element));
442 }
443 }
444 }
445
446 annotations
447 }
448}
449
450impl Default for LifetimeAnalyzer {
451 fn default() -> Self {
452 Self::new()
453 }
454}
455
456pub struct LifetimePatterns;
458
459impl LifetimePatterns {
460 pub fn return_param_ref() -> String {
462 r#"fn first<'a>(x: &'a str, y: &str) -> &'a str {
463 x
464}"#
465 .to_string()
466 }
467
468 pub fn struct_with_ref() -> String {
470 r#"struct Container<'a> {
471 data: &'a str,
472}"#
473 .to_string()
474 }
475
476 pub fn multiple_lifetimes() -> String {
478 r#"fn combine<'a, 'b>(x: &'a str, y: &'b str) -> String {
479 format!("{}{}", x, y)
480}"#
481 .to_string()
482 }
483
484 pub fn lifetime_bounds() -> String {
486 r#"struct Wrapper<'a, T: 'a> {
487 data: &'a T,
488}"#
489 .to_string()
490 }
491
492 pub fn static_lifetime() -> String {
494 r#"const MESSAGE: &'static str = "Hello, World!";
495
496fn get_message() -> &'static str {
497 MESSAGE
498}"#
499 .to_string()
500 }
501
502 pub fn elision() -> String {
504 r#"// With elision (no explicit lifetimes needed):
505fn process(s: &str) -> &str {
506 s.trim()
507}
508
509// Equivalent to:
510fn process_explicit<'a>(s: &'a str) -> &'a str {
511 s.trim()
512}"#
513 .to_string()
514 }
515
516 pub fn self_lifetime() -> String {
518 r#"impl<'a> Container<'a> {
519 fn get_data(&self) -> &'a str {
520 self.data
521 }
522}"#
523 .to_string()
524 }
525}
526
527#[cfg(test)]
528mod tests {
529 use super::*;
530
531 #[test]
532 fn test_lifetime_creation() {
533 let lifetime = Lifetime::new("a");
534 assert_eq!(lifetime.to_string(), "'a");
535 }
536
537 #[test]
538 fn test_type_with_lifetime() {
539 let ty = TypeWithLifetime::new("str")
540 .as_reference()
541 .with_lifetime(Lifetime::new("a"));
542
543 assert_eq!(ty.to_rust_string(), "&'a str");
544 }
545
546 #[test]
547 fn test_function_signature() {
548 let mut sig = FunctionSignature::new("example");
549 sig.add_param(
550 "x".to_string(),
551 TypeWithLifetime::new("str")
552 .as_reference()
553 .with_lifetime(Lifetime::new("a")),
554 );
555 sig.set_return_type(
556 TypeWithLifetime::new("str")
557 .as_reference()
558 .with_lifetime(Lifetime::new("a")),
559 );
560
561 let rust = sig.to_rust_string();
562 assert!(rust.contains("fn example"));
563 assert!(rust.contains("'a"));
564 }
565
566 #[test]
567 fn test_elision_single_param() {
568 let mut analyzer = LifetimeAnalyzer::new();
569 let sig = analyzer.analyze_function(
570 &[("s".to_string(), "str".to_string(), true)],
571 Some(("str", true)),
572 Some("s"),
573 );
574
575 let rust = sig.to_rust_string();
577 assert!(rust.contains("&str"));
578 }
579
580 #[test]
581 fn test_struct_with_references() {
582 let mut analyzer = LifetimeAnalyzer::new();
583 let struct_def = analyzer.analyze_struct(&[
584 ("name".to_string(), "str".to_string(), true),
585 ("age".to_string(), "i32".to_string(), false),
586 ]);
587
588 let rust = struct_def.to_rust_string();
589 assert!(rust.contains("'a"));
590 assert!(rust.contains("&'a str"));
591 }
592}