diff options
Diffstat (limited to 'vendor/gix/src/reference/iter.rs')
-rw-r--r-- | vendor/gix/src/reference/iter.rs | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/vendor/gix/src/reference/iter.rs b/vendor/gix/src/reference/iter.rs new file mode 100644 index 000000000..a2b022f64 --- /dev/null +++ b/vendor/gix/src/reference/iter.rs @@ -0,0 +1,127 @@ +//! +use std::path::Path; + +use gix_odb::pack::Find; +use gix_ref::file::ReferenceExt; + +/// A platform to create iterators over references. +#[must_use = "Iterators should be obtained from this iterator platform"] +pub struct Platform<'r> { + pub(crate) platform: gix_ref::file::iter::Platform<'r>, + pub(crate) repo: &'r crate::Repository, +} + +/// An iterator over references, with or without filter. +pub struct Iter<'r> { + inner: gix_ref::file::iter::LooseThenPacked<'r, 'r>, + peel: bool, + repo: &'r crate::Repository, +} + +impl<'r> Iter<'r> { + fn new(repo: &'r crate::Repository, platform: gix_ref::file::iter::LooseThenPacked<'r, 'r>) -> Self { + Iter { + inner: platform, + peel: false, + repo, + } + } +} + +impl<'r> Platform<'r> { + /// Return an iterator over all references in the repository. + /// + /// Even broken or otherwise unparsable or inaccessible references are returned and have to be handled by the caller on a + /// case by case basis. + pub fn all(&self) -> Result<Iter<'_>, init::Error> { + Ok(Iter::new(self.repo, self.platform.all()?)) + } + + /// Return an iterator over all references that match the given `prefix`. + /// + /// These are of the form `refs/heads` or `refs/remotes/origin`, and must not contain relative paths components like `.` or `..`. + // TODO: Create a custom `Path` type that enforces the requirements of git naturally, this type is surprising possibly on windows + // and when not using a trailing '/' to signal directories. + pub fn prefixed(&self, prefix: impl AsRef<Path>) -> Result<Iter<'_>, init::Error> { + Ok(Iter::new(self.repo, self.platform.prefixed(prefix)?)) + } + + // TODO: tests + /// Return an iterator over all references that are tags. + /// + /// They are all prefixed with `refs/tags`. + pub fn tags(&self) -> Result<Iter<'_>, init::Error> { + Ok(Iter::new(self.repo, self.platform.prefixed("refs/tags/")?)) + } + + // TODO: tests + /// Return an iterator over all local branches. + /// + /// They are all prefixed with `refs/heads`. + pub fn local_branches(&self) -> Result<Iter<'_>, init::Error> { + Ok(Iter::new(self.repo, self.platform.prefixed("refs/heads/")?)) + } + + // TODO: tests + /// Return an iterator over all remote branches. + /// + /// They are all prefixed with `refs/remotes`. + pub fn remote_branches(&self) -> Result<Iter<'_>, init::Error> { + Ok(Iter::new(self.repo, self.platform.prefixed("refs/remotes/")?)) + } +} + +impl<'r> Iter<'r> { + /// Automatically peel references before yielding them during iteration. + /// + /// This has the same effect as using `iter.map(|r| {r.peel_to_id_in_place(); r})`. + /// + /// # Note + /// + /// Doing this is necessary as the packed-refs buffer is already held by the iterator, disallowing the consumer of the iterator + /// to peel the returned references themselves. + pub fn peeled(mut self) -> Self { + self.peel = true; + self + } +} + +impl<'r> Iterator for Iter<'r> { + type Item = Result<crate::Reference<'r>, Box<dyn std::error::Error + Send + Sync + 'static>>; + + fn next(&mut self) -> Option<Self::Item> { + self.inner.next().map(|res| { + res.map_err(|err| Box::new(err) as Box<dyn std::error::Error + Send + Sync + 'static>) + .and_then(|mut r| { + if self.peel { + let handle = &self.repo; + r.peel_to_id_in_place(&handle.refs, |oid, buf| { + handle + .objects + .try_find(oid, buf) + .map(|po| po.map(|(o, _l)| (o.kind, o.data))) + }) + .map_err(|err| Box::new(err) as Box<dyn std::error::Error + Send + Sync + 'static>) + .map(|_| r) + } else { + Ok(r) + } + }) + .map(|r| crate::Reference::from_ref(r, self.repo)) + }) + } +} + +/// +pub mod init { + /// The error returned by [`Platform::all()`][super::Platform::all()] or [`Platform::prefixed()`][super::Platform::prefixed()]. + #[derive(Debug, thiserror::Error)] + #[allow(missing_docs)] + pub enum Error { + #[error(transparent)] + Io(#[from] std::io::Error), + } +} + +/// The error returned by [references()][crate::Repository::references()]. +pub type Error = gix_ref::packed::buffer::open::Error; |