Skip to main content

entrenar/citl/trainer/
trace.rs

1//! Decision trace types for CITL trainer
2
3use super::SourceSpan;
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6
7/// A single decision in the compiler trace
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct DecisionTrace {
10    /// Unique ID for this decision
11    pub id: String,
12    /// Type of decision (e.g., "type_inference", "borrow_check", "lifetime_resolution")
13    pub decision_type: String,
14    /// Description of the decision
15    pub description: String,
16    /// Source span where this decision was made
17    pub span: Option<SourceSpan>,
18    /// Timestamp (nanoseconds since session start)
19    pub timestamp_ns: u64,
20    /// Dependencies on other decisions
21    pub depends_on: Vec<String>,
22    /// Additional metadata
23    pub metadata: HashMap<String, String>,
24}
25
26impl DecisionTrace {
27    /// Create a new decision trace
28    #[must_use]
29    pub fn new(
30        id: impl Into<String>,
31        decision_type: impl Into<String>,
32        description: impl Into<String>,
33    ) -> Self {
34        Self {
35            id: id.into(),
36            decision_type: decision_type.into(),
37            description: description.into(),
38            span: None,
39            timestamp_ns: 0,
40            depends_on: Vec::new(),
41            metadata: HashMap::new(),
42        }
43    }
44
45    /// Set the source span
46    #[must_use]
47    pub fn with_span(mut self, span: SourceSpan) -> Self {
48        self.span = Some(span);
49        self
50    }
51
52    /// Set the timestamp
53    #[must_use]
54    pub fn with_timestamp(mut self, timestamp_ns: u64) -> Self {
55        self.timestamp_ns = timestamp_ns;
56        self
57    }
58
59    /// Add a dependency
60    #[must_use]
61    pub fn with_dependency(mut self, dep_id: impl Into<String>) -> Self {
62        self.depends_on.push(dep_id.into());
63        self
64    }
65
66    /// Add dependencies
67    #[must_use]
68    pub fn with_dependencies(mut self, deps: Vec<String>) -> Self {
69        self.depends_on.extend(deps);
70        self
71    }
72}
73
74#[cfg(test)]
75mod tests {
76    use super::*;
77
78    #[test]
79    fn test_decision_trace_new() {
80        let trace = DecisionTrace::new("d1", "type_inference", "Inferred type i32");
81        assert_eq!(trace.id, "d1");
82        assert_eq!(trace.decision_type, "type_inference");
83        assert_eq!(trace.description, "Inferred type i32");
84    }
85
86    #[test]
87    fn test_decision_trace_with_span() {
88        let trace =
89            DecisionTrace::new("d1", "type", "desc").with_span(SourceSpan::line("main.rs", 5));
90        assert!(trace.span.is_some());
91    }
92
93    #[test]
94    fn test_decision_trace_with_timestamp() {
95        let trace = DecisionTrace::new("d1", "type", "desc").with_timestamp(1000);
96        assert_eq!(trace.timestamp_ns, 1000);
97    }
98
99    #[test]
100    fn test_decision_trace_with_dependencies() {
101        let trace = DecisionTrace::new("d1", "type", "desc")
102            .with_dependency("d0")
103            .with_dependencies(vec!["d2".to_string(), "d3".to_string()]);
104        assert_eq!(trace.depends_on.len(), 3);
105    }
106}