use std::{fmt, io};
pub type Result<T> = std::result::Result<T, GitError>;
#[derive(Debug)]
pub enum GitError {
Io(io::Error),
NotRepository(String),
InvalidFormat(String),
NotFound(String),
Unsupported(String),
LimitExceeded {
resource: &'static str,
limit: usize,
},
}
impl fmt::Display for GitError {
fn fmt(&self, output: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Io(error) => write!(output, "I/O error: {error}"),
Self::NotRepository(message) => write!(output, "not a Git repository: {message}"),
Self::InvalidFormat(message) => write!(output, "invalid Git data: {message}"),
Self::NotFound(message) => write!(output, "Git object not found: {message}"),
Self::Unsupported(message) => write!(output, "unsupported Git feature: {message}"),
Self::LimitExceeded { resource, limit } => {
write!(output, "{resource} exceeds configured limit {limit}")
}
}
}
}
impl std::error::Error for GitError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Io(error) => Some(error),
_ => None,
}
}
}
impl From<io::Error> for GitError {
fn from(error: io::Error) -> Self {
Self::Io(error)
}
}
pub(crate) fn invalid(message: impl Into<String>) -> GitError {
GitError::InvalidFormat(message.into())
}
#[cfg(test)]
mod tests {
use std::{error::Error, io};
use super::GitError;
#[test]
fn formats_every_error_variant() {
let errors = [
GitError::Io(io::Error::other("disk")),
GitError::NotRepository("path".to_owned()),
GitError::InvalidFormat("bytes".to_owned()),
GitError::NotFound("object".to_owned()),
GitError::Unsupported("feature".to_owned()),
GitError::LimitExceeded {
resource: "depth",
limit: 4,
},
];
for error in errors {
assert!(!error.to_string().is_empty());
}
assert!(GitError::Io(io::Error::other("disk")).source().is_some());
assert!(GitError::NotFound("x".to_owned()).source().is_none());
}
}