Skip to main content

voxora_engine/
backend.rs

1//! Hardware backend descriptor shared across engine adapters.
2
3use std::fmt;
4
5/// Compile-time hardware backend the engine was built against.
6///
7/// Engines can ship multiple backends as separate Cargo features
8/// (`cpu` / `cuda` / `metal` / `vulkan`); this enum captures which
9/// one was selected at runtime via `BackendDescriptor`.
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
11#[non_exhaustive]
12pub enum BackendKind {
13    /// Pure CPU execution.
14    Cpu,
15    /// NVIDIA CUDA (requires `cuda` feature on the engine).
16    Cuda,
17    /// Apple Metal (requires `metal` feature on the engine).
18    Metal,
19    /// Vulkan compute (requires `vulkan` feature on the engine).
20    Vulkan,
21}
22
23impl BackendKind {
24    /// Canonical config spelling.
25    pub fn as_config(self) -> &'static str {
26        match self {
27            Self::Cpu => "cpu",
28            Self::Cuda => "cuda",
29            Self::Metal => "metal",
30            Self::Vulkan => "vulkan",
31        }
32    }
33
34    /// Parse the canonical config spelling. Case-insensitive;
35    /// returns `None` for unknown values so callers can render their
36    /// own diagnostic message.
37    pub fn from_config(value: &str) -> Option<Self> {
38        match value.to_ascii_lowercase().as_str() {
39            "cpu" => Some(Self::Cpu),
40            "cuda" => Some(Self::Cuda),
41            "metal" => Some(Self::Metal),
42            "vulkan" => Some(Self::Vulkan),
43            _ => None,
44        }
45    }
46}
47
48impl fmt::Display for BackendKind {
49    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50        f.write_str(self.as_config())
51    }
52}
53
54/// Concrete backend a particular engine instance was loaded with.
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56#[non_exhaustive]
57pub struct BackendDescriptor {
58    /// Backend kind the engine was loaded against.
59    pub kind: BackendKind,
60}
61
62impl BackendDescriptor {
63    /// The CPU descriptor — most common, useful as a default.
64    pub const CPU: Self = Self {
65        kind: BackendKind::Cpu,
66    };
67
68    /// Build a descriptor for an arbitrary backend kind.
69    pub fn new(kind: BackendKind) -> Self {
70        Self { kind }
71    }
72}
73
74#[cfg(test)]
75mod tests {
76    use super::*;
77
78    #[test]
79    fn roundtrip() {
80        for k in [
81            BackendKind::Cpu,
82            BackendKind::Cuda,
83            BackendKind::Metal,
84            BackendKind::Vulkan,
85        ] {
86            assert_eq!(BackendKind::from_config(k.as_config()), Some(k));
87        }
88    }
89
90    #[test]
91    fn rejects_unknown() {
92        assert_eq!(BackendKind::from_config("webgpu"), None);
93        assert_eq!(BackendKind::from_config(""), None);
94    }
95
96    #[test]
97    fn is_case_insensitive() {
98        assert_eq!(BackendKind::from_config("CUDA"), Some(BackendKind::Cuda));
99    }
100
101    #[test]
102    fn cpu_descriptor_is_const() {
103        let d = BackendDescriptor::CPU;
104        assert_eq!(d.kind, BackendKind::Cpu);
105    }
106}