1use crate::{
2 RawOsError,
3 kind::{ErrorKind, FromRawOsError},
4};
5
6#[cfg(feature = "alloc")]
7use alloc::boxed::Box;
8
9#[derive(Debug)]
10enum ErrorPayload {
11 Simple,
12 RawOsError(RawOsError),
13 Message(&'static str),
14 #[cfg(feature = "alloc")]
15 Error(Box<dyn core::error::Error + Send + Sync + 'static>),
16}
17
18#[derive(Debug)]
21pub struct Error<K> {
22 kind: K,
23 payload: ErrorPayload,
24 #[cfg(feature = "error-track_caller")]
25 #[expect(dead_code, reason = "Intentionally Unused Field for debugging only")]
26 caller_location: &'static core::panic::Location<'static>, }
28
29impl<K: ErrorKind> core::fmt::Display for Error<K> {
30 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
31 core::fmt::Display::fmt(&self.kind, f)?;
32 match &self.payload {
33 ErrorPayload::Simple => Ok(()),
34 ErrorPayload::RawOsError(os) => f.write_fmt(format_args!(" (raw os error {os})")),
35 ErrorPayload::Message(m) => f.write_fmt(format_args!(": {m}")),
36 #[cfg(feature = "alloc")]
37 ErrorPayload::Error(error) => f.write_fmt(format_args!(": {error}")),
38 }
39 }
40}
41
42impl<K> Error<K> {
43 #[cfg_attr(feature = "error-track_caller", track_caller)]
44 const fn internal_new(kind: K, payload: ErrorPayload) -> Self {
45 Self {
46 kind,
47 payload,
48 #[cfg(feature = "error-track_caller")]
49 caller_location: core::panic::Location::caller(),
50 }
51 }
52
53 #[cfg_attr(feature = "error-track_caller", track_caller)]
55 pub const fn new_simple(kind: K) -> Self {
56 Self::internal_new(kind, ErrorPayload::Simple)
57 }
58
59 #[cfg_attr(feature = "error-track_caller", track_caller)]
61 pub const fn new_with_message(kind: K, msg: &'static str) -> Self {
62 Self::internal_new(kind, ErrorPayload::Message(msg))
63 }
64
65 #[cfg_attr(feature = "error-track_caller", track_caller)]
67 #[cfg(feature = "alloc")]
68 pub fn new<E: Into<Box<dyn core::error::Error + Send + Sync + 'static>>>(
69 kind: K,
70 error: E,
71 ) -> Self {
72 Self::internal_new(kind, ErrorPayload::Error(error.into()))
73 }
74
75 pub const fn kind(&self) -> K
77 where
78 K: Copy,
79 {
80 self.kind
81 }
82
83 pub fn raw_os_error(&self) -> Option<RawOsError> {
85 match self.payload {
86 ErrorPayload::RawOsError(e) => Some(e),
87 _ => None,
88 }
89 }
90
91 #[cfg(feature = "alloc")]
97 pub fn into_error(self) -> Option<Box<dyn core::error::Error + Send + Sync + 'static>> {
98 match self.payload {
99 ErrorPayload::Error(payload) => Some(payload),
100 ErrorPayload::Message(m) => Some(m.into()),
101 _ => None,
102 }
103 }
104
105 #[cfg(feature = "alloc")]
108 pub fn into_inner(self) -> Option<Box<dyn core::error::Error + Send + Sync + 'static>> {
109 match self.payload {
110 ErrorPayload::Error(payload) => Some(payload),
111 _ => None,
112 }
113 }
114}
115
116impl<K: ErrorKind> Error<K> {
117
118 #[cfg_attr(feature = "error-track_caller", track_caller)]
119 const fn internal_other(payload: ErrorPayload) -> Self {
120 Self::internal_new(K::OTHER, payload)
121 }
122
123 #[cfg_attr(feature = "error-track_caller", track_caller)]
125 pub const fn other_simple() -> Self {
126 Self::internal_other(ErrorPayload::Simple)
127 }
128
129 #[cfg_attr(feature = "error-track_caller", track_caller)]
131 pub const fn other_with_message(msg: &'static str) -> Self {
132 Self::internal_other(ErrorPayload::Message(msg))
133 }
134
135 #[cfg_attr(feature = "error-track_caller", track_caller)]
137 #[cfg(feature = "alloc")]
138 pub fn other<E: Into<Box<dyn core::error::Error + Send + Sync + 'static>>>(error: E) -> Self {
139 Self::internal_other(ErrorPayload::Error(error.into()))
140 }
141
142 #[cfg_attr(feature = "error-track_caller", track_caller)]
143 fn internal_uncategorized(payload: ErrorPayload) -> Self {
144 Self::internal_new(K::uncategorized(), payload)
145 }
146
147 #[cfg_attr(feature = "error-track_caller", track_caller)]
149 pub fn uncategorized_simple() -> Self {
150 Self::internal_uncategorized(ErrorPayload::Simple)
151 }
152
153 #[cfg_attr(feature = "error-track_caller", track_caller)]
155 pub fn uncategorized_with_message(msg: &'static str) -> Self {
156 Self::internal_uncategorized(ErrorPayload::Message(msg))
157 }
158
159 #[cfg_attr(feature = "error-track_caller", track_caller)]
161 #[cfg(feature = "alloc")]
162 pub fn uncategorized<E: Into<Box<dyn core::error::Error + Send + Sync + 'static>>>(
163 error: E,
164 ) -> Self {
165 Self::internal_uncategorized(ErrorPayload::Error(error.into()))
166 }
167}
168
169impl<K: FromRawOsError> Error<K> {
170 #[cfg_attr(feature = "error-track_caller", track_caller)]
172 pub fn from_raw_os_error(error: RawOsError) -> Self {
173 Self::internal_new(K::from_raw_os_error(error), ErrorPayload::RawOsError(error))
174 }
175}
176
177impl<K: ErrorKind> core::error::Error for Error<K> {}
178
179#[cfg(feature = "std")]
180impl<K: crate::kind::FromIoKind> From<std::io::ErrorKind> for Error<K> {
181 #[cfg_attr(feature = "error-track_caller", track_caller)]
182 fn from(kind: std::io::ErrorKind) -> Self {
183 Error::new_simple(K::from_io_error_kind(kind))
184 }
185}
186
187#[cfg(feature = "std")]
188impl<K: crate::kind::FromIoKind> From<std::io::Error> for Error<K> {
189 #[cfg_attr(feature = "error-track_caller", track_caller)]
190 fn from(value: std::io::Error) -> Self {
191 let kind = K::from_io_error_kind(value.kind());
192 if let Some(code) = value.raw_os_error() {
193 Self::internal_new(kind, ErrorPayload::RawOsError(code))
194 } else if let Some(data) = value.into_inner() {
195 Self::internal_new(kind, ErrorPayload::Error(data))
196 } else {
197 Self::internal_new(kind, ErrorPayload::Simple)
198 }
199 }
200}
201
202#[cfg(feature = "std")]
203impl<K: crate::kind::IntoIoKind> From<Error<K>> for std::io::Error {
204 fn from(value: Error<K>) -> Self {
205 if let Some(code) = value.raw_os_error() {
206 Self::from_raw_os_error(code)
207 } else {
208 let kind = K::into_io_error_kind(value.kind());
209
210 if let Some(payload) = value.into_error() {
211 std::io::Error::new(kind, payload)
212 } else {
213 std::io::Error::new(kind, "(no context)")
214 }
215 }
216 }
217}