Skip to main content

stylus_trace_core/diff/
engine.rs

1//! Core diff engine implementation.
2//! Generates complete diff reports by comparing two profiles.
3
4use crate::parser::schema::Profile;
5use chrono::Utc;
6
7use super::normalizer::{
8    are_profiles_identical, calculate_gas_delta, calculate_hostio_delta, check_compatibility,
9    compare_hot_paths,
10};
11use super::schema::{Deltas, DiffReport, DiffSummary, ProfileMetadata};
12use super::DiffError;
13
14/// Generate a complete diff report comparing two profiles
15///
16/// # Arguments
17/// * `baseline` - The baseline profile to compare against
18/// * `target` - The target profile to compare
19///
20/// # Returns
21/// Complete DiffReport with all deltas calculated
22///
23/// # Errors
24/// * `DiffError::IncompatibleVersions` - If schema versions don't match
25///
26/// # Example
27/// ```ignore
28/// use stylus_trace_core::diff::generate_diff;
29/// use stylus_trace_core::output::json::read_profile;
30///
31/// let baseline = read_profile("baseline.json")?;
32/// let target = read_profile("target.json")?;
33/// let diff = generate_diff(&baseline, &target)?;
34/// ```
35pub fn generate_diff(baseline: &Profile, target: &Profile) -> Result<DiffReport, DiffError> {
36    // Step 1: Check compatibility
37    check_compatibility(baseline, target)?;
38
39    // Step 2: Extract metadata
40    let baseline_meta = ProfileMetadata {
41        transaction_hash: baseline.transaction_hash.clone(),
42        total_gas: baseline.total_gas,
43        generated_at: baseline.generated_at.clone(),
44    };
45
46    let target_meta = ProfileMetadata {
47        transaction_hash: target.transaction_hash.clone(),
48        total_gas: target.total_gas,
49        generated_at: target.generated_at.clone(),
50    };
51
52    // Step 3: Calculate all deltas
53    let gas_delta = calculate_gas_delta(baseline.total_gas, target.total_gas);
54
55    let hostio_delta = calculate_hostio_delta(&baseline.hostio_summary, &target.hostio_summary);
56
57    let hot_paths_delta = compare_hot_paths(&baseline.hot_paths, &target.hot_paths);
58
59    let deltas = Deltas {
60        gas: gas_delta,
61        hostio: hostio_delta,
62        hot_paths: hot_paths_delta,
63    };
64
65    // Step 4: Create summary (no thresholds yet)
66    let mut summary = DiffSummary {
67        has_regressions: false,
68        violation_count: 0,
69        status: "PASSED".to_string(),
70        warning: None,
71    };
72
73    // Check if profiles are identical
74    if are_profiles_identical(baseline, target) {
75        summary.warning = Some("Baseline and target profiles are identical".to_string());
76    }
77
78    // Step 5: Heuristic Analysis (Option 4)
79    let insights = super::analyzer::analyze_profile(target);
80
81    // Step 6: Build the report
82    Ok(DiffReport {
83        diff_version: "1.0.0".to_string(),
84        generated_at: Utc::now().to_rfc3339(),
85        baseline: baseline_meta,
86        target: target_meta,
87        deltas,
88        threshold_violations: Vec::new(), // Will be populated by check_thresholds
89        insights,
90        summary,
91    })
92}