gix_traverse/tree/
recorder.rs1use gix_hash::ObjectId;
2use gix_object::{
3 bstr::{BStr, BString, ByteSlice, ByteVec},
4 tree,
5};
6
7use crate::tree::{visit::Action, Recorder, Visit};
8
9#[derive(Debug, Clone, Copy, Eq, PartialEq)]
11pub enum Location {
12 Path,
14 FileName,
18}
19
20#[derive(Clone, Debug, PartialEq, Eq)]
23pub struct Entry {
24 pub mode: tree::EntryMode,
26 pub filepath: BString,
30 pub oid: ObjectId,
32}
33
34impl Entry {
35 fn new(entry: &tree::EntryRef<'_>, filepath: BString) -> Self {
36 Entry {
37 filepath,
38 oid: entry.oid.to_owned(),
39 mode: entry.mode,
40 }
41 }
42}
43
44impl Default for Recorder {
45 fn default() -> Self {
46 Recorder {
47 path_deque: Default::default(),
48 path: Default::default(),
49 location: Location::Path.into(),
50 records: vec![],
51 }
52 }
53}
54
55impl Recorder {
56 fn pop_element(&mut self) {
57 if let Some(pos) = self.path.rfind_byte(b'/') {
58 self.path.resize(pos, 0);
59 } else {
60 self.path.clear();
61 }
62 }
63
64 fn push_element(&mut self, name: &BStr) {
65 if name.is_empty() {
66 return;
67 }
68 if !self.path.is_empty() {
69 self.path.push(b'/');
70 }
71 self.path.push_str(name);
72 }
73}
74
75impl Recorder {
77 pub fn track_location(mut self, location: Option<Location>) -> Self {
79 self.location = location;
80 self
81 }
82}
83
84impl Recorder {
86 pub fn path_clone(&self) -> BString {
88 self.path.clone()
89 }
90
91 pub fn path(&self) -> &BStr {
93 self.path.as_ref()
94 }
95}
96
97impl Visit for Recorder {
98 fn pop_back_tracked_path_and_set_current(&mut self) {
99 if let Some(Location::Path) = self.location {
100 self.path = self.path_deque.pop_back().unwrap_or_default();
101 }
102 }
103
104 fn pop_front_tracked_path_and_set_current(&mut self) {
105 if let Some(Location::Path) = self.location {
106 self.path = self
107 .path_deque
108 .pop_front()
109 .expect("every call is matched with push_tracked_path_component");
110 }
111 }
112
113 fn push_back_tracked_path_component(&mut self, component: &BStr) {
114 if let Some(Location::Path) = self.location {
115 self.push_element(component);
116 self.path_deque.push_back(self.path.clone());
117 }
118 }
119
120 fn push_path_component(&mut self, component: &BStr) {
121 match self.location {
122 None => {}
123 Some(Location::Path) => {
124 self.push_element(component);
125 }
126 Some(Location::FileName) => {
127 self.path.clear();
128 self.path.extend_from_slice(component);
129 }
130 }
131 }
132
133 fn pop_path_component(&mut self) {
134 if let Some(Location::Path) = self.location {
135 self.pop_element();
136 }
137 }
138
139 fn visit_tree(&mut self, entry: &tree::EntryRef<'_>) -> Action {
140 self.records.push(Entry::new(entry, self.path_clone()));
141 Action::Continue
142 }
143
144 fn visit_nontree(&mut self, entry: &tree::EntryRef<'_>) -> Action {
145 self.records.push(Entry::new(entry, self.path_clone()));
146 Action::Continue
147 }
148}