1use std::panic::Location;
4
5pub use derive_more::Error;
6pub use infinite_errors_macros::err_context;
7
8#[macro_export]
27macro_rules! declare_error_type {
28 ($error_kind:ident) => {
29 #[derive(::std::fmt::Debug, ::infinite_errors::Error)]
31 pub struct Error {
32 kind: $error_kind,
33 cause: ::std::option::Option<::std::boxed::Box<Error>>,
34 location: &'static ::std::panic::Location<'static>,
35 }
36
37 impl Error {
38 pub fn new(
40 kind: $error_kind,
41 location: &'static ::std::panic::Location<'static>,
42 ) -> Self {
43 Self {
44 kind,
45 cause: ::std::option::Option::None,
46 location,
47 }
48 }
49
50 pub fn kind(&self) -> &$error_kind {
52 &self.kind
53 }
54
55 pub fn cause(&self) -> ::std::option::Option<&Self> {
57 self.cause.as_deref()
58 }
59
60 pub fn location(&self) -> &'static ::std::panic::Location<'static> {
62 self.location
63 }
64 }
65
66 impl ::infinite_errors::ErrorType for Error {
67 type ErrorKind = $error_kind;
68
69 fn new(
70 kind: Self::ErrorKind,
71 cause: ::std::option::Option<::std::boxed::Box<Self>>,
72 location: &'static ::std::panic::Location<'static>,
73 ) -> Self {
74 Self {
75 kind,
76 cause,
77 location,
78 }
79 }
80 }
81
82 impl ::std::fmt::Display for Error {
83 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
84 write!(f, "{}", self.kind)?;
85 if let Some(cause) = &self.cause {
86 write!(f, ": {cause}")?;
87 }
88
89 Ok(())
90 }
91 }
92
93 impl<T> ::std::convert::From<T> for Error
94 where
95 T: ::std::convert::Into<$error_kind>,
96 {
97 #[track_caller]
98 fn from(kind: T) -> Self {
99 Self::new(kind.into(), ::std::panic::Location::caller())
100 }
101 }
102
103 pub trait ErrorContext<T> {
105 #[track_caller]
107 fn err_context(self, kind: $error_kind) -> ::std::result::Result<T, Error>;
108
109 #[track_caller]
113 fn err_context_with(
114 self,
115 kind: impl FnOnce() -> $error_kind,
116 ) -> ::std::result::Result<T, Error>;
117 }
118
119 impl<T, OE> ErrorContext<T> for ::std::result::Result<T, OE>
120 where
121 OE: Into<Error>,
122 {
123 fn err_context(self, kind: $error_kind) -> ::std::result::Result<T, Error> {
124 self.map_err(|x| Error {
125 kind,
126 cause: ::std::option::Option::Some(::std::boxed::Box::new(x.into())),
127 location: ::std::panic::Location::caller(),
128 })
129 }
130
131 fn err_context_with(
132 self,
133 f: impl FnOnce() -> $error_kind,
134 ) -> ::std::result::Result<T, Error> {
135 self.map_err(|x| Error {
136 kind: f(),
137 cause: ::std::option::Option::Some(::std::boxed::Box::new(x.into())),
138 location: ::std::panic::Location::caller(),
139 })
140 }
141 }
142 };
143}
144
145pub trait ErrorType {
147 type ErrorKind;
149
150 fn new(
153 kind: Self::ErrorKind,
154 cause: Option<Box<Self>>,
155 location: &'static Location<'static>,
156 ) -> Self;
157}
158
159pub trait ErrorContext<T, K, E> {
164 #[track_caller]
166 fn err_context(self, kind: K) -> Result<T, E>;
167
168 #[track_caller]
172 fn err_context_with(self, kind: impl FnOnce() -> K) -> Result<T, E>;
173}
174
175impl<T, K, E, OE> ErrorContext<T, K, E> for Result<T, OE>
176where
177 OE: Into<E>,
178 E: ErrorType<ErrorKind = K>,
179{
180 fn err_context(self, kind: K) -> Result<T, E> {
181 self.map_err(|x| E::new(kind, Some(Box::new(x.into())), Location::caller()))
182 }
183
184 fn err_context_with(self, f: impl FnOnce() -> K) -> Result<T, E> {
185 self.map_err(|x| E::new(f(), Some(Box::new(x.into())), Location::caller()))
186 }
187}