gix_diff/tree/
visit.rs

1use gix_hash::ObjectId;
2use gix_object::{tree, tree::EntryMode};
3
4/// A way to recognize and associate different [`Change`] instances.
5///
6/// These are unique only within one diff operation.
7pub type ChangeId = u32;
8
9/// Identifies a relationship between this instance and another one.
10#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Ord, Eq, Hash)]
11pub enum Relation {
12    /// This is a parent with the given ID, which will always have at least one child
13    /// assuming that empty directories are not allowed in valid trees.
14    /// It's also always a tree which is the start of a recursive deletion or addition.
15    ///
16    /// The change with this relation is always emitted first.
17    Parent(ChangeId),
18    /// This is a direct or indirect child, tree or not tree, of the parent with the given ID.
19    ChildOfParent(ChangeId),
20}
21
22/// Represents any possible change in order to turn one tree into another.
23#[derive(Debug, Clone, PartialOrd, PartialEq, Ord, Eq, Hash)]
24pub enum Change {
25    /// An entry was added, like the addition of a file or directory.
26    Addition {
27        /// The mode of the added entry.
28        entry_mode: tree::EntryMode,
29        /// The object id of the added entry.
30        oid: ObjectId,
31        /// Possibly associate this change with another for hierarchical rename tracking.
32        relation: Option<Relation>,
33    },
34    /// An entry was deleted, like the deletion of a file or directory.
35    Deletion {
36        /// The mode of the deleted entry.
37        entry_mode: tree::EntryMode,
38        /// The object id of the deleted entry.
39        oid: ObjectId,
40        /// Possibly associate this change with another for hierarchical rename tracking.
41        relation: Option<Relation>,
42    },
43    /// An entry was modified, e.g. changing the contents of a file adjusts its object id and turning
44    /// a file into a symbolic link adjusts its mode.
45    Modification {
46        /// The mode of the entry before the modification.
47        previous_entry_mode: tree::EntryMode,
48        /// The object id of the entry before the modification.
49        previous_oid: ObjectId,
50
51        /// The mode of the entry after the modification.
52        entry_mode: tree::EntryMode,
53        /// The object id after the modification.
54        oid: ObjectId,
55    },
56}
57
58impl Change {
59    /// Return the current object id.
60    pub fn oid(&self) -> &gix_hash::oid {
61        match self {
62            Change::Addition { oid, .. } | Change::Deletion { oid, .. } | Change::Modification { oid, .. } => oid,
63        }
64    }
65    /// Return the current tree entry mode.
66    pub fn entry_mode(&self) -> EntryMode {
67        match self {
68            Change::Addition { entry_mode, .. }
69            | Change::Deletion { entry_mode, .. }
70            | Change::Modification { entry_mode, .. } => *entry_mode,
71        }
72    }
73    /// Return the current object id and tree entry mode of a change.
74    pub fn oid_and_entry_mode(&self) -> (&gix_hash::oid, EntryMode) {
75        match self {
76            Change::Addition {
77                oid,
78                entry_mode,
79                relation: _,
80            }
81            | Change::Deletion {
82                oid,
83                entry_mode,
84                relation: _,
85            }
86            | Change::Modification { oid, entry_mode, .. } => (oid, *entry_mode),
87        }
88    }
89}
90
91/// What to do after a [Change] was [recorded](super::Visit::visit()).
92#[derive(Default, Clone, Copy, PartialOrd, PartialEq, Ord, Eq, Hash)]
93pub enum Action {
94    /// Continue the traversal of changes.
95    #[default]
96    Continue,
97    /// Stop the traversal of changes, making this the last call to [visit(…)](super::Visit::visit()).
98    Cancel,
99}
100
101impl Action {
102    /// Returns true if this action means to stop the traversal.
103    pub fn cancelled(&self) -> bool {
104        matches!(self, Action::Cancel)
105    }
106}
107
108#[cfg(feature = "blob")]
109mod change_impls {
110    use gix_hash::oid;
111    use gix_object::tree::EntryMode;
112
113    use crate::tree::visit::Relation;
114    use crate::{rewrites::tracker::ChangeKind, tree::visit::Change};
115
116    impl crate::rewrites::tracker::Change for crate::tree::visit::Change {
117        fn id(&self) -> &oid {
118            match self {
119                Change::Addition { oid, .. } | Change::Deletion { oid, .. } | Change::Modification { oid, .. } => oid,
120            }
121        }
122
123        fn relation(&self) -> Option<Relation> {
124            match self {
125                Change::Addition { relation, .. } | Change::Deletion { relation, .. } => *relation,
126                Change::Modification { .. } => None,
127            }
128        }
129
130        fn kind(&self) -> ChangeKind {
131            match self {
132                Change::Addition { .. } => ChangeKind::Addition,
133                Change::Deletion { .. } => ChangeKind::Deletion,
134                Change::Modification { .. } => ChangeKind::Modification,
135            }
136        }
137
138        fn entry_mode(&self) -> EntryMode {
139            match self {
140                Change::Addition { entry_mode, .. }
141                | Change::Deletion { entry_mode, .. }
142                | Change::Modification { entry_mode, .. } => *entry_mode,
143            }
144        }
145
146        fn id_and_entry_mode(&self) -> (&oid, EntryMode) {
147            match self {
148                Change::Addition { entry_mode, oid, .. }
149                | Change::Deletion { entry_mode, oid, .. }
150                | Change::Modification { entry_mode, oid, .. } => (oid, *entry_mode),
151            }
152        }
153    }
154}
155
156#[cfg(test)]
157mod tests {
158    use super::*;
159
160    #[test]
161    fn size_of_change() {
162        let actual = std::mem::size_of::<Change>();
163        assert!(
164            actual <= 48,
165            "{actual} <= 48: this type shouldn't grow without us knowing"
166        );
167    }
168}