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::{
114        rewrites::tracker::ChangeKind,
115        tree::visit::{Change, Relation},
116    };
117
118    impl crate::rewrites::tracker::Change for crate::tree::visit::Change {
119        fn id(&self) -> &oid {
120            match self {
121                Change::Addition { oid, .. } | Change::Deletion { oid, .. } | Change::Modification { oid, .. } => oid,
122            }
123        }
124
125        fn relation(&self) -> Option<Relation> {
126            match self {
127                Change::Addition { relation, .. } | Change::Deletion { relation, .. } => *relation,
128                Change::Modification { .. } => None,
129            }
130        }
131
132        fn kind(&self) -> ChangeKind {
133            match self {
134                Change::Addition { .. } => ChangeKind::Addition,
135                Change::Deletion { .. } => ChangeKind::Deletion,
136                Change::Modification { .. } => ChangeKind::Modification,
137            }
138        }
139
140        fn entry_mode(&self) -> EntryMode {
141            match self {
142                Change::Addition { entry_mode, .. }
143                | Change::Deletion { entry_mode, .. }
144                | Change::Modification { entry_mode, .. } => *entry_mode,
145            }
146        }
147
148        fn id_and_entry_mode(&self) -> (&oid, EntryMode) {
149            match self {
150                Change::Addition { entry_mode, oid, .. }
151                | Change::Deletion { entry_mode, oid, .. }
152                | Change::Modification { entry_mode, oid, .. } => (oid, *entry_mode),
153            }
154        }
155    }
156}
157
158#[cfg(test)]
159mod tests {
160    use super::*;
161
162    #[test]
163    fn size_of_change() {
164        let actual = std::mem::size_of::<Change>();
165        assert!(
166            actual <= 48,
167            "{actual} <= 48: this type shouldn't grow without us knowing"
168        );
169    }
170}