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}