1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
//! Tree differencing trait.
//!
//! # Architecture
//! This module provides the abstract contract for computing structural deltas
//! between two tree objects. It abstracts the diffing algorithm (e.g., Myers,
//! Histogram) away from the core engine, allowing consumers to plug in
//! optimized or specialized diffing strategies.
//!
//! # Design Rationale: Associated Types over Generics
//! The trait uses an associated type (`type TreeId`) rather than a generic
//! parameter (`<TreeId>`). This design choice is deliberate: it ties the
//! identifier type to the specific `TreeDiffer` implementation. A differ that
//! reads from an in-memory store might use array indices as IDs, while a
//! filesystem-based differ uses `Hash`. Associated types prevent the need to
//! annotate the trait with generics at every call site, simplifying the API
//! while preserving flexibility.
use crateVctrlError;
use crateTreeDelta;
/// Trait for computing differences between two trees.
///
/// # Why this exists
/// Comparing two trees to find file additions, deletions, modifications, and
/// renames is a fundamental operation in version control. By defining this as
/// a trait, the crate ensures that the core logic does not depend on a specific
/// algorithm or storage backend. The output is a strongly-typed [`TreeDelta`],
/// which aggregates [`FileDelta`](crate::FileDelta) entries, ensuring that
/// downstream consumers (like UI renderers or merge drivers) receive a
/// consistent, validated data structure.
///
/// # How it works
/// The implementor receives references to two tree identifiers (`old` and `new`).
/// It is responsible for resolving these IDs to actual tree data (if necessary),
/// comparing their entries recursively, and classifying the changes. The
/// resulting [`TreeDelta`] provides an iterator-like interface over these
/// atomic file changes.
///
/// # Design Rationale: Thread Safety
/// The trait requires `Send + Sync` on both `Self` and the associated `TreeId`.
/// This is critical for performance: diffing large repositories is highly
/// parallelizable. By enforcing thread safety, the engine can dispatch
/// multiple `diff_trees` calls across a thread pool (e.g., using `rayon`)
/// to compare different directory branches concurrently without data races.
///
/// # Examples
///
/// Implementing the trait for a mock store that always reports no changes:
///
/// ```
/// # use libvctrl_handler::traits::core::diff::TreeDiffer;
/// # use libvctrl_handler::{TreeDelta, Hash, VctrlError};
/// #
/// struct MockDiffer;
///
/// impl TreeDiffer for MockDiffer {
/// type TreeId = Hash;
///
/// fn diff_trees(&self, _old: &Self::TreeId, _new: &Self::TreeId) -> Result<TreeDelta, VctrlError> {
/// // In a real implementation, this would load trees and compare entries.
/// Ok(TreeDelta::new())
/// }
/// }
///
/// let differ = MockDiffer;
/// let old_hash = Hash::from_bytes(&[0_u8; 64])?;
/// let new_hash = Hash::from_bytes(&[1u8; 64])?;
///
/// let delta = differ.diff_trees(&old_hash, &new_hash)?;
/// assert!(delta.is_empty());
/// # Ok::<(), VctrlError>(())
/// ```