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 #[allow(dead_code)]
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 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 #[cfg_attr(feature = "error-track_caller", track_caller)]
119 pub const fn other_simple() -> Self {
120 Self::internal_new(K::OTHER, ErrorPayload::Simple)
121 }
122
123 #[cfg_attr(feature = "error-track_caller", track_caller)]
125 pub const fn other_with_message(msg: &'static str) -> Self {
126 Self::internal_new(K::OTHER, ErrorPayload::Message(msg))
127 }
128
129 #[cfg_attr(feature = "error-track_caller", track_caller)]
131 #[cfg(feature = "alloc")]
132 pub fn other<E: Into<Box<dyn core::error::Error + Send + Sync + 'static>>>(error: E) -> Self {
133 Self::internal_new(K::OTHER, ErrorPayload::Error(error.into()))
134 }
135
136 #[cfg_attr(feature = "error-track_caller", track_caller)]
138 pub fn uncategorized_simple() -> Self {
139 Self::internal_new(K::uncategorized(), ErrorPayload::Simple)
140 }
141
142 #[cfg_attr(feature = "error-track_caller", track_caller)]
144 pub fn uncategorized_with_message(msg: &'static str) -> Self {
145 Self::internal_new(K::uncategorized(), ErrorPayload::Message(msg))
146 }
147
148 #[cfg_attr(feature = "error-track_caller", track_caller)]
150 #[cfg(feature = "alloc")]
151 pub fn uncategorized<E: Into<Box<dyn core::error::Error + Send + Sync + 'static>>>(
152 error: E,
153 ) -> Self {
154 Self::internal_new(K::uncategorized(), ErrorPayload::Error(error.into()))
155 }
156}
157
158impl<K: FromRawOsError> Error<K> {
159 #[cfg_attr(feature = "error-track_caller", track_caller)]
161 pub fn from_raw_os_error(error: RawOsError) -> Self {
162 Self::internal_new(K::from_raw_os_error(error), ErrorPayload::RawOsError(error))
163 }
164}
165
166impl<K: ErrorKind> core::error::Error for Error<K> {}
167
168#[cfg(feature = "std")]
169impl<K: crate::kind::FromIoKind> From<std::io::ErrorKind> for Error<K> {
170 #[cfg_attr(feature = "error-track_caller", track_caller)]
171 fn from(kind: std::io::ErrorKind) -> Self {
172 Error::new_simple(K::from_io_error_kind(kind))
173 }
174}
175
176#[cfg(feature = "std")]
177impl<K: crate::kind::FromIoKind> From<std::io::Error> for Error<K> {
178 #[cfg_attr(feature = "error-track_caller", track_caller)]
179 fn from(value: std::io::Error) -> Self {
180 let kind = K::from_io_error_kind(value.kind());
181 if let Some(code) = value.raw_os_error() {
182 Self::internal_new(kind, ErrorPayload::RawOsError(code))
183 } else if let Some(data) = value.into_inner() {
184 Self::internal_new(kind, ErrorPayload::Error(data))
185 } else {
186 Self::internal_new(kind, ErrorPayload::Simple)
187 }
188 }
189}
190
191#[cfg(feature = "std")]
192impl<K: crate::kind::IntoIoKind> From<Error<K>> for std::io::Error {
193 fn from(value: Error<K>) -> Self {
194 if let Some(code) = value.raw_os_error() {
195 Self::from_raw_os_error(code)
196 } else {
197 let kind = K::into_io_error_kind(value.kind());
198
199 if let Some(payload) = value.into_error() {
200 std::io::Error::new(kind, payload)
201 } else {
202 std::io::Error::new(kind, "(no context)")
203 }
204 }
205 }
206}