gix_traverse/tree/
depthfirst.rs1pub use super::breadthfirst::Error;
2
3#[derive(Default, Clone)]
5pub struct State {
6 freelist: Vec<Vec<u8>>,
7}
8
9impl State {
10 pub fn pop_buf(&mut self) -> Vec<u8> {
12 match self.freelist.pop() {
13 None => Vec::new(),
14 Some(mut buf) => {
15 buf.clear();
16 buf
17 }
18 }
19 }
20
21 pub fn push_buf(&mut self, buf: Vec<u8>) {
23 self.freelist.push(buf);
24 }
25}
26
27pub(super) mod function {
28 use super::{Error, State};
29 use crate::tree::visit::Action;
30 use crate::tree::Visit;
31 use gix_hash::ObjectId;
32 use gix_object::{FindExt, TreeRefIter};
33 use std::borrow::BorrowMut;
34
35 pub fn depthfirst<StateMut, Find, V>(
40 root: ObjectId,
41 mut state: StateMut,
42 objects: Find,
43 delegate: &mut V,
44 ) -> Result<(), Error>
45 where
46 Find: gix_object::Find,
47 StateMut: BorrowMut<State>,
48 V: Visit,
49 {
50 enum Machine {
51 GetTree(ObjectId),
52 Iterate {
53 tree_buf: Vec<u8>,
54 byte_offset_to_next_entry: usize,
55 },
56 }
57
58 let state = state.borrow_mut();
59 let mut stack = vec![Machine::GetTree(root)];
60 'outer: while let Some(item) = stack.pop() {
61 match item {
62 Machine::GetTree(id) => {
63 let mut buf = state.pop_buf();
64 objects.find_tree_iter(&id, &mut buf)?;
65 stack.push(Machine::Iterate {
66 tree_buf: buf,
67 byte_offset_to_next_entry: 0,
68 });
69 }
70 Machine::Iterate {
71 tree_buf: buf,
72 byte_offset_to_next_entry,
73 } => {
74 let mut iter = TreeRefIter::from_bytes(&buf[byte_offset_to_next_entry..]);
75 delegate.pop_back_tracked_path_and_set_current();
76 while let Some(entry) = iter.next() {
77 let entry = entry?;
78 if entry.mode.is_tree() {
79 delegate.push_path_component(entry.filename);
80 let res = delegate.visit_tree(&entry);
81 delegate.pop_path_component();
82 match res {
83 Action::Continue => {}
84 Action::Cancel => break 'outer,
85 Action::Skip => continue,
86 }
87
88 delegate.push_back_tracked_path_component("".into());
89 delegate.push_back_tracked_path_component(entry.filename);
90 let recurse_tree = Machine::GetTree(entry.oid.to_owned());
91 let continue_at_next_entry = Machine::Iterate {
92 byte_offset_to_next_entry: iter.offset_to_next_entry(&buf),
93 tree_buf: buf,
94 };
95 stack.push(continue_at_next_entry);
96 stack.push(recurse_tree);
97 continue 'outer;
98 } else {
99 delegate.push_path_component(entry.filename);
100 if let Action::Cancel = delegate.visit_nontree(&entry) {
101 break 'outer;
102 }
103 delegate.pop_path_component();
104 }
105 }
106 state.push_buf(buf);
107 }
108 }
109 }
110 Ok(())
111 }
112}