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