Skip to content

Commit 5be96b3

Browse files
committed
allow user callbacks to have any error (#470)
1 parent e51f3cd commit 5be96b3

File tree

1 file changed

+35
-8
lines changed
  • git-repository/src/object/tree

1 file changed

+35
-8
lines changed

git-repository/src/object/tree/mod.rs

+35-8
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,16 @@ pub mod diff {
7171
use git_object::TreeRefIter;
7272
use git_odb::FindExt;
7373

74+
/// The error return by methods on the [diff platform][super::Platform].
75+
#[derive(Debug, thiserror::Error)]
76+
#[allow(missing_docs)]
77+
pub enum Error {
78+
#[error(transparent)]
79+
Diff(#[from] git_diff::tree::changes::Error),
80+
#[error("The user-provided callback failed")]
81+
ForEach(#[source] Box<dyn std::error::Error + Send + Sync + 'static>),
82+
}
83+
7484
/// Represents any possible change in order to turn one tree into another.
7585
#[derive(Debug, Clone, Copy)]
7686
pub enum Event<'repo, 'other_repo> {
@@ -121,35 +131,46 @@ pub mod diff {
121131

122132
/// Add the item to compare to.
123133
impl<'a, 'repo> Platform<'a, 'repo> {
124-
pub fn to_obtain_tree<'other_repo>(
134+
/// Call `for_each` repeatedly with all changes that are needed to convert the source of the diff to the tree to `other`.
135+
pub fn for_each_to_obtain_tree<'other_repo, E>(
125136
&mut self,
126137
other: &Tree<'other_repo>,
127-
for_each: impl FnMut(Event<'repo, 'other_repo>) -> git_diff::tree::visit::Action,
128-
) -> Result<(), git_diff::tree::changes::Error> {
138+
for_each: impl FnMut(Event<'repo, 'other_repo>) -> Result<git_diff::tree::visit::Action, E>,
139+
) -> Result<(), Error>
140+
where
141+
E: std::error::Error + Sync + Send + 'static,
142+
{
129143
let repo = self.lhs.repo;
130144
let mut delegate = Delegate {
131145
repo: self.lhs.repo,
132146
other_repo: other.repo,
133147
visit: for_each,
148+
err: None,
134149
};
135150
git_diff::tree::Changes::from(TreeRefIter::from_bytes(&self.lhs.data)).needed_to_obtain(
136151
TreeRefIter::from_bytes(&other.data),
137152
&mut self.state,
138153
|oid, buf| repo.objects.find_tree_iter(oid, buf),
139154
&mut delegate,
140-
)
155+
)?;
156+
match delegate.err {
157+
Some(err) => Err(Error::ForEach(Box::new(err))),
158+
None => Ok(()),
159+
}
141160
}
142161
}
143162

144-
struct Delegate<'repo, 'other_repo, VisitFn> {
163+
struct Delegate<'repo, 'other_repo, VisitFn, E> {
145164
repo: &'repo Repository,
146165
other_repo: &'other_repo Repository,
147166
visit: VisitFn,
167+
err: Option<E>,
148168
}
149169

150-
impl<'repo, 'other_repo, VisitFn> git_diff::tree::Visit for Delegate<'repo, 'other_repo, VisitFn>
170+
impl<'repo, 'other_repo, VisitFn, E> git_diff::tree::Visit for Delegate<'repo, 'other_repo, VisitFn, E>
151171
where
152-
VisitFn: FnMut(Event<'repo, 'other_repo>) -> git_diff::tree::visit::Action,
172+
VisitFn: FnMut(Event<'repo, 'other_repo>) -> Result<git_diff::tree::visit::Action, E>,
173+
E: std::error::Error + Sync + Send + 'static,
153174
{
154175
fn pop_front_tracked_path_and_set_current(&mut self) {}
155176

@@ -184,7 +205,13 @@ pub mod diff {
184205
id: oid.attach(self.other_repo),
185206
},
186207
};
187-
(self.visit)(event)
208+
match (self.visit)(event) {
209+
Ok(action) => action,
210+
Err(err) => {
211+
self.err = Some(err);
212+
git_diff::tree::visit::Action::Cancel
213+
}
214+
}
188215
}
189216
}
190217
}

0 commit comments

Comments
 (0)