Skip to main content

gix_diff/tree/
mod.rs

1use std::collections::VecDeque;
2
3use bstr::BStr;
4use gix_hash::ObjectId;
5use gix_object::bstr::BString;
6
7use crate::tree::visit::Relation;
8
9/// The error returned by [`tree()`](super::tree()).
10#[derive(Debug)]
11#[expect(missing_docs)]
12pub enum Error {
13    Cancelled,
14    Failure(gix_error::Error),
15}
16
17impl std::fmt::Display for Error {
18    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19        match self {
20            Error::Cancelled => f.write_str("The delegate cancelled the operation"),
21            Error::Failure(err) => std::fmt::Display::fmt(err, f),
22        }
23    }
24}
25
26impl std::error::Error for Error {
27    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
28        match self {
29            Error::Cancelled => Some(const { &gix_error::ClassificationMarker::CANCELLED }),
30            Error::Failure(err) => Some(err),
31        }
32    }
33}
34
35impl<E> From<gix_error::Exn<E>> for Error
36where
37    E: std::error::Error + Send + Sync + 'static,
38{
39    fn from(err: gix_error::Exn<E>) -> Self {
40        Error::Failure(err.into_error())
41    }
42}
43
44impl From<gix_error::Error> for Error {
45    fn from(err: gix_error::Error) -> Self {
46        Error::Failure(err)
47    }
48}
49
50impl From<gix_error::Message> for Error {
51    fn from(err: gix_error::Message) -> Self {
52        Error::Failure(gix_error::Error::from_error(err))
53    }
54}
55
56/// A trait to allow responding to a traversal designed to figure out the [changes](visit::Change)
57/// to turn tree A into tree B.
58pub trait Visit {
59    /// Sets the full path in front of the queue so future calls to push and pop components affect it instead.
60    fn pop_front_tracked_path_and_set_current(&mut self);
61    /// Append a `component` to the end of a path, which may be empty.
62    fn push_back_tracked_path_component(&mut self, component: &BStr);
63    /// Append a `component` to the end of a path, which may be empty.
64    fn push_path_component(&mut self, component: &BStr);
65    /// Removes the last component from the path, which may leave it empty.
66    fn pop_path_component(&mut self);
67    /// Record a `change` and return an instruction whether to continue or not.
68    ///
69    /// The implementation may use the current path to lean where in the tree the change is located.
70    fn visit(&mut self, change: visit::Change) -> visit::Action;
71}
72
73/// The state required to run [tree-diffs](super::tree()).
74#[derive(Default, Clone)]
75pub struct State {
76    /// A buffer for object data.
77    pub buf1: Vec<u8>,
78    /// Another buffer for object data.
79    pub buf2: Vec<u8>,
80    trees: VecDeque<TreeInfoTuple>,
81    change_id: visit::ChangeId,
82}
83
84type TreeInfoTuple = (Option<ObjectId>, Option<ObjectId>, Option<Relation>);
85
86impl State {
87    fn clear(&mut self) {
88        self.trees.clear();
89        self.buf1.clear();
90        self.buf2.clear();
91        self.change_id = 0;
92    }
93}
94
95pub(super) mod function;
96
97///
98pub mod visit;
99
100/// A [Visit] implementation to record every observed change and keep track of the changed paths.
101#[derive(Clone, Debug)]
102pub struct Recorder {
103    path_deque: VecDeque<BString>,
104    path: BString,
105    location: Option<recorder::Location>,
106    /// The observed changes.
107    pub records: Vec<recorder::Change>,
108}
109
110/// Useful for use as delegate implementing [`Visit`] to keep track of all seen changes. Useful for debugging or printing primarily.
111pub mod recorder;