gunnar_sendpack/error.rs
1//! One error type for the whole conversation.
2
3use std::fmt;
4
5/// What went wrong.
6#[derive(Debug, thiserror::Error)]
7pub enum Error {
8 /// The peer put something on the wire this grammar cannot read.
9 #[error("{0}")]
10 Protocol(String),
11 /// The caller asked for something that cannot be put on the wire.
12 ///
13 /// Separated from [`Error::Protocol`] because the two have different
14 /// audiences: a protocol error is the remote's fault and belongs in a
15 /// diagnostic, an invalid request is the caller's and belongs in a
16 /// compile-time-adjacent complaint.
17 #[error("{0}")]
18 Invalid(String),
19 /// The peer used a hash algorithm this repository does not.
20 ///
21 /// A variant of its own rather than a [`Error::Protocol`] string, because
22 /// it is the one protocol error a caller routinely wants to *re-report* in
23 /// its own vocabulary — an `object-format` mismatch is what a server tells
24 /// a client in its status report, and digging two algorithm names back out
25 /// of a formatted message to do so is how a message becomes an API by
26 /// accident.
27 #[error("an object id is {theirs} but the repository is {ours}")]
28 ObjectFormat {
29 /// The repository's algorithm, as it appears in `object-format=`.
30 ours: &'static str,
31 /// The peer's.
32 theirs: &'static str,
33 },
34 /// The remote refused the conversation and said why, in an `ERR <msg>`
35 /// packet or on sideband 3.
36 ///
37 /// Its own variant rather than an [`Error::Protocol`] string because it is
38 /// **not** a protocol error: the grammar was obeyed exactly. `ERR` is the
39 /// one line in the advertisement that is a sentence for a human rather than
40 /// a record for a parser, and reading it as a ref turns
41 /// `you are not allowed to push here` into
42 /// `bad object id "ERR" for ref "you are not allowed to push here"`.
43 ///
44 /// The wording is git's — `connect.c` answers an `ERR` packet with
45 /// `die(_("remote error: %s"), arg)` — so an operator who has seen the
46 /// message from git does not have to learn a second phrase for it. Measured
47 /// against git 2.53.0: `fatal: remote error: you are not allowed to push
48 /// here`, exit 128.
49 #[error("remote error: {0}")]
50 Remote(String),
51 /// The socket, the pipe or the file underneath.
52 #[error("io: {0}")]
53 Io(#[from] std::io::Error),
54}
55
56impl Error {
57 /// A protocol error from anything printable.
58 pub fn protocol(message: impl fmt::Display) -> Self {
59 Error::Protocol(message.to_string())
60 }
61
62 /// An invalid-request error from anything printable.
63 pub fn invalid(message: impl fmt::Display) -> Self {
64 Error::Invalid(message.to_string())
65 }
66}
67
68/// The crate's result type.
69pub type Result<T> = std::result::Result<T, Error>;