git_diff/tree/visit.rs
1use git_hash::ObjectId;
2use git_object::{bstr::BStr, tree};
3
4/// Represents any possible change in order to turn one tree into another.
5#[derive(Debug, Clone, PartialOrd, PartialEq, Ord, Eq, Hash)]
6pub enum Change {
7 /// An entry was added, like the addition of a file or directory.
8 Addition {
9 /// The mode of the added entry.
10 entry_mode: tree::EntryMode,
11 /// The object id of the added entry.
12 oid: ObjectId,
13 },
14 /// An entry was deleted, like the deletion of a file or directory.
15 Deletion {
16 /// The mode of the deleted entry.
17 entry_mode: tree::EntryMode,
18 /// The object id of the deleted entry.
19 oid: ObjectId,
20 },
21 /// An entry was modified, e.g. changing the contents of a file adjusts its object id and turning
22 /// a file into a symbolic link adjusts its mode.
23 Modification {
24 /// The mode of the entry before the modification.
25 previous_entry_mode: tree::EntryMode,
26 /// The object id of the entry before the modification.
27 previous_oid: ObjectId,
28
29 /// The mode of the entry after the modification.
30 entry_mode: tree::EntryMode,
31 /// The object id after the modification.
32 oid: ObjectId,
33 },
34}
35
36/// What to do after a [Change] was [recorded][Visit::visit()].
37#[derive(Clone, Copy, PartialOrd, PartialEq, Ord, Eq, Hash)]
38pub enum Action {
39 /// Continue the traversal of changes.
40 Continue,
41 /// Stop the traversal of changes, making this the last call to [visit(…)][Visit::visit()].
42 Cancel,
43}
44
45impl Default for Action {
46 fn default() -> Self {
47 Action::Continue
48 }
49}
50
51impl Action {
52 /// Returns true if this action means to stop the traversal.
53 pub fn cancelled(&self) -> bool {
54 matches!(self, Action::Cancel)
55 }
56}
57
58/// A trait to allow responding to a traversal designed to figure out the [changes][Change]
59/// to turn tree A into tree B.
60pub trait Visit {
61 /// Sets the full path path in front of the queue so future calls to push and pop components affect it instead.
62 fn pop_front_tracked_path_and_set_current(&mut self);
63 /// Append a `component` to the end of a path, which may be empty.
64 fn push_back_tracked_path_component(&mut self, component: &BStr);
65 /// Append a `component` to the end of a path, which may be empty.
66 fn push_path_component(&mut self, component: &BStr);
67 /// Removes the last component from the path, which may leave it empty.
68 fn pop_path_component(&mut self);
69 /// Record a `change` and return an instruction whether to continue or not.
70 ///
71 /// The implementation may use the current path to lean where in the tree the change is located.
72 fn visit(&mut self, change: Change) -> Action;
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78
79 #[test]
80 fn size_of_change() {
81 let actual = std::mem::size_of::<Change>();
82 assert!(
83 actual <= 46,
84 "{actual} <= 46: this type shouldn't grow without us knowing"
85 )
86 }
87}