| use gix_hash::ObjectId; |
| |
| use crate::{FullName, Target}; |
| |
| /// A fully owned backend agnostic reference |
| #[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct Reference { |
| /// The path to uniquely identify this ref within its store. |
| pub name: FullName, |
| /// The target of the reference, either a symbolic reference by full name or a possibly intermediate object by its id. |
| pub target: Target, |
| /// The fully peeled object to which this reference ultimately points to. Only guaranteed to be set after |
| /// [`Reference::peel_to_id_in_place()`](crate::file::ReferenceExt) was called or if this reference originated |
| /// from a packed ref. |
| pub peeled: Option<ObjectId>, |
| } |
| |
| mod convert { |
| use gix_hash::ObjectId; |
| |
| use crate::{ |
| raw::Reference, |
| store_impl::{file::loose, packed}, |
| Target, |
| }; |
| |
| impl From<Reference> for loose::Reference { |
| fn from(value: Reference) -> Self { |
| loose::Reference { |
| name: value.name, |
| target: value.target, |
| } |
| } |
| } |
| |
| impl From<loose::Reference> for Reference { |
| fn from(value: loose::Reference) -> Self { |
| Reference { |
| name: value.name, |
| target: value.target, |
| peeled: None, |
| } |
| } |
| } |
| |
| impl<'p> From<packed::Reference<'p>> for Reference { |
| fn from(value: packed::Reference<'p>) -> Self { |
| Reference { |
| name: value.name.into(), |
| target: Target::Peeled(value.target()), |
| peeled: value |
| .object |
| .map(|hex| ObjectId::from_hex(hex).expect("parser validation")), |
| } |
| } |
| } |
| } |
| |
| mod access { |
| use gix_object::bstr::ByteSlice; |
| |
| use crate::{raw::Reference, FullNameRef, Namespace, Target}; |
| |
| impl Reference { |
| /// Returns the kind of reference based on its target |
| pub fn kind(&self) -> crate::Kind { |
| self.target.kind() |
| } |
| |
| /// Return the full validated name of the reference, with the given namespace stripped if possible. |
| /// |
| /// If the reference name wasn't prefixed with `namespace`, `None` is returned instead. |
| pub fn name_without_namespace(&self, namespace: &Namespace) -> Option<&FullNameRef> { |
| self.name |
| .0 |
| .as_bstr() |
| .strip_prefix(namespace.0.as_bytes()) |
| .map(|stripped| FullNameRef::new_unchecked(stripped.as_bstr())) |
| } |
| |
| /// Strip the given namespace from our name as well as the name, but not the reference we point to. |
| pub fn strip_namespace(&mut self, namespace: &Namespace) -> &mut Self { |
| self.name.strip_namespace(namespace); |
| if let Target::Symbolic(name) = &mut self.target { |
| name.strip_namespace(namespace); |
| } |
| self |
| } |
| } |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use super::*; |
| |
| #[test] |
| fn size_of_reference() { |
| assert_eq!( |
| std::mem::size_of::<Reference>(), |
| 80, |
| "let's not let it change size undetected" |
| ); |
| } |
| } |