Skip to main content

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        library: &'static str,
26        candidates: Vec<&'static str>,
27        search_paths: usize,
28    },
29
30    /// The library was loaded but did not export the requested symbol.
31    #[error("library '{library}' is missing symbol '{symbol}'")]
32    SymbolNotFound {
33        library: &'static str,
34        symbol: &'static str,
35    },
36
37    /// `cuGetProcAddress` returned `CU_GET_PROC_ADDRESS_VERSION_NOT_SUFFICIENT`
38    /// for `symbol`: the installed driver does not provide it at the version
39    /// baracuda asked for.
40    #[error("symbol '{symbol}' requires {required} but baracuda's driver loader sees {installed}")]
41    VersionTooOld {
42        symbol: &'static str,
43        required: CudaVersion,
44        installed: CudaVersion,
45    },
46
47    /// Raw `libloading` error — kept for platform-specific diagnostics that
48    /// the other variants can't express (e.g. a missing dependency on a
49    /// chained `.so`).
50    #[error("{0}")]
51    Libloading(#[from] libloading::Error),
52
53    /// baracuda does not target this platform (e.g. macOS).
54    #[error("baracuda does not support {platform}; NVIDIA driver is only available on Linux and Windows")]
55    UnsupportedPlatform { platform: &'static str },
56}
57
58impl LoaderError {
59    /// Convenience constructor for the common case of "tried these names,
60    /// none worked".
61    pub fn library_not_found(library: &'static str, candidates: &[&'static str]) -> Self {
62        Self::LibraryNotFound {
63            library,
64            candidates: candidates.to_vec(),
65            search_paths: 0,
66        }
67    }
68
69    /// As above, but records how many directories were searched.
70    pub fn library_not_found_with_search(
71        library: &'static str,
72        candidates: &[&'static str],
73        search_path_count: usize,
74    ) -> Self {
75        Self::LibraryNotFound {
76            library,
77            candidates: candidates.to_vec(),
78            search_paths: search_path_count,
79        }
80    }
81}
82
83/// A generic error enum for any safe wrapper crate over a single NVIDIA
84/// library. Safe crates may use this directly or compose their own richer
85/// `Error` enum out of its variants.
86///
87/// `#[non_exhaustive]` — new error variants may land as new failure modes
88/// are surfaced by NVIDIA libraries. Match arms must include a `_ =>`
89/// catch-all.
90#[derive(Debug, Error)]
91#[non_exhaustive]
92pub enum Error<S>
93where
94    S: CudaStatus + Send + Sync + 'static,
95{
96    /// The library returned a non-success status code.
97    #[error("{} returned {} ({}): {}", .status.library(), .status.name(), .status.code(), .status.description())]
98    Status { status: S },
99
100    /// The dynamic loader failed.
101    #[error(transparent)]
102    Loader(#[from] LoaderError),
103
104    /// The requested API is newer than the installed driver supports.
105    #[error("{api} requires {since}; install a newer driver to use it")]
106    FeatureNotSupported {
107        api: &'static str,
108        since: CudaVersion,
109    },
110}
111
112impl<S> Error<S>
113where
114    S: CudaStatus + Send + Sync + 'static,
115{
116    /// Treat a raw status code as a `Result`. Success codes yield `Ok(())`,
117    /// all others yield `Err(Error::Status { .. })`.
118    pub fn check(status: S) -> Result<(), Self> {
119        if status.is_success() {
120            Ok(())
121        } else {
122            Err(Self::Status { status })
123        }
124    }
125}
126
127/// A library-erased error, useful at process boundaries where the caller
128/// doesn't want to parameterize over every NVIDIA library's status enum.
129///
130/// `#[non_exhaustive]` — new error categories may land as the workspace
131/// adds backends. Match arms must include a `_ =>` catch-all.
132#[derive(Debug, Error)]
133#[non_exhaustive]
134pub enum BaracudaError {
135    /// A status code from any NVIDIA library.
136    #[error("{library} returned {name} ({code}): {description}")]
137    Status {
138        library: &'static str,
139        name: &'static str,
140        description: &'static str,
141        code: i32,
142    },
143
144    /// The dynamic loader failed.
145    #[error(transparent)]
146    Loader(#[from] LoaderError),
147
148    /// The requested API is newer than the installed driver supports.
149    #[error("{api} requires {since}; install a newer driver to use it")]
150    FeatureNotSupported {
151        api: &'static str,
152        since: CudaVersion,
153    },
154
155    /// For sources that want to attach a path or other context (e.g. a
156    /// missing PTX file).
157    #[error("{context}")]
158    Context { context: &'static str },
159}
160
161impl<S> From<Error<S>> for BaracudaError
162where
163    S: CudaStatus + Send + Sync + 'static,
164{
165    fn from(err: Error<S>) -> Self {
166        match err {
167            Error::Status { status } => BaracudaError::Status {
168                library: status.library(),
169                name: status.name(),
170                description: status.description(),
171                code: status.code(),
172            },
173            Error::Loader(l) => BaracudaError::Loader(l),
174            Error::FeatureNotSupported { api, since } => {
175                BaracudaError::FeatureNotSupported { api, since }
176            }
177        }
178    }
179}
180
181/// Path-returning variant used by `find_library` probes. (Kept out of public
182/// API surface for now — re-exported here so doc-links work.)
183#[allow(dead_code)]
184pub(crate) type PathList = Vec<PathBuf>;