Skip to main content

suture_driver/
lib.rs

1//! SutureDriver trait and registry for format-specific drivers.
2//!
3//! Drivers translate between file formats and semantic patches,
4//! enabling Suture to understand *what changed* rather than just
5//! *which bytes changed*.
6
7pub mod error;
8pub mod plugin;
9pub mod registry;
10pub mod types;
11
12pub use error::DriverError;
13pub use plugin::{BuiltinDriverPlugin, DriverPlugin, PluginError, PluginRegistry};
14pub use registry::DriverRegistry;
15pub use types::{DiffHunk, DiffHunkType, DiffSummary, VisualDiff};
16
17/// Format-specific driver for translating between file formats and Suture patches.
18///
19/// Implementations must be `Send + Sync` for concurrent use across threads.
20/// A driver understands the *semantics* of a file format — it knows that
21/// changing a key in a JSON object is a different operation than appending
22/// to an array.
23pub trait SutureDriver: Send + Sync {
24    /// Human-readable driver name (e.g., "JSON", "OpenTimelineIO", "CSV").
25    fn name(&self) -> &str;
26
27    /// File extensions this driver handles (e.g., `[".json", ".jsonl"]`).
28    fn supported_extensions(&self) -> &[&str];
29
30    /// Parse a file and produce a semantic diff between it and an optional base.
31    ///
32    /// If `base_content` is `None`, this is a new file — produce creation patches.
33    /// If `base_content` is `Some`, produce patches representing the differences.
34    ///
35    /// Each returned `SemanticChange` describes a meaningful semantic operation
36    /// (e.g., "key `users.2.email` changed from `old@example.com` to `new@example.com`").
37    fn diff(
38        &self,
39        base_content: Option<&str>,
40        new_content: &str,
41    ) -> Result<Vec<SemanticChange>, DriverError>;
42
43    /// Produce a human-readable diff string between two versions of a file.
44    ///
45    /// This is used by `suture diff` when a driver is available for the file type.
46    /// The output should be more meaningful than raw line diffs — showing
47    /// semantic operations like key changes, array insertions, etc.
48    fn format_diff(
49        &self,
50        base_content: Option<&str>,
51        new_content: &str,
52    ) -> Result<String, DriverError>;
53
54    /// Perform a semantic three-way merge.
55    ///
56    /// Given base, ours, and theirs content, produce a merged result.
57    /// Returns `None` if the merge cannot be resolved automatically (conflict).
58    /// Returns `Some(merged_content)` if the merge is clean.
59    fn merge(
60        &self,
61        _base: &str,
62        _ours: &str,
63        _theirs: &str,
64    ) -> Result<Option<String>, DriverError> {
65        Ok(None)
66    }
67}
68
69/// A single semantic change detected by a driver.
70#[derive(Debug, Clone, PartialEq)]
71pub enum SemanticChange {
72    /// A value was added at a path (e.g., new key in JSON object).
73    Added { path: String, value: String },
74    /// A value was removed at a path.
75    Removed { path: String, old_value: String },
76    /// A value was modified at a path.
77    Modified {
78        path: String,
79        old_value: String,
80        new_value: String,
81    },
82    /// A value was moved/renamed from one path to another.
83    Moved {
84        old_path: String,
85        new_path: String,
86        value: String,
87    },
88}