1use alloc::sync::Arc;
10use core::fmt;
11use std::io;
12use std::os::raw::c_int;
13use std::sync::Mutex;
14
15pub(crate) type Result<T> = core::result::Result<T, Error>;
17
18#[derive(Debug, Clone)]
20#[non_exhaustive]
21pub enum ErrorKind {
22 TooManyVMPages,
24
25 UnknownPageSize,
27
28 InvalidPageSize(u64),
30
31 #[non_exhaustive]
33 Io {
34 operation: &'static str,
36 error: Arc<io::Error>,
38 process_id: Option<libc::pid_t>,
40 },
41
42 #[non_exhaustive]
44 IntegerCast(core::num::TryFromIntError),
45}
46
47struct ErrorBackTrace {
49 backtrace: backtrace::Backtrace,
50 resolved: bool,
51}
52
53impl ErrorBackTrace {
54 fn resolve(&mut self) {
57 if !self.resolved {
58 self.resolved = true;
59 self.backtrace.resolve();
60 }
61 }
62}
63
64impl fmt::Debug for ErrorBackTrace {
65 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
66 fmt::Debug::fmt(&self.backtrace, f)
67 }
68}
69
70#[derive(Clone)]
72struct ErrorData {
73 kind: ErrorKind,
74 backtrace: Arc<Mutex<ErrorBackTrace>>,
75}
76
77impl fmt::Debug for ErrorData {
78 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
79 let mut back_trace_lock = self.backtrace.lock().unwrap();
80 back_trace_lock.resolve();
81 write!(f, "Error: {:?}. At:\n{:?}", self.kind, *back_trace_lock)
82 }
83}
84
85#[derive(Debug, Clone)]
87#[non_exhaustive]
88pub struct Error(Box<ErrorData>);
89
90impl fmt::Display for Error {
91 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
92 match &self.0.kind {
93 ErrorKind::TooManyVMPages => {
94 write!(f, "virtual memory address range contains too many pages")
95 }
96 ErrorKind::UnknownPageSize => {
97 write!(f, "failed to query the system page size")
98 }
99 ErrorKind::InvalidPageSize(size) => {
100 write!(f, "invalid system page size: {size} bytes")
101 }
102 ErrorKind::Io {
103 operation,
104 error,
105 process_id,
106 } => match process_id {
107 None => write!(f, "{operation}: {error}"),
108 Some(process_id) => write!(f, "{operation}({process_id}): {error}"),
109 },
110 ErrorKind::IntegerCast(err) => err.fmt(f),
111 }
112 }
113}
114
115impl core::error::Error for Error {
116 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
117 match &self.0.kind {
118 ErrorKind::TooManyVMPages
120 | ErrorKind::UnknownPageSize
121 | ErrorKind::InvalidPageSize(_)
122 | ErrorKind::Io { .. } => None,
123
124 ErrorKind::IntegerCast(err) => Some(err),
126 }
127 }
128}
129
130impl From<ErrorKind> for Error {
132 fn from(kind: ErrorKind) -> Self {
133 let backtrace = backtrace::Backtrace::new_unresolved();
134
135 Self(Box::new(ErrorData {
136 kind,
137 backtrace: Arc::new(Mutex::new(ErrorBackTrace {
138 backtrace,
139 resolved: false,
140 })),
141 }))
142 }
143}
144
145impl From<core::num::TryFromIntError> for Error {
147 fn from(err: core::num::TryFromIntError) -> Self {
148 Self::from(ErrorKind::IntegerCast(err))
149 }
150}
151
152impl Error {
153 pub(crate) fn from_io3(
155 error: io::Error,
156 operation: &'static str,
157 process_id: libc::pid_t,
158 ) -> Self {
159 ErrorKind::Io {
160 operation,
161 error: Arc::new(error),
162 process_id: Some(process_id),
163 }
164 .into()
165 }
166
167 #[must_use]
169 pub fn kind(&self) -> &ErrorKind {
170 &self.0.kind
171 }
172
173 #[must_use]
176 pub fn os_error_code(&self) -> Option<c_int> {
177 match &self.0.kind {
178 ErrorKind::TooManyVMPages
179 | ErrorKind::UnknownPageSize
180 | ErrorKind::InvalidPageSize(_)
181 | ErrorKind::IntegerCast { .. } => None,
182
183 ErrorKind::Io { error, .. } => error.raw_os_error(),
184 }
185 }
186}