use std::fmt;
use std::sync::Arc;
use crate::git_dir::GitDirPathOperation;
use crate::refs::RefnameUnavailable;
use super::{Expected, RawRef};
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
#[non_exhaustive]
pub enum RefStoreError {
#[error("cannot lock ref '{name}': lock held")]
LockHeld {
name: String,
},
#[error("ref '{name}' did not match expected state")]
ExpectedMismatch {
name: String,
expected: Expected,
actual: Option<RawRef>,
},
#[error("cannot lock ref: {}", reason.lock_message_suffix())]
NameUnavailable {
reason: RefnameUnavailable,
},
#[error("multiple updates for ref '{name}' not allowed")]
DuplicateUpdate {
name: String,
},
#[error("symbolic ref loop or chain too deep")]
SymrefLoop,
#[error("ref not found: {name}")]
NotFound {
name: String,
},
#[error("corrupt ref store: {0}")]
Corrupt(String),
#[error("{}", crate::git_dir::io_error::format_git_dir_io_message(.path, *operation, &Self::git_dir_io_source(*.os_error)))]
GitDirPathIo {
path: String,
operation: GitDirPathOperation,
os_error: i32,
},
#[error("refusing to update ref with bad name '{name}'")]
InvalidRefName {
name: String,
},
#[error("refusing to point ref '{name}' at the null object id")]
NullOid {
name: String,
},
#[error(transparent)]
InvalidReflog(#[from] crate::ident::SignatureError),
#[error(transparent)]
Backend(BackendError),
}
impl RefStoreError {
pub(crate) fn git_dir_path_io(
path: String,
operation: GitDirPathOperation,
source: std::io::Error,
) -> Self {
Self::GitDirPathIo {
path,
operation,
os_error: source.raw_os_error().unwrap_or(0),
}
}
pub(crate) fn git_dir_io_source(os_error: i32) -> std::io::Error {
if os_error == 0 {
std::io::Error::from(std::io::ErrorKind::Other)
} else {
std::io::Error::from_raw_os_error(os_error)
}
}
pub(crate) fn not_found(name: &str) -> Self {
Self::NotFound {
name: name.to_owned(),
}
}
pub fn backend(err: impl std::error::Error + Send + Sync + 'static) -> Self {
Self::Backend(BackendError::new(err))
}
}
#[derive(Clone)]
pub struct BackendError(Arc<dyn std::error::Error + Send + Sync + 'static>);
impl BackendError {
pub fn new(err: impl std::error::Error + Send + Sync + 'static) -> Self {
Self(Arc::new(err))
}
#[must_use]
pub fn get_ref(&self) -> &(dyn std::error::Error + Send + Sync + 'static) {
self.0.as_ref()
}
#[must_use]
pub fn downcast_ref<E: std::error::Error + 'static>(&self) -> Option<&E> {
self.0.downcast_ref::<E>()
}
}
impl fmt::Debug for BackendError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
impl fmt::Display for BackendError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
impl std::error::Error for BackendError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.0.source()
}
}
impl PartialEq for BackendError {
fn eq(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.0, &other.0)
}
}
impl Eq for BackendError {}
impl From<BackendError> for RefStoreError {
fn from(err: BackendError) -> Self {
Self::Backend(err)
}
}
impl From<RefnameUnavailable> for RefStoreError {
fn from(reason: RefnameUnavailable) -> Self {
Self::NameUnavailable { reason }
}
}