/src/gitoxide/gix-diff/src/tree/visit.rs
Line | Count | Source |
1 | | use gix_hash::ObjectId; |
2 | | use 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. |
7 | | pub type ChangeId = u32; |
8 | | |
9 | | /// Identifies a relationship between this instance and another one. |
10 | | #[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Ord, Eq, Hash)] |
11 | | pub 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)] |
24 | | pub 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 | | |
58 | | impl Change { |
59 | | /// Return the current object id. |
60 | 0 | pub fn oid(&self) -> &gix_hash::oid { |
61 | 0 | match self { |
62 | 0 | Change::Addition { oid, .. } | Change::Deletion { oid, .. } | Change::Modification { oid, .. } => oid, |
63 | | } |
64 | 0 | } |
65 | | /// Return the current tree entry mode. |
66 | 0 | pub fn entry_mode(&self) -> EntryMode { |
67 | 0 | match self { |
68 | 0 | Change::Addition { entry_mode, .. } |
69 | 0 | | Change::Deletion { entry_mode, .. } |
70 | 0 | | Change::Modification { entry_mode, .. } => *entry_mode, |
71 | | } |
72 | 0 | } |
73 | | /// Return the current object id and tree entry mode of a change. |
74 | 0 | pub fn oid_and_entry_mode(&self) -> (&gix_hash::oid, EntryMode) { |
75 | 0 | match self { |
76 | | Change::Addition { |
77 | 0 | oid, |
78 | 0 | entry_mode, |
79 | | relation: _, |
80 | | } |
81 | | | Change::Deletion { |
82 | 0 | oid, |
83 | 0 | entry_mode, |
84 | | relation: _, |
85 | | } |
86 | 0 | | Change::Modification { oid, entry_mode, .. } => (oid, *entry_mode), |
87 | | } |
88 | 0 | } |
89 | | } |
90 | | |
91 | | /// What to do after a [Change] was [recorded](super::Visit::visit()). |
92 | | #[derive(Default, Clone, Copy, PartialOrd, PartialEq, Ord, Eq, Hash)] |
93 | | pub 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 | | |
101 | | impl Action { |
102 | | /// Returns true if this action means to stop the traversal. |
103 | 0 | pub fn cancelled(&self) -> bool { |
104 | 0 | matches!(self, Action::Cancel) |
105 | 0 | } |
106 | | } |
107 | | |
108 | | #[cfg(feature = "blob")] |
109 | | mod 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 | 0 | fn id(&self) -> &oid { |
120 | 0 | match self { |
121 | 0 | Change::Addition { oid, .. } | Change::Deletion { oid, .. } | Change::Modification { oid, .. } => oid, |
122 | | } |
123 | 0 | } |
124 | | |
125 | 0 | fn relation(&self) -> Option<Relation> { |
126 | 0 | match self { |
127 | 0 | Change::Addition { relation, .. } | Change::Deletion { relation, .. } => *relation, |
128 | 0 | Change::Modification { .. } => None, |
129 | | } |
130 | 0 | } |
131 | | |
132 | 0 | fn kind(&self) -> ChangeKind { |
133 | 0 | match self { |
134 | 0 | Change::Addition { .. } => ChangeKind::Addition, |
135 | 0 | Change::Deletion { .. } => ChangeKind::Deletion, |
136 | 0 | Change::Modification { .. } => ChangeKind::Modification, |
137 | | } |
138 | 0 | } |
139 | | |
140 | 0 | fn entry_mode(&self) -> EntryMode { |
141 | 0 | match self { |
142 | 0 | Change::Addition { entry_mode, .. } |
143 | 0 | | Change::Deletion { entry_mode, .. } |
144 | 0 | | Change::Modification { entry_mode, .. } => *entry_mode, |
145 | | } |
146 | 0 | } |
147 | | |
148 | 0 | fn id_and_entry_mode(&self) -> (&oid, EntryMode) { |
149 | 0 | match self { |
150 | 0 | Change::Addition { entry_mode, oid, .. } |
151 | 0 | | Change::Deletion { entry_mode, oid, .. } |
152 | 0 | | Change::Modification { entry_mode, oid, .. } => (oid, *entry_mode), |
153 | | } |
154 | 0 | } |
155 | | } |
156 | | } |
157 | | |
158 | | #[cfg(test)] |
159 | | mod 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 | | } |