1use crate::event::Event;
14use serde::{Deserialize, Serialize};
15
16#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
18pub struct LifetimeRelation {
19 pub borrower_id: String,
21 pub borrowed_id: String,
23 pub start_time: u64,
25 pub end_time: Option<u64>,
27 pub is_mutable: bool,
29}
30
31impl LifetimeRelation {
32 pub fn new(
34 borrower_id: String,
35 borrowed_id: String,
36 start_time: u64,
37 is_mutable: bool,
38 ) -> Self {
39 Self {
40 borrower_id,
41 borrowed_id,
42 start_time,
43 end_time: None,
44 is_mutable,
45 }
46 }
47
48 pub fn is_active(&self) -> bool {
50 self.end_time.is_none()
51 }
52
53 pub fn duration(&self) -> Option<u64> {
55 self.end_time.map(|end| end - self.start_time)
56 }
57
58 pub fn overlaps_with(&self, other: &LifetimeRelation) -> bool {
62 let self_end = self.end_time.unwrap_or(u64::MAX);
63 let other_end = other.end_time.unwrap_or(u64::MAX);
64
65 self.start_time < other_end && other.start_time < self_end
66 }
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct Timeline {
72 pub relations: Vec<LifetimeRelation>,
74 pub min_time: u64,
76 pub max_time: u64,
78}
79
80impl Timeline {
81 pub fn from_events(events: &[Event]) -> Self {
83 let mut relations = Vec::new();
84 let mut active_borrows: std::collections::HashMap<String, (String, u64, bool)> =
85 std::collections::HashMap::new();
86
87 let mut min_time = u64::MAX;
88 let mut max_time = 0;
89
90 for event in events {
91 let timestamp = event.timestamp();
92 min_time = min_time.min(timestamp);
93 max_time = max_time.max(timestamp);
94
95 match event {
96 Event::Borrow {
97 borrower_id,
98 owner_id,
99 mutable,
100 timestamp,
101 ..
102 } => {
103 active_borrows.insert(
104 borrower_id.clone(),
105 (owner_id.clone(), *timestamp, *mutable),
106 );
107 }
108 Event::Drop { var_id, timestamp } => {
109 if let Some((borrowed_id, start_time, is_mutable)) =
110 active_borrows.remove(var_id)
111 {
112 let mut relation = LifetimeRelation::new(
113 var_id.clone(),
114 borrowed_id,
115 start_time,
116 is_mutable,
117 );
118 relation.end_time = Some(*timestamp);
119 relations.push(relation);
120 }
121 }
122 _ => {}
123 }
124 }
125
126 for (borrower_id, (borrowed_id, start_time, is_mutable)) in active_borrows {
128 relations.push(LifetimeRelation::new(
129 borrower_id,
130 borrowed_id,
131 start_time,
132 is_mutable,
133 ));
134 }
135
136 Self {
137 relations,
138 min_time: if min_time == u64::MAX { 0 } else { min_time },
139 max_time,
140 }
141 }
142
143 pub fn relations_for(&self, var_id: &str) -> Vec<&LifetimeRelation> {
145 self.relations
146 .iter()
147 .filter(|r| r.borrower_id == var_id || r.borrowed_id == var_id)
148 .collect()
149 }
150
151 pub fn active_at(&self, timestamp: u64) -> Vec<&LifetimeRelation> {
153 self.relations
154 .iter()
155 .filter(|r| r.start_time <= timestamp && r.end_time.map_or(true, |end| timestamp < end))
156 .collect()
157 }
158
159 pub fn lifetimes_overlap(&self, var1: &str, var2: &str) -> bool {
161 let relations1 = self.relations_for(var1);
162 let relations2 = self.relations_for(var2);
163
164 for r1 in &relations1 {
165 for r2 in &relations2 {
166 if r1.overlaps_with(r2) {
167 return true;
168 }
169 }
170 }
171 false
172 }
173
174 pub fn total_duration(&self) -> u64 {
176 self.max_time.saturating_sub(self.min_time)
177 }
178}
179
180#[derive(Debug, Clone, Copy, PartialEq, Eq)]
182pub enum ElisionRule {
183 EachInputOwn,
185 SingleInputToOutput,
187 SelfToOutput,
189}
190
191impl ElisionRule {
192 pub fn description(&self) -> &'static str {
194 match self {
195 ElisionRule::EachInputOwn => "Each input parameter gets its own lifetime",
196 ElisionRule::SingleInputToOutput => "If one input parameter, output gets that lifetime",
197 ElisionRule::SelfToOutput => {
198 "If multiple inputs with &self, output gets self's lifetime"
199 }
200 }
201 }
202}
203
204#[cfg(test)]
205mod tests {
206 use super::*;
207
208 #[test]
209 fn test_lifetime_relation_creation() {
210 let relation = LifetimeRelation::new("r".to_string(), "x".to_string(), 100, false);
211
212 assert_eq!(relation.borrower_id, "r");
213 assert_eq!(relation.borrowed_id, "x");
214 assert_eq!(relation.start_time, 100);
215 assert_eq!(relation.end_time, None);
216 assert!(!relation.is_mutable);
217 assert!(relation.is_active());
218 }
219
220 #[test]
221 fn test_lifetime_relation_duration() {
222 let mut relation = LifetimeRelation::new("r".to_string(), "x".to_string(), 100, false);
223
224 assert_eq!(relation.duration(), None);
225
226 relation.end_time = Some(150);
227 assert_eq!(relation.duration(), Some(50));
228 assert!(!relation.is_active());
229 }
230
231 #[test]
232 fn test_lifetime_overlap() {
233 let r1 = LifetimeRelation {
234 borrower_id: "r1".to_string(),
235 borrowed_id: "x".to_string(),
236 start_time: 100,
237 end_time: Some(200),
238 is_mutable: false,
239 };
240
241 let r2 = LifetimeRelation {
242 borrower_id: "r2".to_string(),
243 borrowed_id: "x".to_string(),
244 start_time: 150,
245 end_time: Some(250),
246 is_mutable: false,
247 };
248
249 let r3 = LifetimeRelation {
250 borrower_id: "r3".to_string(),
251 borrowed_id: "x".to_string(),
252 start_time: 300,
253 end_time: Some(400),
254 is_mutable: false,
255 };
256
257 assert!(r1.overlaps_with(&r2));
258 assert!(r2.overlaps_with(&r1));
259 assert!(!r1.overlaps_with(&r3));
260 assert!(!r3.overlaps_with(&r1));
261 }
262
263 #[test]
264 fn test_timeline_from_events() {
265 let events = vec![
266 Event::New {
267 timestamp: 0,
268 var_name: "x".to_string(),
269 var_id: "x_0".to_string(),
270 type_name: "i32".to_string(),
271 },
272 Event::Borrow {
273 timestamp: 10,
274 borrower_name: "r1".to_string(),
275 borrower_id: "r1_0".to_string(),
276 owner_id: "x_0".to_string(),
277 mutable: false,
278 },
279 Event::Borrow {
280 timestamp: 20,
281 borrower_name: "r2".to_string(),
282 borrower_id: "r2_0".to_string(),
283 owner_id: "x_0".to_string(),
284 mutable: false,
285 },
286 Event::Drop {
287 timestamp: 30,
288 var_id: "r2_0".to_string(),
289 },
290 Event::Drop {
291 timestamp: 40,
292 var_id: "r1_0".to_string(),
293 },
294 Event::Drop {
295 timestamp: 50,
296 var_id: "x_0".to_string(),
297 },
298 ];
299
300 let timeline = Timeline::from_events(&events);
301
302 assert_eq!(timeline.relations.len(), 2);
303 assert_eq!(timeline.min_time, 0);
304 assert_eq!(timeline.max_time, 50);
305 assert_eq!(timeline.total_duration(), 50);
306
307 let r1_relation = timeline
309 .relations
310 .iter()
311 .find(|r| r.borrower_id == "r1_0")
312 .unwrap();
313 assert_eq!(r1_relation.borrowed_id, "x_0");
314 assert_eq!(r1_relation.start_time, 10);
315 assert_eq!(r1_relation.end_time, Some(40));
316 assert_eq!(r1_relation.duration(), Some(30));
317
318 let r2_relation = timeline
320 .relations
321 .iter()
322 .find(|r| r.borrower_id == "r2_0")
323 .unwrap();
324 assert_eq!(r2_relation.borrowed_id, "x_0");
325 assert_eq!(r2_relation.start_time, 20);
326 assert_eq!(r2_relation.end_time, Some(30));
327 assert_eq!(r2_relation.duration(), Some(10));
328 }
329
330 #[test]
331 fn test_timeline_relations_for() {
332 let events = vec![
333 Event::New {
334 timestamp: 0,
335 var_name: "x".to_string(),
336 var_id: "x_0".to_string(),
337 type_name: "i32".to_string(),
338 },
339 Event::Borrow {
340 timestamp: 10,
341 borrower_name: "r".to_string(),
342 borrower_id: "r_0".to_string(),
343 owner_id: "x_0".to_string(),
344 mutable: false,
345 },
346 Event::Drop {
347 timestamp: 20,
348 var_id: "r_0".to_string(),
349 },
350 ];
351
352 let timeline = Timeline::from_events(&events);
353
354 let x_relations = timeline.relations_for("x_0");
355 assert_eq!(x_relations.len(), 1);
356 assert_eq!(x_relations[0].borrowed_id, "x_0");
357
358 let r_relations = timeline.relations_for("r_0");
359 assert_eq!(r_relations.len(), 1);
360 assert_eq!(r_relations[0].borrower_id, "r_0");
361 }
362
363 #[test]
364 fn test_timeline_active_at() {
365 let events = vec![
366 Event::Borrow {
367 timestamp: 10,
368 borrower_name: "r1".to_string(),
369 borrower_id: "r1_0".to_string(),
370 owner_id: "x_0".to_string(),
371 mutable: false,
372 },
373 Event::Borrow {
374 timestamp: 20,
375 borrower_name: "r2".to_string(),
376 borrower_id: "r2_0".to_string(),
377 owner_id: "x_0".to_string(),
378 mutable: false,
379 },
380 Event::Drop {
381 timestamp: 30,
382 var_id: "r1_0".to_string(),
383 },
384 ];
385
386 let timeline = Timeline::from_events(&events);
387
388 let active_at_15 = timeline.active_at(15);
390 assert_eq!(active_at_15.len(), 1);
391 assert_eq!(active_at_15[0].borrower_id, "r1_0");
392
393 let active_at_25 = timeline.active_at(25);
395 assert_eq!(active_at_25.len(), 2);
396
397 let active_at_35 = timeline.active_at(35);
399 assert_eq!(active_at_35.len(), 1);
400 assert_eq!(active_at_35[0].borrower_id, "r2_0");
401 }
402
403 #[test]
404 fn test_timeline_lifetimes_overlap() {
405 let events = vec![
406 Event::Borrow {
407 timestamp: 10,
408 borrower_name: "r1".to_string(),
409 borrower_id: "r1_0".to_string(),
410 owner_id: "x_0".to_string(),
411 mutable: false,
412 },
413 Event::Borrow {
414 timestamp: 20,
415 borrower_name: "r2".to_string(),
416 borrower_id: "r2_0".to_string(),
417 owner_id: "x_0".to_string(),
418 mutable: false,
419 },
420 Event::Drop {
421 timestamp: 30,
422 var_id: "r1_0".to_string(),
423 },
424 Event::Drop {
425 timestamp: 40,
426 var_id: "r2_0".to_string(),
427 },
428 ];
429
430 let timeline = Timeline::from_events(&events);
431
432 assert!(timeline.lifetimes_overlap("r1_0", "r2_0"));
434 }
435
436 #[test]
437 fn test_mutable_borrow_tracking() {
438 let events = vec![
439 Event::Borrow {
440 timestamp: 10,
441 borrower_name: "r".to_string(),
442 borrower_id: "r_0".to_string(),
443 owner_id: "x_0".to_string(),
444 mutable: true,
445 },
446 Event::Drop {
447 timestamp: 20,
448 var_id: "r_0".to_string(),
449 },
450 ];
451
452 let timeline = Timeline::from_events(&events);
453
454 assert_eq!(timeline.relations.len(), 1);
455 assert!(timeline.relations[0].is_mutable);
456 }
457
458 #[test]
459 fn test_elision_rule_descriptions() {
460 assert!(!ElisionRule::EachInputOwn.description().is_empty());
461 assert!(!ElisionRule::SingleInputToOutput.description().is_empty());
462 assert!(!ElisionRule::SelfToOutput.description().is_empty());
463 }
464
465 #[test]
466 fn test_empty_timeline() {
467 let timeline = Timeline::from_events(&[]);
468
469 assert_eq!(timeline.relations.len(), 0);
470 assert_eq!(timeline.min_time, 0);
471 assert_eq!(timeline.max_time, 0);
472 assert_eq!(timeline.total_duration(), 0);
473 }
474
475 #[test]
476 fn test_nested_lifetimes() {
477 let events = vec![
478 Event::Borrow {
479 timestamp: 10,
480 borrower_name: "r1".to_string(),
481 borrower_id: "r1_0".to_string(),
482 owner_id: "x_0".to_string(),
483 mutable: false,
484 },
485 Event::Borrow {
486 timestamp: 15,
487 borrower_name: "r2".to_string(),
488 borrower_id: "r2_0".to_string(),
489 owner_id: "x_0".to_string(),
490 mutable: false,
491 },
492 Event::Drop {
493 timestamp: 20,
494 var_id: "r2_0".to_string(),
495 },
496 Event::Drop {
497 timestamp: 25,
498 var_id: "r1_0".to_string(),
499 },
500 ];
501
502 let timeline = Timeline::from_events(&events);
503
504 let r1 = timeline
506 .relations
507 .iter()
508 .find(|r| r.borrower_id == "r1_0")
509 .unwrap();
510 let r2 = timeline
511 .relations
512 .iter()
513 .find(|r| r.borrower_id == "r2_0")
514 .unwrap();
515
516 assert!(r1.start_time < r2.start_time);
517 assert!(r1.end_time.unwrap() > r2.end_time.unwrap());
518 assert!(r1.overlaps_with(r2));
519 }
520}