git_diff/tree/
recorder.rs1use std::collections::VecDeque;
2
3use git_hash::ObjectId;
4use git_object::{
5 bstr::{BStr, BString, ByteSlice, ByteVec},
6 tree,
7};
8
9use crate::tree::visit;
10
11#[derive(Clone, Debug, PartialEq, Eq)]
14#[allow(missing_docs)]
15pub enum Change {
16 Addition {
17 entry_mode: tree::EntryMode,
18 oid: ObjectId,
19 path: BString,
20 },
21 Deletion {
22 entry_mode: tree::EntryMode,
23 oid: ObjectId,
24 path: BString,
25 },
26 Modification {
27 previous_entry_mode: tree::EntryMode,
28 previous_oid: ObjectId,
29
30 entry_mode: tree::EntryMode,
31 oid: ObjectId,
32
33 path: BString,
34 },
35}
36
37#[derive(Clone, Debug, Default)]
39pub struct Recorder {
40 path_deque: VecDeque<BString>,
41 path: BString,
42 pub records: Vec<Change>,
44}
45
46impl Recorder {
47 fn pop_element(&mut self) {
48 if let Some(pos) = self.path.rfind_byte(b'/') {
49 self.path.resize(pos, 0);
50 } else {
51 self.path.clear();
52 }
53 }
54
55 fn push_element(&mut self, name: &BStr) {
56 if !self.path.is_empty() {
57 self.path.push(b'/');
58 }
59 self.path.push_str(name);
60 }
61
62 fn path_clone(&self) -> BString {
63 self.path.clone()
64 }
65}
66
67impl visit::Visit for Recorder {
68 fn pop_front_tracked_path_and_set_current(&mut self) {
69 self.path = self.path_deque.pop_front().expect("every parent is set only once");
70 }
71
72 fn push_back_tracked_path_component(&mut self, component: &BStr) {
73 self.push_element(component);
74 self.path_deque.push_back(self.path.clone());
75 }
76
77 fn push_path_component(&mut self, component: &BStr) {
78 self.push_element(component);
79 }
80
81 fn pop_path_component(&mut self) {
82 self.pop_element();
83 }
84
85 fn visit(&mut self, change: visit::Change) -> visit::Action {
86 use visit::Change::*;
87 self.records.push(match change {
88 Deletion { entry_mode, oid } => Change::Deletion {
89 entry_mode,
90 oid,
91 path: self.path_clone(),
92 },
93 Addition { entry_mode, oid } => Change::Addition {
94 entry_mode,
95 oid,
96 path: self.path_clone(),
97 },
98 Modification {
99 previous_entry_mode,
100 previous_oid,
101 entry_mode,
102 oid,
103 } => Change::Modification {
104 previous_entry_mode,
105 previous_oid,
106 entry_mode,
107 oid,
108 path: self.path_clone(),
109 },
110 });
111 visit::Action::Continue
112 }
113}