Coverage Report

Created: 2025-11-16 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}