use crate::{Repository, Result, bstr::BStr, revision::Spec};
use gix_error::{ClassificationMarker, Exn};
use gix_hash::ObjectId;
mod types;
pub use types::{ObjectKindHint, Options, RefsHint};
use crate::bstr::BString;
pub mod error;
pub use error::CandidateInfo;
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
MissingReference {
name: BString,
},
AmbiguousPrefix {
prefix: gix_hash::Prefix,
candidates: Vec<(gix_hash::Prefix, CandidateInfo)>,
},
AmbiguousRefAndObject {
prefix: gix_hash::Prefix,
reference: gix_ref::FullName,
candidates: Vec<(gix_hash::Prefix, CandidateInfo)>,
},
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let candidates = match self {
Self::MissingReference { name } => return write!(f, "Reference {name:?} could not be found"),
Self::AmbiguousPrefix { prefix, candidates } => {
write!(f, "Short id {prefix} is ambiguous. Candidates are:")?;
candidates
}
Self::AmbiguousRefAndObject {
prefix,
reference,
candidates,
} => {
write!(
f,
"The object-id prefix {prefix} matched both the reference {reference} and at least one object. Candidates are:"
)?;
candidates
}
};
for (object_id, info) in candidates {
write!(f, "\n\t{object_id} {info}")?;
}
Ok(())
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::MissingReference { .. } => Some(const { &ClassificationMarker::NOT_FOUND }),
Self::AmbiguousPrefix { .. } | Self::AmbiguousRefAndObject { .. } => {
Some(const { &ClassificationMarker::VALIDATION })
}
}
}
}
impl<'repo> Spec<'repo> {
pub fn from_bstr<'a>(spec: impl Into<&'a BStr>, repo: &'repo Repository, opts: Options) -> Result<Self> {
let mut delegate = Delegate::new(repo, opts);
match gix_revision::spec::parse(spec.into(), &mut delegate) {
Err(err) => {
if let Some(delegate_err) = delegate.into_delayed_errors() {
let mut err = err.into_exn();
let sources: Vec<_> = err.drain_children().collect();
Err(err.chain(delegate_err.chain_all(sources)).into_error())
} else {
Err(err)
}
}
Ok(()) => delegate.into_rev_spec(),
}
}
}
struct Delegate<'repo> {
refs: [Option<gix_ref::Reference>; 2],
objs: [Option<Vec<ObjectId>>; 2],
paths: [Option<(BString, gix_object::tree::EntryMode)>; 2],
ambiguous_objects: [Option<Vec<ObjectId>>; 2],
idx: usize,
kind: Option<gix_revision::spec::Kind>,
opts: Options,
delayed_errors: Vec<Exn>,
prefix: [Option<gix_hash::Prefix>; 2],
last_call_was_disambiguate_prefix: [bool; 2],
repo: &'repo Repository,
}
mod delegate;