| use crate::{ |
| ext::{ObjectIdExt, ReferenceExt}, |
| head::Kind, |
| Head, |
| }; |
| |
| mod error { |
| use crate::{object, reference}; |
| |
| /// The error returned by [`Head::peel_to_id_in_place()`](super::Head::try_peel_to_id_in_place()) |
| /// and [`Head::into_fully_peeled_id()`](super::Head::try_into_peeled_id()). |
| #[derive(Debug, thiserror::Error)] |
| #[allow(missing_docs)] |
| pub enum Error { |
| #[error(transparent)] |
| FindExistingObject(#[from] object::find::existing::Error), |
| #[error(transparent)] |
| PeelReference(#[from] reference::peel::Error), |
| } |
| } |
| |
| pub use error::Error; |
| |
| /// |
| #[allow(clippy::empty_docs)] |
| pub mod into_id { |
| use crate::object; |
| |
| /// The error returned by [`Head::into_peeled_id()`](super::Head::into_peeled_id()). |
| #[derive(Debug, thiserror::Error)] |
| #[allow(missing_docs)] |
| pub enum Error { |
| #[error(transparent)] |
| Peel(#[from] super::Error), |
| #[error("Branch '{name}' does not have any commits")] |
| Unborn { name: gix_ref::FullName }, |
| #[error(transparent)] |
| ObjectKind(#[from] object::try_into::Error), |
| } |
| } |
| |
| /// |
| #[allow(clippy::empty_docs)] |
| pub mod to_commit { |
| use crate::object; |
| |
| /// The error returned by [`Head::peel_to_commit_in_place()`](super::Head::peel_to_commit_in_place()). |
| #[derive(Debug, thiserror::Error)] |
| #[allow(missing_docs)] |
| pub enum Error { |
| #[error(transparent)] |
| PeelToObject(#[from] super::to_object::Error), |
| #[error(transparent)] |
| ObjectKind(#[from] object::try_into::Error), |
| } |
| } |
| |
| /// |
| #[allow(clippy::empty_docs)] |
| pub mod to_object { |
| /// The error returned by [`Head::peel_to_object_in_place()`](super::Head::peel_to_object_in_place()). |
| #[derive(Debug, thiserror::Error)] |
| #[allow(missing_docs)] |
| pub enum Error { |
| #[error(transparent)] |
| Peel(#[from] super::Error), |
| #[error("Branch '{name}' does not have any commits")] |
| Unborn { name: gix_ref::FullName }, |
| } |
| } |
| |
| impl<'repo> Head<'repo> { |
| /// Peel this instance and consume it to make obtaining its final target id possible, while returning an error on unborn heads. |
| /// |
| /// The final target is obtained by following symbolic references and peeling tags to their final destination, which |
| /// typically is a commit, but can be any object. |
| pub fn into_peeled_id(mut self) -> Result<crate::Id<'repo>, into_id::Error> { |
| self.try_peel_to_id_in_place()?; |
| self.id().ok_or_else(|| match self.kind { |
| Kind::Symbolic(gix_ref::Reference { name, .. }) | Kind::Unborn(name) => into_id::Error::Unborn { name }, |
| Kind::Detached { .. } => unreachable!("id can be returned after peeling"), |
| }) |
| } |
| |
| /// Peel this instance and consume it to make obtaining its final target object possible, while returning an error on unborn heads. |
| /// |
| /// The final target is obtained by following symbolic references and peeling tags to their final destination, which |
| /// typically is a commit, but can be any object as well. |
| pub fn into_peeled_object(mut self) -> Result<crate::Object<'repo>, to_object::Error> { |
| self.peel_to_object_in_place() |
| } |
| |
| /// Consume this instance and transform it into the final object that it points to, or `Ok(None)` if the `HEAD` |
| /// reference is yet to be born. |
| /// |
| /// The final target is obtained by following symbolic references and peeling tags to their final destination, which |
| /// typically is a commit, but can be any object. |
| pub fn try_into_peeled_id(mut self) -> Result<Option<crate::Id<'repo>>, Error> { |
| self.try_peel_to_id_in_place() |
| } |
| |
| /// Follow the symbolic reference of this head until its target object and peel it by following tag objects until there is no |
| /// more object to follow, and return that object id. |
| /// |
| /// Returns `Ok(None)` if the head is unborn. |
| /// |
| /// The final target is obtained by following symbolic references and peeling tags to their final destination, which |
| /// typically is a commit, but can be any object. |
| pub fn try_peel_to_id_in_place(&mut self) -> Result<Option<crate::Id<'repo>>, Error> { |
| Ok(Some(match &mut self.kind { |
| Kind::Unborn(_name) => return Ok(None), |
| Kind::Detached { |
| peeled: Some(peeled), .. |
| } => (*peeled).attach(self.repo), |
| Kind::Detached { peeled: None, target } => { |
| let id = target.attach(self.repo); |
| if id.header()?.kind() == gix_object::Kind::Commit { |
| id |
| } else { |
| match id.object()?.peel_tags_to_end() { |
| Ok(obj) => { |
| self.kind = Kind::Detached { |
| peeled: Some(obj.id), |
| target: *target, |
| }; |
| obj.id() |
| } |
| Err(err) => return Err(err.into()), |
| } |
| } |
| } |
| Kind::Symbolic(r) => { |
| let mut nr = r.clone().attach(self.repo); |
| let peeled = nr.peel_to_id_in_place(); |
| *r = nr.detach(); |
| peeled? |
| } |
| })) |
| } |
| |
| /// Follow the symbolic reference of this head until its target object and peel it by following tag objects until there is no |
| /// more object to follow, transform the id into a commit if possible and return that. |
| /// |
| /// Returns an error if the head is unborn or if it doesn't point to a commit. |
| pub fn peel_to_object_in_place(&mut self) -> Result<crate::Object<'repo>, to_object::Error> { |
| let id = self |
| .try_peel_to_id_in_place()? |
| .ok_or_else(|| to_object::Error::Unborn { |
| name: self.referent_name().expect("unborn").to_owned(), |
| })?; |
| id.object() |
| .map_err(|err| to_object::Error::Peel(Error::FindExistingObject(err))) |
| } |
| |
| /// Follow the symbolic reference of this head until its target object and peel it by following tag objects until there is no |
| /// more object to follow, transform the id into a commit if possible and return that. |
| /// |
| /// Returns an error if the head is unborn or if it doesn't point to a commit. |
| pub fn peel_to_commit_in_place(&mut self) -> Result<crate::Commit<'repo>, to_commit::Error> { |
| Ok(self.peel_to_object_in_place()?.try_into_commit()?) |
| } |
| } |