use std::{borrow::Cow, convert::TryFrom, fmt, path::Path};
use bstr::{BStr, BString, ByteSlice};
use git_hash::{oid, ObjectId};
use crate::Kind;
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)]
pub struct FullName(pub(crate) BString);
impl TryFrom<&str> for FullName {
type Error = git_validate::refname::Error;
fn try_from(value: &str) -> Result<Self, Self::Error> {
Ok(FullName(git_validate::refname(value.as_bytes().as_bstr())?.into()))
}
}
impl TryFrom<String> for FullName {
type Error = git_validate::refname::Error;
fn try_from(value: String) -> Result<Self, Self::Error> {
git_validate::refname(value.as_bytes().as_bstr())?;
Ok(FullName(value.into()))
}
}
impl TryFrom<&BStr> for FullName {
type Error = git_validate::refname::Error;
fn try_from(value: &BStr) -> Result<Self, Self::Error> {
Ok(FullName(git_validate::refname(value)?.into()))
}
}
impl TryFrom<BString> for FullName {
type Error = git_validate::refname::Error;
fn try_from(value: BString) -> Result<Self, Self::Error> {
git_validate::refname(value.as_ref())?;
Ok(FullName(value))
}
}
impl<'a> From<crate::FullName<'a>> for FullName {
fn from(value: crate::FullName<'a>) -> Self {
FullName(value.as_bstr().into())
}
}
impl FullName {
pub fn to_partial(&self) -> crate::PartialName<'_> {
crate::PartialName(self.0.as_bstr())
}
pub fn borrow(&self) -> crate::FullName<'_> {
crate::FullName(self.0.as_bstr())
}
pub fn to_path(&self) -> Cow<'_, Path> {
self.0.to_path().expect("UTF-8 conversion always succeeds").into()
}
pub fn into_inner(self) -> BString {
self.0
}
pub fn as_bstr(&self) -> &BStr {
self.0.as_bstr()
}
}
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)]
pub enum Target {
Peeled(ObjectId),
Symbolic(FullName),
}
impl Target {
pub fn kind(&self) -> Kind {
match self {
Target::Symbolic(_) => Kind::Symbolic,
Target::Peeled(_) => Kind::Peeled,
}
}
pub fn is_null(&self) -> bool {
match self {
Target::Peeled(oid) => oid.is_null(),
Target::Symbolic(_) => false,
}
}
pub fn borrow(&self) -> crate::Target<'_> {
match self {
Target::Peeled(oid) => crate::Target::Peeled(oid),
Target::Symbolic(name) => crate::Target::Symbolic(name.0.as_bstr()),
}
}
pub fn as_id(&self) -> Option<&oid> {
match self {
Target::Symbolic(_) => None,
Target::Peeled(oid) => Some(oid),
}
}
pub fn as_name(&self) -> Option<&BStr> {
match self {
Target::Symbolic(name) => Some(name.as_bstr()),
Target::Peeled(_) => None,
}
}
pub fn must_exist() -> Self {
Target::Peeled(ObjectId::null_sha1())
}
}
impl<'a> From<crate::Target<'a>> for Target {
fn from(src: crate::Target<'a>) -> Self {
match src {
crate::Target::Peeled(oid) => Target::Peeled(oid.to_owned()),
crate::Target::Symbolic(name) => Target::Symbolic(FullName(name.to_owned())),
}
}
}
impl<'a> PartialEq<crate::Target<'a>> for Target {
fn eq(&self, other: &crate::Target<'a>) -> bool {
match (self, other) {
(Target::Peeled(lhs), crate::Target::Peeled(rhs)) => lhs == rhs,
(Target::Symbolic(lhs), crate::Target::Symbolic(rhs)) => lhs.as_bstr() == *rhs,
_ => false,
}
}
}
impl fmt::Display for Target {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Target::Peeled(oid) => oid.fmt(f),
Target::Symbolic(name) => write!(f, "ref: {}", name.as_bstr()),
}
}
}