-
-
Notifications
You must be signed in to change notification settings - Fork 315
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add lookup_entry and lookup_entry_by_path to TreeRef #1686
Add lookup_entry and lookup_entry_by_path to TreeRef #1686
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for making more convenient tree access available on 'the lower levels'.
Something that is sorely missing is tests. With that I think it would quickly become clear that this isn't actually working as the implementation doesn't attempt to load its subtrees.
Thanks for having a first look! (Sorry if this first attempt is incomplete. I only have limited context yet on how this works, so any feedback is greatly appreciated. I hope that this does not take away too much of your time. I’m a big fan of getting feedback very early as I’m certain one or two hints from your side will help me a lot initially. I’ll mark this PR as draft for the time being.) |
No worries at all. I think this this crate also has just the trait you need: |
I hope I now have a better understanding of how lookup by path works. Just to confirm: is it correct to recursively load trees and run The code as I just pushed it, does not compile as the buffer that is passed into |
In abstract terms, yes, but it should really be implemented like in
Rust helps :). Like mentioned before, it should be possible to translate the |
I just pushed a non-recursive implementation that passes the 2 tests that I had added before, so it seems to be working. :-) I’m not really happy that it has |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks much more like it, thank you!
The following patch would fix the problem of clone()
…
diff --git a/gix-object/src/tree/ref_iter.rs b/gix-object/src/tree/ref_iter.rs
index fda6f7275..76f063a9f 100644
--- a/gix-object/src/tree/ref_iter.rs
+++ b/gix-object/src/tree/ref_iter.rs
@@ -1,4 +1,5 @@
use bstr::BStr;
+use std::borrow::Cow;
use winnow::{error::ParserError, prelude::*};
use crate::{tree, tree::EntryRef, TreeRef, TreeRefIter};
@@ -65,7 +66,7 @@ impl<'a> TreeRef<'a> {
P: PartialEq<BStr>,
{
let mut path = path.into_iter().peekable();
- let mut entries = self.entries.clone();
+ let mut entries = Cow::Borrowed(&self.entries);
while let Some(component) = path.next() {
match entries.iter().find(|entry| component.eq(entry.filename)) {
@@ -76,7 +77,7 @@ impl<'a> TreeRef<'a> {
let next_id = entry.oid.to_owned();
let obj = odb.find_tree(&next_id, buffer)?;
- entries = obj.entries;
+ entries = Cow::Owned(obj.entries);
}
}
None => return Ok(None),
…but it would still leave the problem of inefficiency as it allocates where it shouldn't.
TreeRefIter
should be used instead.
gix-object/src/tree/ref_iter.rs
Outdated
P: PartialEq<BStr>, | ||
{ | ||
let mut path = path.into_iter().peekable(); | ||
let mut entries = self.entries.clone(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The trick should be to stick to what's done in gix
and implement this on the TreeRefIter
, something I thought I saw in an earlier version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason I implemented the method on TreeRef
was that, in its current iteration, the gix-blame
PR uses odb.find_tree
which returns a TreeRef
. Since it seems I could switch to odb.find_tree_iter
in the gix-blame
PR instead, I’ll move lookup_entry
to TreeRefIter
as you suggested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great! This has the chance to be a small but measurable performance boost as well. I still remember comparing two versions of this - what it is now (in gix
), and one where it would allocate a Vec
and binary-search through it. And it turned out the allocation really kills performance.
gix-object/src/tree/ref_iter.rs
Outdated
/// | ||
pub fn lookup_entry<I, P>( | ||
&self, | ||
odb: impl crate::FindExt, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be crate::Find
, which always implements FindExt
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the hint! Changed.
gix-object/tests/object/tree/iter.rs
Outdated
.unwrap() | ||
.unwrap(); | ||
|
||
assert!(matches!(entry, Entry { .. })); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would deduplicate the tests and compare the whole entry, showing that one can get trees and files. I'd also show what happens if the requested entry doesn't exist.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense! Changed.
As far as I can see, I’m done with the changes in response to your comments. |
a163909
to
71e9282
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot!
If you think it's ready, I think it's ready as well :).
This does not compile as there is only one buffer for potentially many times `lookup_entry` is called. This is intended to check whether the general approach is correct.
Return `Entry` instead of `EntryRef`. `EntryRef` needs the underlying data to be kept by `TreeRef`, but `lookup_entry` only temporarily loads sub-trees, so there is no data to return a reference to.
Adapt functions to new context. This mostly means copying the implementation from `gix::types::Tree` and applying minor changes related to `buffer` being passed as an argument.
71e9282
to
d913bc7
Compare
d913bc7
to
d7f4991
Compare
Awesome! One additional thing that I had in mind that didn’t make it into the PR was adding a comment to |
I see. Probably it would be easiest to make these doc-adjustments in the |
This PR is related to a comment in my
gix blame
PR: #1453 (comment).I wrote the new code in the context of #1453 and then cherry-picked the result into this separate PR. I initially took both methods from
gitoxide/gix/src/object/tree/mod.rs
Lines 51 to 93 in 9ab86a2
gitoxide/gix/src/object/tree/mod.rs
Lines 138 to 154 in 9ab86a2
gix-object
. I needed to addgix-path
as a dependency in order to have access togix_path::os_str_into_bstr
.