1use std::io;
4use thiserror::Error;
5
6#[derive(Debug, Error)]
11pub enum NumaError {
12 #[error("memory policy not supported: {reason}")]
14 PolicyNotSupported {
15 policy: String,
17 reason: String,
19 },
20
21 #[error("missing capability: {capability}")]
23 CapabilityMissing {
24 capability: &'static str,
26 },
27
28 #[error("hard mode unavailable for {feature}: {reason}")]
30 HardModeUnavailable {
31 feature: &'static str,
33 reason: String,
35 },
36
37 #[error("topology discovery failed: {source}")]
39 TopologyError {
40 #[source]
42 source: io::Error,
43 },
44
45 #[error("allocation of {size} bytes failed: {source}")]
47 AllocationFailed {
48 size: usize,
50 #[source]
52 source: io::Error,
53 },
54
55 #[error("thread pinning failed: {source}")]
57 PinningFailed {
58 #[source]
60 source: io::Error,
61 },
62
63 #[error("memory binding failed: {source}")]
65 BindFailed {
66 #[source]
68 source: io::Error,
69 },
70
71 #[error("invalid argument: {message}")]
73 InvalidArgument {
74 message: String,
76 },
77
78 #[error("feature not supported on this platform: {feature}")]
80 NotSupported {
81 feature: &'static str,
83 },
84
85 #[error("I/O error: {0}")]
87 Io(#[from] io::Error),
88}
89
90impl NumaError {
91 pub fn topology(source: io::Error) -> Self {
93 Self::TopologyError { source }
94 }
95
96 pub fn allocation(size: usize, source: io::Error) -> Self {
98 Self::AllocationFailed { size, source }
99 }
100
101 pub fn pinning(source: io::Error) -> Self {
103 Self::PinningFailed { source }
104 }
105
106 pub fn bind(source: io::Error) -> Self {
108 Self::BindFailed { source }
109 }
110
111 pub fn policy_not_supported(policy: impl Into<String>, reason: impl Into<String>) -> Self {
113 Self::PolicyNotSupported {
114 policy: policy.into(),
115 reason: reason.into(),
116 }
117 }
118
119 pub fn hard_mode_unavailable(feature: &'static str, reason: impl Into<String>) -> Self {
121 Self::HardModeUnavailable {
122 feature,
123 reason: reason.into(),
124 }
125 }
126
127 pub fn invalid_argument(message: impl Into<String>) -> Self {
129 Self::InvalidArgument {
130 message: message.into(),
131 }
132 }
133
134 pub fn is_permission_error(&self) -> bool {
136 match self {
137 Self::CapabilityMissing { .. } => true,
138 Self::TopologyError { source }
139 | Self::AllocationFailed { source, .. }
140 | Self::PinningFailed { source }
141 | Self::BindFailed { source } => source.kind() == io::ErrorKind::PermissionDenied,
142 Self::Io(e) => e.kind() == io::ErrorKind::PermissionDenied,
143 _ => false,
144 }
145 }
146
147 pub fn is_not_supported(&self) -> bool {
149 matches!(
150 self,
151 Self::NotSupported { .. } | Self::PolicyNotSupported { .. }
152 )
153 }
154}
155
156pub type Result<T> = std::result::Result<T, NumaError>;
158
159#[cfg(test)]
160mod tests {
161 use super::*;
162
163 #[test]
164 fn test_error_display() {
165 let err = NumaError::policy_not_supported("Bind", "kernel too old");
166 assert_eq!(
167 format!("{}", err),
168 "memory policy not supported: kernel too old"
169 );
170
171 let err = NumaError::CapabilityMissing {
172 capability: "CAP_SYS_NICE",
173 };
174 assert_eq!(format!("{}", err), "missing capability: CAP_SYS_NICE");
175 }
176
177 #[test]
178 fn test_error_is_permission() {
179 let err = NumaError::CapabilityMissing {
180 capability: "CAP_SYS_NICE",
181 };
182 assert!(err.is_permission_error());
183
184 let err = NumaError::pinning(io::Error::from_raw_os_error(1));
186 assert!(err.is_permission_error());
187 }
188}