1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
use crate::visit::record; use git_hash::ObjectId; use git_object::{ bstr::{BStr, BString, ByteSlice, ByteVec}, tree, }; use std::collections::BTreeMap; use std::ops::Deref; use std::path::PathBuf; #[derive(Clone, Debug, PartialEq, Eq)] pub enum Change { Addition { entry_mode: tree::EntryMode, oid: ObjectId, path: PathBuf, }, Deletion { entry_mode: tree::EntryMode, oid: ObjectId, path: PathBuf, }, Modification { previous_entry_mode: tree::EntryMode, previous_oid: ObjectId, entry_mode: tree::EntryMode, oid: ObjectId, path: PathBuf, }, } pub type Changes = Vec<Change>; #[derive(Clone, Debug, Default)] pub struct Recorder { path_count: usize, path_map: BTreeMap<usize, BString>, path: BString, pub records: Vec<Change>, } impl Recorder { fn pop_element(&mut self) { if let Some(pos) = self.path.rfind_byte(b'/') { self.path.resize(pos, 0); } else { self.path.clear(); } } fn push_element(&mut self, name: &BStr) { if !self.path.is_empty() { self.path.push(b'/'); } self.path.push_str(name); } fn path_clone(&self) -> BString { self.path.clone() } fn path_buf(&self) -> PathBuf { self.path.deref().to_owned().into_path_buf_lossy() } } impl record::Record for Recorder { type PathId = usize; fn set_current_path(&mut self, path: Self::PathId) { self.path = self.path_map.remove(&path).expect("every parent is set only once"); } fn push_tracked_path_component(&mut self, component: &BStr) -> Self::PathId { self.push_element(component); self.path_map.insert(self.path_count, self.path_clone()); let res = self.path_count; self.path_count += 1; res } fn push_path_component(&mut self, component: &BStr) { self.push_element(component); } fn pop_path_component(&mut self) { self.pop_element(); } fn record(&mut self, change: record::Change) -> record::Action { use record::Change::*; self.records.push(match change { Deletion { entry_mode, oid } => Change::Deletion { entry_mode, oid, path: self.path_buf(), }, Addition { entry_mode, oid } => Change::Addition { entry_mode, oid, path: self.path_buf(), }, Modification { previous_entry_mode, previous_oid, entry_mode, oid, } => Change::Modification { previous_entry_mode, previous_oid, entry_mode, oid, path: self.path_buf(), }, _ => todo!("record other kinds of changes"), }); record::Action::Continue } }