baracuda_core/error.rs
1//! Error types shared across the baracuda crates.
2
3use std::path::PathBuf;
4
5use baracuda_types::{CudaStatus, CudaVersion};
6use thiserror::Error;
7
8/// An error raised by the dynamic loader.
9///
10/// These surface whenever an NVIDIA shared library or one of its symbols
11/// cannot be resolved at runtime — typically because CUDA is not installed,
12/// the installed driver is older than what baracuda was built against, or
13/// the user is on a platform NVIDIA doesn't support.
14///
15/// `#[non_exhaustive]` — new loader failure modes may land as CUDA
16/// adds entry points (`cuGetProcAddress` v2, the per-library minor-
17/// version checks). Match arms must include a `_ =>` catch-all.
18#[derive(Debug, Error)]
19#[non_exhaustive]
20pub enum LoaderError {
21 /// None of the candidate library filenames resolved anywhere on the
22 /// library search path.
23 #[error("could not load {library}: tried {candidates:?} across {search_paths} path(s)")]
24 LibraryNotFound {
25 /// Value field.
26 library: &'static str,
27 /// Value field.
28 candidates: Vec<&'static str>,
29 /// Value field.
30 search_paths: usize,
31 },
32
33 /// The library was loaded but did not export the requested symbol.
34 #[error("library '{library}' is missing symbol '{symbol}'")]
35 SymbolNotFound {
36 /// Value field.
37 library: &'static str,
38 /// Value field.
39 symbol: &'static str,
40 },
41
42 /// `cuGetProcAddress` returned `CU_GET_PROC_ADDRESS_VERSION_NOT_SUFFICIENT`
43 /// for `symbol`: the installed driver does not provide it at the version
44 /// baracuda asked for.
45 #[error("symbol '{symbol}' requires {required} but baracuda's driver loader sees {installed}")]
46 VersionTooOld {
47 /// Value field.
48 symbol: &'static str,
49 /// Value field.
50 required: CudaVersion,
51 /// Value field.
52 installed: CudaVersion,
53 },
54
55 /// Raw `libloading` error — kept for platform-specific diagnostics that
56 /// the other variants can't express (e.g. a missing dependency on a
57 /// chained `.so`).
58 #[error("{0}")]
59 Libloading(#[from] libloading::Error),
60
61 /// baracuda does not target this platform (e.g. macOS).
62 #[error(
63 "baracuda does not support {platform}; NVIDIA driver is only available on Linux and Windows"
64 )]
65 UnsupportedPlatform {
66 /// Name of the unsupported platform (e.g. "macOS").
67 platform: &'static str,
68 },
69}
70
71impl LoaderError {
72 /// Convenience constructor for the common case of "tried these names,
73 /// none worked".
74 pub fn library_not_found(library: &'static str, candidates: &[&'static str]) -> Self {
75 Self::LibraryNotFound {
76 library,
77 candidates: candidates.to_vec(),
78 search_paths: 0,
79 }
80 }
81
82 /// As above, but records how many directories were searched.
83 pub fn library_not_found_with_search(
84 library: &'static str,
85 candidates: &[&'static str],
86 search_path_count: usize,
87 ) -> Self {
88 Self::LibraryNotFound {
89 library,
90 candidates: candidates.to_vec(),
91 search_paths: search_path_count,
92 }
93 }
94}
95
96/// A generic error enum for any safe wrapper crate over a single NVIDIA
97/// library. Safe crates may use this directly or compose their own richer
98/// `Error` enum out of its variants.
99///
100/// `#[non_exhaustive]` — new error variants may land as new failure modes
101/// are surfaced by NVIDIA libraries. Match arms must include a `_ =>`
102/// catch-all.
103#[derive(Debug, Error)]
104#[non_exhaustive]
105pub enum Error<S>
106where
107 S: CudaStatus + Send + Sync + 'static,
108{
109 /// The library returned a non-success status code.
110 #[error("{} returned {} ({}): {}", .status.library(), .status.name(), .status.code(), .status.description())]
111 Status {
112 /// The non-success status code returned by the underlying library.
113 status: S,
114 },
115
116 /// The dynamic loader failed.
117 #[error(transparent)]
118 Loader(#[from] LoaderError),
119
120 /// The requested API is newer than the installed driver supports.
121 #[error("{api} requires {since}; install a newer driver to use it")]
122 FeatureNotSupported {
123 /// Value field.
124 api: &'static str,
125 /// Value field.
126 since: CudaVersion,
127 },
128}
129
130impl<S> Error<S>
131where
132 S: CudaStatus + Send + Sync + 'static,
133{
134 /// Treat a raw status code as a `Result`. Success codes yield `Ok(())`,
135 /// all others yield `Err(Error::Status { .. })`.
136 pub fn check(status: S) -> Result<(), Self> {
137 if status.is_success() {
138 Ok(())
139 } else {
140 Err(Self::Status { status })
141 }
142 }
143}
144
145/// A library-erased error, useful at process boundaries where the caller
146/// doesn't want to parameterize over every NVIDIA library's status enum.
147///
148/// `#[non_exhaustive]` — new error categories may land as the workspace
149/// adds backends. Match arms must include a `_ =>` catch-all.
150#[derive(Debug, Error)]
151#[non_exhaustive]
152pub enum BaracudaError {
153 /// A status code from any NVIDIA library.
154 #[error("{library} returned {name} ({code}): {description}")]
155 Status {
156 /// Value field.
157 library: &'static str,
158 /// Value field.
159 name: &'static str,
160 /// Value field.
161 description: &'static str,
162 /// Value field.
163 code: i32,
164 },
165
166 /// The dynamic loader failed.
167 #[error(transparent)]
168 Loader(#[from] LoaderError),
169
170 /// The requested API is newer than the installed driver supports.
171 #[error("{api} requires {since}; install a newer driver to use it")]
172 FeatureNotSupported {
173 /// Value field.
174 api: &'static str,
175 /// Value field.
176 since: CudaVersion,
177 },
178
179 /// For sources that want to attach a path or other context (e.g. a
180 /// missing PTX file).
181 #[error("{context}")]
182 Context {
183 /// Free-form context attached by the failing call site.
184 context: &'static str,
185 },
186}
187
188impl<S> From<Error<S>> for BaracudaError
189where
190 S: CudaStatus + Send + Sync + 'static,
191{
192 fn from(err: Error<S>) -> Self {
193 match err {
194 Error::Status { status } => BaracudaError::Status {
195 library: status.library(),
196 name: status.name(),
197 description: status.description(),
198 code: status.code(),
199 },
200 Error::Loader(l) => BaracudaError::Loader(l),
201 Error::FeatureNotSupported { api, since } => {
202 BaracudaError::FeatureNotSupported { api, since }
203 }
204 }
205 }
206}
207
208/// Path-returning variant used by `find_library` probes. (Kept out of public
209/// API surface for now — re-exported here so doc-links work.)
210#[allow(dead_code)]
211pub(crate) type PathList = Vec<PathBuf>;