Skip to content
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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

cruessler
Copy link
Contributor

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

/// Follow a sequence of `path` components starting from this instance, and look them up one by one until the last component
/// is looked up and its tree entry is returned.
///
/// # Performance Notes
///
/// Searching tree entries is currently done in sequence, which allows to the search to be allocation free. It would be possible
/// to reuse a vector and use a binary search instead, which might be able to improve performance over all.
/// However, a benchmark should be created first to have some data and see which trade-off to choose here.
///
pub fn lookup_entry<I, P>(&self, path: I) -> Result<Option<Entry<'repo>>, find::existing::Error>
where
I: IntoIterator<Item = P>,
P: PartialEq<BStr>,
{
let mut buf = self.repo.empty_reusable_buffer();
buf.clear();
let mut path = path.into_iter().peekable();
buf.extend_from_slice(&self.data);
while let Some(component) = path.next() {
match TreeRefIter::from_bytes(&buf)
.filter_map(Result::ok)
.find(|entry| component.eq(entry.filename))
{
Some(entry) => {
if path.peek().is_none() {
return Ok(Some(Entry {
inner: entry.into(),
repo: self.repo,
}));
} else {
let next_id = entry.oid.to_owned();
let obj = self.repo.objects.find(&next_id, &mut buf)?;
if !obj.kind.is_tree() {
return Ok(None);
}
}
}
None => return Ok(None),
}
}
Ok(None)
}
and
/// Like [`Self::lookup_entry()`], but takes a `Path` directly via `relative_path`, a path relative to this tree.
///
/// # Note
///
/// If any path component contains illformed UTF-8 and thus can't be converted to bytes on platforms which can't do so natively,
/// the returned component will be empty which makes the lookup fail.
pub fn lookup_entry_by_path(
&self,
relative_path: impl AsRef<std::path::Path>,
) -> Result<Option<Entry<'repo>>, find::existing::Error> {
use crate::bstr::ByteSlice;
self.lookup_entry(relative_path.as_ref().components().map(|c: std::path::Component<'_>| {
gix_path::os_str_into_bstr(c.as_os_str())
.unwrap_or_else(|_| "".into())
.as_bytes()
}))
}
, respectively. I left the doc comments untouched as they seem adequate in their new context as well. The code was modified to work with the APIs available in gix-object. I needed to add gix-path as a dependency in order to have access to gix_path::os_str_into_bstr.

Copy link
Member

@Byron Byron left a 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.

@cruessler
Copy link
Contributor Author

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.)

@cruessler cruessler marked this pull request as draft November 18, 2024 12:45
@Byron
Copy link
Member

Byron commented Nov 18, 2024

No worries at all. I think this this crate also has just the trait you need: Find, so these subtrees can be loaded into a buffer which probably would have to be passed as parameter as well. And from there it should work very similarly as 'on the upper levels'.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants