oxicuda_backend/
backend_kind.rs1use std::fmt;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
16pub enum BackendKind {
17 Cuda,
19 Rocm,
21 LevelZero,
23 Vulkan,
25 Metal,
27 WebGpu,
29 Cpu,
31}
32
33impl BackendKind {
34 pub const ALL: [BackendKind; 7] = [
36 BackendKind::Cuda,
37 BackendKind::Rocm,
38 BackendKind::LevelZero,
39 BackendKind::Vulkan,
40 BackendKind::Metal,
41 BackendKind::WebGpu,
42 BackendKind::Cpu,
43 ];
44
45 #[must_use]
49 pub const fn as_str(self) -> &'static str {
50 match self {
51 Self::Cuda => "cuda",
52 Self::Rocm => "rocm",
53 Self::LevelZero => "level_zero",
54 Self::Vulkan => "vulkan",
55 Self::Metal => "metal",
56 Self::WebGpu => "webgpu",
57 Self::Cpu => "cpu",
58 }
59 }
60
61 #[must_use]
68 pub const fn default_priority(self) -> u32 {
69 match self {
70 Self::Cuda => 100,
71 Self::Rocm => 90,
72 Self::Metal => 85,
73 Self::LevelZero => 80,
74 Self::Vulkan => 60,
75 Self::WebGpu => 50,
76 Self::Cpu => 1,
77 }
78 }
79
80 #[must_use]
83 pub const fn is_gpu(self) -> bool {
84 !matches!(self, Self::Cpu)
85 }
86
87 #[must_use]
90 pub fn from_name(name: &str) -> Option<Self> {
91 match name.trim().to_ascii_lowercase().as_str() {
92 "cuda" | "nvidia" => Some(Self::Cuda),
93 "rocm" | "hip" | "amd" => Some(Self::Rocm),
94 "level_zero" | "levelzero" | "l0" | "intel" => Some(Self::LevelZero),
95 "vulkan" | "vk" => Some(Self::Vulkan),
96 "metal" | "mtl" | "apple" => Some(Self::Metal),
97 "webgpu" | "wgpu" => Some(Self::WebGpu),
98 "cpu" | "host" | "reference" => Some(Self::Cpu),
99 _ => None,
100 }
101 }
102}
103
104impl fmt::Display for BackendKind {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 f.write_str(self.as_str())
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113 use std::collections::HashSet;
114
115 #[test]
116 fn all_covers_every_variant_uniquely() {
117 let set: HashSet<_> = BackendKind::ALL.iter().copied().collect();
118 assert_eq!(set.len(), 7);
119 assert!(set.contains(&BackendKind::Cpu));
121 assert!(set.contains(&BackendKind::Cuda));
122 assert!(set.contains(&BackendKind::Metal));
123 }
124
125 #[test]
126 fn cpu_is_global_minimum_priority() {
127 let cpu = BackendKind::Cpu.default_priority();
128 for k in BackendKind::ALL {
129 if k != BackendKind::Cpu {
130 assert!(
131 k.default_priority() > cpu,
132 "{k} must outrank the CPU fallback"
133 );
134 }
135 }
136 }
137
138 #[test]
139 fn cuda_is_global_maximum_priority() {
140 let cuda = BackendKind::Cuda.default_priority();
141 for k in BackendKind::ALL {
142 if k != BackendKind::Cuda {
143 assert!(cuda >= k.default_priority());
144 }
145 }
146 }
147
148 #[test]
149 fn priority_ordering_is_strict_per_pair() {
150 assert!(BackendKind::Rocm.default_priority() > BackendKind::Vulkan.default_priority());
152 assert!(BackendKind::Metal.default_priority() > BackendKind::WebGpu.default_priority());
153 assert!(BackendKind::LevelZero.default_priority() > BackendKind::Vulkan.default_priority());
154 }
155
156 #[test]
157 fn is_gpu_is_true_for_all_but_cpu() {
158 for k in BackendKind::ALL {
159 assert_eq!(k.is_gpu(), k != BackendKind::Cpu);
160 }
161 }
162
163 #[test]
164 fn name_round_trips() {
165 for k in BackendKind::ALL {
166 assert_eq!(BackendKind::from_name(k.as_str()), Some(k));
167 }
168 }
169
170 #[test]
171 fn name_aliases_and_case() {
172 assert_eq!(BackendKind::from_name("HIP"), Some(BackendKind::Rocm));
173 assert_eq!(BackendKind::from_name(" L0 "), Some(BackendKind::LevelZero));
174 assert_eq!(BackendKind::from_name("WGPU"), Some(BackendKind::WebGpu));
175 assert_eq!(BackendKind::from_name("Host"), Some(BackendKind::Cpu));
176 assert_eq!(BackendKind::from_name("nvidia"), Some(BackendKind::Cuda));
177 assert_eq!(BackendKind::from_name("opencl"), None);
178 }
179
180 #[test]
181 fn display_matches_as_str() {
182 assert_eq!(BackendKind::LevelZero.to_string(), "level_zero");
183 assert_eq!(BackendKind::Cpu.to_string(), "cpu");
184 }
185}