1use abscissa_core::error::{BoxError, Context};
4use std::{
5 error::Error as ErrorTrait,
6 fmt::{self, Display},
7 io,
8 ops::Deref,
9};
10use thiserror::Error;
11
12#[derive(Copy, Clone, Debug, Eq, Error, PartialEq)]
14pub enum ErrorKind {
15 #[error("config error")]
17 Config,
18
19 #[error("I/O error")]
21 Io,
22
23 #[error("parse error")]
25 Parse,
26
27 #[error("git repo error")]
29 Repo,
30
31 #[error("version error")]
33 Version,
34
35 #[error("other error")]
37 Other,
38}
39
40impl ErrorKind {
41 pub fn context(self, source: impl Into<BoxError>) -> Context<ErrorKind> {
43 Context::new(self, Some(source.into()))
44 }
45}
46
47#[derive(Debug)]
49pub struct Error(Box<Context<ErrorKind>>);
50
51impl Error {
52 pub fn kind(&self) -> ErrorKind {
54 *self.0.kind()
55 }
56}
57
58impl Deref for Error {
59 type Target = Context<ErrorKind>;
60
61 fn deref(&self) -> &Context<ErrorKind> {
62 &self.0
63 }
64}
65
66impl Display for Error {
67 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68 self.0.fmt(f)
69 }
70}
71
72impl From<Context<ErrorKind>> for Error {
73 fn from(context: Context<ErrorKind>) -> Self {
74 Error(Box::new(context))
75 }
76}
77
78impl From<io::Error> for Error {
79 fn from(other: io::Error) -> Self {
80 ErrorKind::Io.context(other).into()
81 }
82}
83
84impl From<rustsec::Error> for Error {
85 fn from(err: rustsec::Error) -> Self {
86 match err.kind() {
87 rustsec::ErrorKind::Io => ErrorKind::Io,
88 rustsec::ErrorKind::Parse => ErrorKind::Parse,
89 rustsec::ErrorKind::Repo => ErrorKind::Repo,
90 rustsec::ErrorKind::Version => ErrorKind::Version,
91 _ => ErrorKind::Other,
92 }
93 .context(err)
94 .into()
95 }
96}
97
98impl From<cargo_lock::Error> for Error {
99 fn from(err: cargo_lock::Error) -> Self {
100 match err {
101 cargo_lock::Error::Io(_) => ErrorKind::Io,
102 cargo_lock::Error::Parse(_) => ErrorKind::Parse,
103 cargo_lock::Error::Version(_) => ErrorKind::Version,
104 _ => ErrorKind::Other,
105 }
106 .context(err)
107 .into()
108 }
109}
110
111impl std::error::Error for Error {
112 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
113 self.0.source()
114 }
115}
116
117pub fn display_err_with_source<E: ErrorTrait>(error: &E) -> String {
123 display_error_chain::DisplayErrorChain::new(error).to_string()
124}