use crate::bstr::BStr; use crate::{ext::ReferenceExt, revision::Spec, Id, Reference}; /// pub mod parse; mod impls { use std::ops::{Deref, DerefMut}; use crate::revision::Spec; impl<'repo> Deref for Spec<'repo> { type Target = gix_revision::Spec; fn deref(&self) -> &Self::Target { &self.inner } } impl<'repo> DerefMut for Spec<'repo> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner } } impl<'repo> PartialEq for Spec<'repo> { fn eq(&self, other: &Self) -> bool { self.inner == other.inner } } impl<'repo> Eq for Spec<'repo> {} } /// Initialization impl<'repo> Spec<'repo> { /// Create a single specification which points to `id`. pub fn from_id(id: Id<'repo>) -> Self { Spec { inner: gix_revision::Spec::Include(id.inner), path: None, repo: id.repo, first_ref: None, second_ref: None, } } } /// Access impl<'repo> Spec<'repo> { /// Detach the `Repository` from this instance, leaving only plain data that can be moved freely and serialized. pub fn detach(self) -> gix_revision::Spec { self.inner } /// Some revision specifications leave information about references which are returned as `(from-ref, to-ref)` here, e.g. /// `HEAD@{-1}..main` might be `(Some(refs/heads/previous-branch), Some(refs/heads/main))`, /// or `@` returns `(Some(refs/heads/main), None)`. pub fn into_references(self) -> (Option>, Option>) { let repo = self.repo; ( self.first_ref.map(|r| r.attach(repo)), self.second_ref.map(|r| r.attach(repo)), ) } /// Return the path encountered in specs like `@:` or `:`, along with the kind of object it represents. /// /// Note that there can only be one as paths always terminates further revspec parsing. pub fn path_and_mode(&self) -> Option<(&BStr, gix_object::tree::EntryMode)> { self.path.as_ref().map(|(p, mode)| (p.as_ref(), *mode)) } /// Return the name of the first reference we encountered while resolving the rev-spec, or `None` if a short hash /// was used. For example, `@` might yield `Some(HEAD)`, but `abcd` yields `None`. pub fn first_reference(&self) -> Option<&gix_ref::Reference> { self.first_ref.as_ref() } /// Return the name of the second reference we encountered while resolving the rev-spec, or `None` if a short hash /// was used or there was no second reference. For example, `..@` might yield `Some(HEAD)`, but `..abcd` or `@` /// yields `None`. pub fn second_reference(&self) -> Option<&gix_ref::Reference> { self.second_ref.as_ref() } /// Return the single included object represented by this instance, or `None` if it is a range of any kind. pub fn single(&self) -> Option> { match self.inner { gix_revision::Spec::Include(id) | gix_revision::Spec::ExcludeParents(id) => { Id::from_id(id, self.repo).into() } gix_revision::Spec::Exclude(_) | gix_revision::Spec::Range { .. } | gix_revision::Spec::Merge { .. } | gix_revision::Spec::IncludeOnlyParents { .. } => None, } } }