Skip to main content

oxicuda_runtime/
error.rs

1//! CUDA Runtime API error types.
2//!
3//! The Runtime API uses `cudaError_t` (a C enum) as its primary error code.
4//! This module maps all standard `cudaError_t` values to [`CudaRtError`] and
5//! provides [`CudaRtResult`] for ergonomic `?` propagation.
6
7use thiserror::Error;
8
9// =========================================================================
10// CudaRtError
11// =========================================================================
12
13/// CUDA Runtime API error.
14///
15/// Each variant corresponds to a distinct `cudaError_t` value from the
16/// CUDA Runtime specification. The integer discriminant matches the canonical
17/// `cudaError_t` value so that raw codes received through FFI can be
18/// converted cheaply via [`from_code`](CudaRtError::from_code).
19#[derive(Debug, Clone, PartialEq, Eq, Hash, Error)]
20#[repr(u32)]
21pub enum CudaRtError {
22    /// `cudaErrorInvalidValue` (1) — an invalid value was supplied.
23    #[error("CUDA RT: invalid value")]
24    InvalidValue = 1,
25
26    /// `cudaErrorMemoryAllocation` (2) — device memory allocation failed.
27    #[error("CUDA RT: out of device memory")]
28    MemoryAllocation = 2,
29
30    /// `cudaErrorInitializationError` (3) — CUDA initialization failed.
31    #[error("CUDA RT: initialization error")]
32    InitializationError = 3,
33
34    /// `cudaErrorCudartUnloading` (4) — CUDA runtime is unloading.
35    #[error("CUDA RT: CUDA runtime is unloading")]
36    CudartUnloading = 4,
37
38    /// `cudaErrorProfilerDisabled` (5) — profiler was disabled.
39    #[error("CUDA RT: profiler disabled")]
40    ProfilerDisabled = 5,
41
42    /// `cudaErrorInvalidConfiguration` (9) — invalid kernel launch configuration.
43    #[error("CUDA RT: invalid launch configuration")]
44    InvalidConfiguration = 9,
45
46    /// `cudaErrorInvalidPitchValue` (12)
47    #[error("CUDA RT: invalid pitch value")]
48    InvalidPitchValue = 12,
49
50    /// `cudaErrorInvalidSymbol` (13)
51    #[error("CUDA RT: invalid symbol")]
52    InvalidSymbol = 13,
53
54    /// `cudaErrorInvalidHostPointer` (16)
55    #[error("CUDA RT: invalid host pointer")]
56    InvalidHostPointer = 16,
57
58    /// `cudaErrorInvalidDevicePointer` (17)
59    #[error("CUDA RT: invalid device pointer")]
60    InvalidDevicePointer = 17,
61
62    /// `cudaErrorInvalidTexture` (18)
63    #[error("CUDA RT: invalid texture")]
64    InvalidTexture = 18,
65
66    /// `cudaErrorInvalidTextureBinding` (19)
67    #[error("CUDA RT: invalid texture binding")]
68    InvalidTextureBinding = 19,
69
70    /// `cudaErrorInvalidChannelDescriptor` (20)
71    #[error("CUDA RT: invalid channel descriptor")]
72    InvalidChannelDescriptor = 20,
73
74    /// `cudaErrorInvalidMemcpyDirection` (21)
75    #[error("CUDA RT: invalid memcpy direction")]
76    InvalidMemcpyDirection = 21,
77
78    /// `cudaErrorInvalidFilterSetting` (26)
79    #[error("CUDA RT: invalid filter setting")]
80    InvalidFilterSetting = 26,
81
82    /// `cudaErrorInvalidNormSetting` (27)
83    #[error("CUDA RT: invalid norm setting")]
84    InvalidNormSetting = 27,
85
86    /// `cudaErrorStubLibrary` (34) — stub library loaded instead of real driver.
87    #[error("CUDA RT: stub library")]
88    StubLibrary = 34,
89
90    /// `cudaErrorInsufficientDriver` (35) — installed driver is too old.
91    #[error("CUDA RT: installed driver version is insufficient")]
92    InsufficientDriver = 35,
93
94    /// `cudaErrorCallRequiresNewerDriver` (36)
95    #[error("CUDA RT: call requires a newer driver version")]
96    CallRequiresNewerDriver = 36,
97
98    /// `cudaErrorInvalidSurface` (37)
99    #[error("CUDA RT: invalid surface")]
100    InvalidSurface = 37,
101
102    /// `cudaErrorDuplicateVariableName` (43)
103    #[error("CUDA RT: duplicate variable name")]
104    DuplicateVariableName = 43,
105
106    /// `cudaErrorDuplicateTextureName` (44)
107    #[error("CUDA RT: duplicate texture name")]
108    DuplicateTextureName = 44,
109
110    /// `cudaErrorDuplicateSurfaceName` (45)
111    #[error("CUDA RT: duplicate surface name")]
112    DuplicateSurfaceName = 45,
113
114    /// `cudaErrorDevicesUnavailable` (46)
115    #[error("CUDA RT: all CUDA-capable devices are busy or unavailable")]
116    DevicesUnavailable = 46,
117
118    /// `cudaErrorIncompatibleDriverContext` (49)
119    #[error("CUDA RT: incompatible driver context")]
120    IncompatibleDriverContext = 49,
121
122    /// `cudaErrorMissingConfiguration` (52)
123    #[error("CUDA RT: missing configuration")]
124    MissingConfiguration = 52,
125
126    /// `cudaErrorLaunchMaxDepthExceeded` (65)
127    #[error("CUDA RT: launch max depth exceeded (dynamic parallelism)")]
128    LaunchMaxDepthExceeded = 65,
129
130    /// `cudaErrorLaunchFileScopedTex` (66)
131    #[error("CUDA RT: attempted launch of file-scoped texture")]
132    LaunchFileScopedTex = 66,
133
134    /// `cudaErrorLaunchFileScopedSurf` (67)
135    #[error("CUDA RT: attempted launch of file-scoped surface")]
136    LaunchFileScopedSurf = 67,
137
138    /// `cudaErrorSyncDepthExceeded` (68)
139    #[error("CUDA RT: sync depth exceeded")]
140    SyncDepthExceeded = 68,
141
142    /// `cudaErrorLaunchPendingCountExceeded` (69)
143    #[error("CUDA RT: launch pending count exceeded")]
144    LaunchPendingCountExceeded = 69,
145
146    /// `cudaErrorInvalidDeviceFunction` (98)
147    #[error("CUDA RT: invalid device function")]
148    InvalidDeviceFunction = 98,
149
150    /// `cudaErrorNoDevice` (100) — no CUDA-capable device is detected.
151    #[error("CUDA RT: no CUDA-capable device found")]
152    NoDevice = 100,
153
154    /// `cudaErrorInvalidDevice` (101) — the specified device is invalid.
155    #[error("CUDA RT: invalid device ordinal")]
156    InvalidDevice = 101,
157
158    /// `cudaErrorDeviceNotLicensed` (102)
159    #[error("CUDA RT: device not licensed for compute")]
160    DeviceNotLicensed = 102,
161
162    /// `cudaErrorSoftwareValidityNotEstablished` (103)
163    #[error("CUDA RT: software validity not established")]
164    SoftwareValidityNotEstablished = 103,
165
166    /// `cudaErrorStartupFailure` (127)
167    #[error("CUDA RT: startup failure")]
168    StartupFailure = 127,
169
170    /// `cudaErrorInvalidKernelImage` (200)
171    #[error("CUDA RT: invalid kernel image")]
172    InvalidKernelImage = 200,
173
174    /// `cudaErrorDeviceUninitialized` (201)
175    #[error("CUDA RT: device uninitialized")]
176    DeviceUninitialized = 201,
177
178    /// `cudaErrorMapBufferObjectFailed` (205)
179    #[error("CUDA RT: map buffer object failed")]
180    MapBufferObjectFailed = 205,
181
182    /// `cudaErrorUnmapBufferObjectFailed` (206)
183    #[error("CUDA RT: unmap buffer object failed")]
184    UnmapBufferObjectFailed = 206,
185
186    /// `cudaErrorArrayIsMapped` (207)
187    #[error("CUDA RT: array is mapped")]
188    ArrayIsMapped = 207,
189
190    /// `cudaErrorAlreadyMapped` (208)
191    #[error("CUDA RT: already mapped")]
192    AlreadyMapped = 208,
193
194    /// `cudaErrorNoKernelImageForDevice` (209)
195    #[error("CUDA RT: no kernel image for this device")]
196    NoKernelImageForDevice = 209,
197
198    /// `cudaErrorAlreadyAcquired` (210)
199    #[error("CUDA RT: already acquired")]
200    AlreadyAcquired = 210,
201
202    /// `cudaErrorNotMapped` (211)
203    #[error("CUDA RT: not mapped")]
204    NotMapped = 211,
205
206    /// `cudaErrorNotMappedAsArray` (212)
207    #[error("CUDA RT: not mapped as array")]
208    NotMappedAsArray = 212,
209
210    /// `cudaErrorNotMappedAsPointer` (213)
211    #[error("CUDA RT: not mapped as pointer")]
212    NotMappedAsPointer = 213,
213
214    /// `cudaErrorECCUncorrectable` (214)
215    #[error("CUDA RT: uncorrectable ECC error")]
216    EccUncorrectable = 214,
217
218    /// `cudaErrorUnsupportedLimit` (215)
219    #[error("CUDA RT: unsupported limit")]
220    UnsupportedLimit = 215,
221
222    /// `cudaErrorDeviceAlreadyInUse` (216)
223    #[error("CUDA RT: device already in use")]
224    DeviceAlreadyInUse = 216,
225
226    /// `cudaErrorPeerAccessUnsupported` (217)
227    #[error("CUDA RT: peer access unsupported")]
228    PeerAccessUnsupported = 217,
229
230    /// `cudaErrorInvalidPtx` (218)
231    #[error("CUDA RT: invalid PTX")]
232    InvalidPtx = 218,
233
234    /// `cudaErrorInvalidGraphicsContext` (219)
235    #[error("CUDA RT: invalid graphics context")]
236    InvalidGraphicsContext = 219,
237
238    /// `cudaErrorNvlinkUncorrectable` (220)
239    #[error("CUDA RT: NVLink uncorrectable error")]
240    NvlinkUncorrectable = 220,
241
242    /// `cudaErrorJitCompilerNotFound` (221)
243    #[error("CUDA RT: JIT compiler not found")]
244    JitCompilerNotFound = 221,
245
246    /// `cudaErrorUnsupportedPtxVersion` (222)
247    #[error("CUDA RT: unsupported PTX version")]
248    UnsupportedPtxVersion = 222,
249
250    /// `cudaErrorJitCompilationDisabled` (223)
251    #[error("CUDA RT: JIT compilation disabled")]
252    JitCompilationDisabled = 223,
253
254    /// `cudaErrorUnsupportedExecAffinity` (224)
255    #[error("CUDA RT: unsupported exec affinity")]
256    UnsupportedExecAffinity = 224,
257
258    /// `cudaErrorUnsupportedDevSideSync` (225)
259    #[error("CUDA RT: unsupported device-side sync")]
260    UnsupportedDevSideSync = 225,
261
262    /// `cudaErrorInvalidSource` (300)
263    #[error("CUDA RT: invalid source")]
264    InvalidSource = 300,
265
266    /// `cudaErrorFileNotFound` (301)
267    #[error("CUDA RT: file not found")]
268    FileNotFound = 301,
269
270    /// `cudaErrorSharedObjectSymbolNotFound` (302)
271    #[error("CUDA RT: shared object symbol not found")]
272    SharedObjectSymbolNotFound = 302,
273
274    /// `cudaErrorSharedObjectInitFailed` (303)
275    #[error("CUDA RT: shared object init failed")]
276    SharedObjectInitFailed = 303,
277
278    /// `cudaErrorOperatingSystem` (304)
279    #[error("CUDA RT: operating system error")]
280    OperatingSystem = 304,
281
282    /// `cudaErrorInvalidResourceHandle` (400)
283    #[error("CUDA RT: invalid resource handle")]
284    InvalidResourceHandle = 400,
285
286    /// `cudaErrorIllegalState` (401)
287    #[error("CUDA RT: illegal state")]
288    IllegalState = 401,
289
290    /// `cudaErrorLostConnection` (402)
291    #[error("CUDA RT: lost connection to client")]
292    LostConnection = 402,
293
294    /// `cudaErrorSymbolNotFound` (500)
295    #[error("CUDA RT: named symbol not found")]
296    SymbolNotFound = 500,
297
298    /// `cudaErrorNotReady` (600) — async operation not yet complete.
299    #[error("CUDA RT: operation not ready")]
300    NotReady = 600,
301
302    /// `cudaErrorIllegalAddress` (700)
303    #[error("CUDA RT: illegal memory access")]
304    IllegalAddress = 700,
305
306    /// `cudaErrorLaunchOutOfResources` (701)
307    #[error("CUDA RT: launch out of resources")]
308    LaunchOutOfResources = 701,
309
310    /// `cudaErrorLaunchTimeout` (702)
311    #[error("CUDA RT: launch timed out")]
312    LaunchTimeout = 702,
313
314    /// `cudaErrorLaunchIncompatibleTexturing` (703)
315    #[error("CUDA RT: incompatible texturing mode")]
316    LaunchIncompatibleTexturing = 703,
317
318    /// `cudaErrorPeerAccessAlreadyEnabled` (704)
319    #[error("CUDA RT: peer access already enabled")]
320    PeerAccessAlreadyEnabled = 704,
321
322    /// `cudaErrorPeerAccessNotEnabled` (705)
323    #[error("CUDA RT: peer access not enabled")]
324    PeerAccessNotEnabled = 705,
325
326    /// `cudaErrorSetOnActiveProcess` (708)
327    #[error("CUDA RT: cannot set while active process")]
328    SetOnActiveProcess = 708,
329
330    /// `cudaErrorContextIsDestroyed` (709)
331    #[error("CUDA RT: context is destroyed")]
332    ContextIsDestroyed = 709,
333
334    /// `cudaErrorAssert` (710) — device-side assertion triggered.
335    #[error("CUDA RT: device assertion triggered")]
336    Assert = 710,
337
338    /// `cudaErrorTooManyPeers` (711)
339    #[error("CUDA RT: too many peer mappings")]
340    TooManyPeers = 711,
341
342    /// `cudaErrorHostMemoryAlreadyRegistered` (712)
343    #[error("CUDA RT: host memory already registered")]
344    HostMemoryAlreadyRegistered = 712,
345
346    /// `cudaErrorHostMemoryNotRegistered` (713)
347    #[error("CUDA RT: host memory not registered")]
348    HostMemoryNotRegistered = 713,
349
350    /// `cudaErrorHardwareStackError` (714)
351    #[error("CUDA RT: hardware stack error")]
352    HardwareStackError = 714,
353
354    /// `cudaErrorIllegalInstruction` (715)
355    #[error("CUDA RT: illegal instruction")]
356    IllegalInstruction = 715,
357
358    /// `cudaErrorMisalignedAddress` (716)
359    #[error("CUDA RT: misaligned address")]
360    MisalignedAddress = 716,
361
362    /// `cudaErrorInvalidAddressSpace` (717)
363    #[error("CUDA RT: invalid address space")]
364    InvalidAddressSpace = 717,
365
366    /// `cudaErrorInvalidPc` (718)
367    #[error("CUDA RT: invalid program counter")]
368    InvalidPc = 718,
369
370    /// `cudaErrorLaunchFailure` (719) — exception during kernel execution.
371    #[error("CUDA RT: exception during kernel launch")]
372    LaunchFailure = 719,
373
374    /// `cudaErrorCooperativeLaunchTooLarge` (720)
375    #[error("CUDA RT: cooperative launch too large")]
376    CooperativeLaunchTooLarge = 720,
377
378    /// `cudaErrorNotPermitted` (800)
379    #[error("CUDA RT: not permitted")]
380    NotPermitted = 800,
381
382    /// `cudaErrorNotSupported` (801)
383    #[error("CUDA RT: not supported")]
384    NotSupported = 801,
385
386    /// `cudaErrorSystemNotReady` (802)
387    #[error("CUDA RT: system not ready")]
388    SystemNotReady = 802,
389
390    /// `cudaErrorSystemDriverMismatch` (803)
391    #[error("CUDA RT: system driver mismatch")]
392    SystemDriverMismatch = 803,
393
394    /// `cudaErrorCompatNotSupportedOnDevice` (804)
395    #[error("CUDA RT: compat mode not supported on device")]
396    CompatNotSupportedOnDevice = 804,
397
398    /// `cudaErrorMpsConnectionFailed` (805)
399    #[error("CUDA RT: MPS connection failed")]
400    MpsConnectionFailed = 805,
401
402    /// `cudaErrorMpsRpcFailure` (806)
403    #[error("CUDA RT: MPS RPC failure")]
404    MpsRpcFailure = 806,
405
406    /// `cudaErrorMpsServerNotReady` (807)
407    #[error("CUDA RT: MPS server not ready")]
408    MpsServerNotReady = 807,
409
410    /// `cudaErrorMpsMaxClientsReached` (808)
411    #[error("CUDA RT: MPS max clients reached")]
412    MpsMaxClientsReached = 808,
413
414    /// `cudaErrorMpsMaxConnectionsReached` (809)
415    #[error("CUDA RT: MPS max connections reached")]
416    MpsMaxConnectionsReached = 809,
417
418    /// `cudaErrorMpsClientTerminated` (810)
419    #[error("CUDA RT: MPS client terminated")]
420    MpsClientTerminated = 810,
421
422    /// `cudaErrorCdpNotSupported` (811)
423    #[error("CUDA RT: CDP not supported")]
424    CdpNotSupported = 811,
425
426    /// `cudaErrorCdpVersionMismatch` (812)
427    #[error("CUDA RT: CDP version mismatch")]
428    CdpVersionMismatch = 812,
429
430    /// `cudaErrorStreamCaptureUnsupported` (900)
431    #[error("CUDA RT: stream capture unsupported")]
432    StreamCaptureUnsupported = 900,
433
434    /// `cudaErrorStreamCaptureInvalidated` (901)
435    #[error("CUDA RT: stream capture invalidated")]
436    StreamCaptureInvalidated = 901,
437
438    /// `cudaErrorStreamCaptureMerge` (902)
439    #[error("CUDA RT: stream capture merge failed")]
440    StreamCaptureMerge = 902,
441
442    /// `cudaErrorStreamCaptureUnmatched` (903)
443    #[error("CUDA RT: stream capture unmatched")]
444    StreamCaptureUnmatched = 903,
445
446    /// `cudaErrorStreamCaptureUnjoined` (904)
447    #[error("CUDA RT: stream capture unjoined")]
448    StreamCaptureUnjoined = 904,
449
450    /// `cudaErrorStreamCaptureIsolation` (905)
451    #[error("CUDA RT: stream capture isolation")]
452    StreamCaptureIsolation = 905,
453
454    /// `cudaErrorStreamCaptureImplicit` (906)
455    #[error("CUDA RT: stream capture implicit")]
456    StreamCaptureImplicit = 906,
457
458    /// `cudaErrorCapturedEvent` (907)
459    #[error("CUDA RT: captured event")]
460    CapturedEvent = 907,
461
462    /// `cudaErrorStreamCaptureWrongThread` (908)
463    #[error("CUDA RT: stream capture wrong thread")]
464    StreamCaptureWrongThread = 908,
465
466    /// `cudaErrorTimeout` (909)
467    #[error("CUDA RT: timeout")]
468    Timeout = 909,
469
470    /// `cudaErrorGraphExecUpdateFailure` (910)
471    #[error("CUDA RT: CUDA graph exec update failure")]
472    GraphExecUpdateFailure = 910,
473
474    /// `cudaErrorExternalDevice` (911)
475    #[error("CUDA RT: external device error")]
476    ExternalDevice = 911,
477
478    /// `cudaErrorInvalidClusterSize` (912)
479    #[error("CUDA RT: invalid cluster size")]
480    InvalidClusterSize = 912,
481
482    /// `cudaErrorFunctionNotLoaded` (913)
483    #[error("CUDA RT: function not loaded")]
484    FunctionNotLoaded = 913,
485
486    /// `cudaErrorInvalidResourceType` (914)
487    #[error("CUDA RT: invalid resource type")]
488    InvalidResourceType = 914,
489
490    /// `cudaErrorInvalidResourceConfiguration` (915)
491    #[error("CUDA RT: invalid resource configuration")]
492    InvalidResourceConfiguration = 915,
493
494    /// `cudaErrorUnknown` (999) — unknown error.
495    #[error("CUDA RT: unknown error")]
496    Unknown = 999,
497
498    /// Driver could not be loaded at runtime (libcuda.so not found).
499    #[error("CUDA RT: CUDA driver not available")]
500    DriverNotAvailable,
501
502    /// No GPU available (driver loaded but 0 CUDA devices).
503    #[error("CUDA RT: no GPU device available")]
504    NoGpu,
505
506    /// Runtime context not initialised (call cudaSetDevice first).
507    #[error("CUDA RT: device not set — call cudaSetDevice before using runtime API")]
508    DeviceNotSet,
509}
510
511/// Convenience alias for `Result<T, CudaRtError>`.
512pub type CudaRtResult<T> = Result<T, CudaRtError>;
513
514impl CudaRtError {
515    /// Convert a raw `cudaError_t` integer to [`CudaRtError`].
516    ///
517    /// Returns `Ok(())` for `cudaSuccess` (0) and maps all other values.
518    #[must_use]
519    pub fn from_code(code: u32) -> Option<Self> {
520        match code {
521            0 => None, // cudaSuccess
522            1 => Some(Self::InvalidValue),
523            2 => Some(Self::MemoryAllocation),
524            3 => Some(Self::InitializationError),
525            4 => Some(Self::CudartUnloading),
526            5 => Some(Self::ProfilerDisabled),
527            9 => Some(Self::InvalidConfiguration),
528            12 => Some(Self::InvalidPitchValue),
529            13 => Some(Self::InvalidSymbol),
530            16 => Some(Self::InvalidHostPointer),
531            17 => Some(Self::InvalidDevicePointer),
532            18 => Some(Self::InvalidTexture),
533            19 => Some(Self::InvalidTextureBinding),
534            20 => Some(Self::InvalidChannelDescriptor),
535            21 => Some(Self::InvalidMemcpyDirection),
536            26 => Some(Self::InvalidFilterSetting),
537            27 => Some(Self::InvalidNormSetting),
538            34 => Some(Self::StubLibrary),
539            35 => Some(Self::InsufficientDriver),
540            36 => Some(Self::CallRequiresNewerDriver),
541            37 => Some(Self::InvalidSurface),
542            43 => Some(Self::DuplicateVariableName),
543            44 => Some(Self::DuplicateTextureName),
544            45 => Some(Self::DuplicateSurfaceName),
545            46 => Some(Self::DevicesUnavailable),
546            49 => Some(Self::IncompatibleDriverContext),
547            52 => Some(Self::MissingConfiguration),
548            65 => Some(Self::LaunchMaxDepthExceeded),
549            66 => Some(Self::LaunchFileScopedTex),
550            67 => Some(Self::LaunchFileScopedSurf),
551            68 => Some(Self::SyncDepthExceeded),
552            69 => Some(Self::LaunchPendingCountExceeded),
553            98 => Some(Self::InvalidDeviceFunction),
554            100 => Some(Self::NoDevice),
555            101 => Some(Self::InvalidDevice),
556            102 => Some(Self::DeviceNotLicensed),
557            103 => Some(Self::SoftwareValidityNotEstablished),
558            127 => Some(Self::StartupFailure),
559            200 => Some(Self::InvalidKernelImage),
560            201 => Some(Self::DeviceUninitialized),
561            205 => Some(Self::MapBufferObjectFailed),
562            206 => Some(Self::UnmapBufferObjectFailed),
563            207 => Some(Self::ArrayIsMapped),
564            208 => Some(Self::AlreadyMapped),
565            209 => Some(Self::NoKernelImageForDevice),
566            210 => Some(Self::AlreadyAcquired),
567            211 => Some(Self::NotMapped),
568            212 => Some(Self::NotMappedAsArray),
569            213 => Some(Self::NotMappedAsPointer),
570            214 => Some(Self::EccUncorrectable),
571            215 => Some(Self::UnsupportedLimit),
572            216 => Some(Self::DeviceAlreadyInUse),
573            217 => Some(Self::PeerAccessUnsupported),
574            218 => Some(Self::InvalidPtx),
575            219 => Some(Self::InvalidGraphicsContext),
576            220 => Some(Self::NvlinkUncorrectable),
577            221 => Some(Self::JitCompilerNotFound),
578            222 => Some(Self::UnsupportedPtxVersion),
579            223 => Some(Self::JitCompilationDisabled),
580            224 => Some(Self::UnsupportedExecAffinity),
581            225 => Some(Self::UnsupportedDevSideSync),
582            300 => Some(Self::InvalidSource),
583            301 => Some(Self::FileNotFound),
584            302 => Some(Self::SharedObjectSymbolNotFound),
585            303 => Some(Self::SharedObjectInitFailed),
586            304 => Some(Self::OperatingSystem),
587            400 => Some(Self::InvalidResourceHandle),
588            401 => Some(Self::IllegalState),
589            402 => Some(Self::LostConnection),
590            500 => Some(Self::SymbolNotFound),
591            600 => Some(Self::NotReady),
592            700 => Some(Self::IllegalAddress),
593            701 => Some(Self::LaunchOutOfResources),
594            702 => Some(Self::LaunchTimeout),
595            703 => Some(Self::LaunchIncompatibleTexturing),
596            704 => Some(Self::PeerAccessAlreadyEnabled),
597            705 => Some(Self::PeerAccessNotEnabled),
598            708 => Some(Self::SetOnActiveProcess),
599            709 => Some(Self::ContextIsDestroyed),
600            710 => Some(Self::Assert),
601            711 => Some(Self::TooManyPeers),
602            712 => Some(Self::HostMemoryAlreadyRegistered),
603            713 => Some(Self::HostMemoryNotRegistered),
604            714 => Some(Self::HardwareStackError),
605            715 => Some(Self::IllegalInstruction),
606            716 => Some(Self::MisalignedAddress),
607            717 => Some(Self::InvalidAddressSpace),
608            718 => Some(Self::InvalidPc),
609            719 => Some(Self::LaunchFailure),
610            720 => Some(Self::CooperativeLaunchTooLarge),
611            800 => Some(Self::NotPermitted),
612            801 => Some(Self::NotSupported),
613            802 => Some(Self::SystemNotReady),
614            803 => Some(Self::SystemDriverMismatch),
615            804 => Some(Self::CompatNotSupportedOnDevice),
616            805 => Some(Self::MpsConnectionFailed),
617            806 => Some(Self::MpsRpcFailure),
618            807 => Some(Self::MpsServerNotReady),
619            808 => Some(Self::MpsMaxClientsReached),
620            809 => Some(Self::MpsMaxConnectionsReached),
621            810 => Some(Self::MpsClientTerminated),
622            811 => Some(Self::CdpNotSupported),
623            812 => Some(Self::CdpVersionMismatch),
624            900 => Some(Self::StreamCaptureUnsupported),
625            901 => Some(Self::StreamCaptureInvalidated),
626            902 => Some(Self::StreamCaptureMerge),
627            903 => Some(Self::StreamCaptureUnmatched),
628            904 => Some(Self::StreamCaptureUnjoined),
629            905 => Some(Self::StreamCaptureIsolation),
630            906 => Some(Self::StreamCaptureImplicit),
631            907 => Some(Self::CapturedEvent),
632            908 => Some(Self::StreamCaptureWrongThread),
633            909 => Some(Self::Timeout),
634            910 => Some(Self::GraphExecUpdateFailure),
635            911 => Some(Self::ExternalDevice),
636            912 => Some(Self::InvalidClusterSize),
637            913 => Some(Self::FunctionNotLoaded),
638            914 => Some(Self::InvalidResourceType),
639            915 => Some(Self::InvalidResourceConfiguration),
640            _ => Some(Self::Unknown),
641        }
642    }
643
644    /// Return `true` if the error is transient (e.g. `NotReady`).
645    #[must_use]
646    pub fn is_transient(self) -> bool {
647        matches!(self, Self::NotReady)
648    }
649
650    /// Return `true` if the error indicates no CUDA hardware is present.
651    #[must_use]
652    pub fn is_no_device(self) -> bool {
653        matches!(self, Self::NoDevice | Self::NoGpu | Self::DeviceNotSet)
654    }
655}
656
657/// Convert a `CudaError` (driver error) to `CudaRtError`.
658impl From<oxicuda_driver::error::CudaError> for CudaRtError {
659    fn from(e: oxicuda_driver::error::CudaError) -> Self {
660        // Map the most common driver errors to their runtime equivalents.
661        use oxicuda_driver::error::CudaError as D;
662        match e {
663            D::InvalidValue => Self::InvalidValue,
664            D::OutOfMemory => Self::MemoryAllocation,
665            D::NotInitialized => Self::InitializationError,
666            D::Deinitialized => Self::CudartUnloading,
667            D::ProfilerDisabled => Self::ProfilerDisabled,
668            D::StubLibrary => Self::StubLibrary,
669            D::DeviceUnavailable => Self::DevicesUnavailable,
670            D::NoDevice => Self::NoDevice,
671            D::InvalidDevice => Self::InvalidDevice,
672            D::InvalidImage => Self::InvalidKernelImage,
673            D::NotReady => Self::NotReady,
674            D::IllegalAddress => Self::IllegalAddress,
675            D::LaunchOutOfResources => Self::LaunchOutOfResources,
676            D::LaunchTimeout => Self::LaunchTimeout,
677            D::LaunchFailed => Self::LaunchFailure,
678            D::NotPermitted => Self::NotPermitted,
679            D::NotSupported => Self::NotSupported,
680            D::Unknown(_) => Self::Unknown,
681            _ => Self::Unknown,
682        }
683    }
684}
685
686// =========================================================================
687// Tests
688// =========================================================================
689
690#[cfg(test)]
691mod tests {
692    use super::*;
693
694    #[test]
695    fn from_code_success_returns_none() {
696        assert!(CudaRtError::from_code(0).is_none());
697    }
698
699    #[test]
700    fn from_code_known_errors() {
701        assert_eq!(CudaRtError::from_code(1), Some(CudaRtError::InvalidValue));
702        assert_eq!(
703            CudaRtError::from_code(2),
704            Some(CudaRtError::MemoryAllocation)
705        );
706        assert_eq!(CudaRtError::from_code(100), Some(CudaRtError::NoDevice));
707        assert_eq!(
708            CudaRtError::from_code(719),
709            Some(CudaRtError::LaunchFailure)
710        );
711        assert_eq!(CudaRtError::from_code(999), Some(CudaRtError::Unknown));
712    }
713
714    #[test]
715    fn from_code_unrecognised_becomes_unknown() {
716        assert_eq!(CudaRtError::from_code(12345), Some(CudaRtError::Unknown));
717    }
718
719    #[test]
720    fn is_transient_only_for_not_ready() {
721        assert!(CudaRtError::NotReady.is_transient());
722        assert!(!CudaRtError::LaunchFailure.is_transient());
723    }
724
725    #[test]
726    fn is_no_device_variants() {
727        assert!(CudaRtError::NoDevice.is_no_device());
728        assert!(CudaRtError::NoGpu.is_no_device());
729        assert!(CudaRtError::DeviceNotSet.is_no_device());
730        assert!(!CudaRtError::InvalidValue.is_no_device());
731    }
732
733    #[test]
734    fn error_display() {
735        let e = CudaRtError::MemoryAllocation;
736        assert!(e.to_string().contains("out of device memory"));
737    }
738
739    #[test]
740    fn from_driver_error() {
741        let rt: CudaRtError = oxicuda_driver::error::CudaError::OutOfMemory.into();
742        assert_eq!(rt, CudaRtError::MemoryAllocation);
743    }
744}