crates/gunnar-sendpack/src/error.rs
//! One error type for the whole conversation.
use std::fmt;
/// What went wrong.
#[derive(Debug, thiserror::Error)]
pub enum Error {
/// The peer put something on the wire this grammar cannot read.
#[error("{0}")]
Protocol(String),
/// The caller asked for something that cannot be put on the wire.
///
/// Separated from [`Error::Protocol`] because the two have different
/// audiences: a protocol error is the remote's fault and belongs in a
/// diagnostic, an invalid request is the caller's and belongs in a
/// compile-time-adjacent complaint.
#[error("{0}")]
Invalid(String),
/// The peer used a hash algorithm this repository does not.
///
/// A variant of its own rather than a [`Error::Protocol`] string, because
/// it is the one protocol error a caller routinely wants to *re-report* in
/// its own vocabulary — an `object-format` mismatch is what a server tells
/// a client in its status report, and digging two algorithm names back out
/// of a formatted message to do so is how a message becomes an API by
/// accident.
#[error("an object id is {theirs} but the repository is {ours}")]
ObjectFormat {
/// The repository's algorithm, as it appears in `object-format=`.
ours: &'static str,
/// The peer's.
theirs: &'static str,
},
/// The remote refused the conversation and said why, in an `ERR <msg>`
/// packet or on sideband 3.
///
/// Its own variant rather than an [`Error::Protocol`] string because it is
/// **not** a protocol error: the grammar was obeyed exactly. `ERR` is the
/// one line in the advertisement that is a sentence for a human rather than
/// a record for a parser, and reading it as a ref turns
/// `you are not allowed to push here` into
/// `bad object id "ERR" for ref "you are not allowed to push here"`.
///
/// The wording is git's — `connect.c` answers an `ERR` packet with
/// `die(_("remote error: %s"), arg)` — so an operator who has seen the
/// message from git does not have to learn a second phrase for it. Measured
/// against git 2.53.0: `fatal: remote error: you are not allowed to push
/// here`, exit 128.
#[error("remote error: {0}")]
Remote(String),
/// The socket, the pipe or the file underneath.
#[error("io: {0}")]
Io(#[from] std::io::Error),
}
impl Error {
/// A protocol error from anything printable.
pub fn protocol(message: impl fmt::Display) -> Self {
Error::Protocol(message.to_string())
}
/// An invalid-request error from anything printable.
pub fn invalid(message: impl fmt::Display) -> Self {
Error::Invalid(message.to_string())
}
}
/// The crate's result type.
pub type Result<T> = std::result::Result<T, Error>;