concinnity_core/platform.rs
1//! The shader `Platform` selector: which shader source language the running
2//! backend consumes. Pure (no I/O, cfg-resolved), so it sits in the runtime
3//! foundation rather than the build module -- the engine picks a `Shader` stage's
4//! current-platform source at runtime, and the build pipeline reuses the same
5//! selection at compile time.
6
7/// Shader source language families supported by the engine. Each variant
8/// matches one render backend: Metal, HLSL (DirectX), or GLSL (Vulkan).
9///
10/// A given build only ever constructs the variant for its own backend (see
11/// `current`), so the other two read as never-constructed; `key` still matches
12/// all three, so the type stays whole.
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum Platform {
15 /// Metal Shading Language, for the Metal backend.
16 Metal,
17 /// HLSL, for the DirectX backend.
18 Hlsl,
19 /// GLSL, for the Vulkan backend.
20 Glsl,
21}
22
23impl Platform {
24 /// The shader platform the current binary's rendering backend was built
25 /// for. Resolved from the backend cfg (see build.rs), not the target OS, so
26 /// a Windows Vulkan build correctly selects GLSL rather than HLSL.
27 pub fn current() -> Self {
28 #[cfg(backend_metal)]
29 {
30 Platform::Metal
31 }
32 #[cfg(backend_dx)]
33 {
34 Platform::Hlsl
35 }
36 #[cfg(backend_vk)]
37 {
38 Platform::Glsl
39 }
40 }
41
42 /// String key used in the `sources` map of a `Shader` stage.
43 pub fn key(self) -> &'static str {
44 match self {
45 Platform::Metal => "metal",
46 Platform::Hlsl => "hlsl",
47 Platform::Glsl => "glsl",
48 }
49 }
50
51 /// Whether a shader source with the given file extension is usable on this
52 /// platform. The matching extension (`metal` / `hlsl` / `glsl`) is accepted;
53 /// a non-matching shader extension is rejected so a single-path source
54 /// authored for one backend doesn't get fed to another; an unknown
55 /// extension is accepted by default (the build step surfaces a real compile
56 /// error later if the file truly can't be built).
57 ///
58 /// Shared by the per-platform source selection of `Shader` stages and
59 /// `SdfVolume` so both apply identical fallback rules.
60 pub fn accepts_ext(self, ext: &str) -> bool {
61 !matches!(ext, "metal" | "hlsl" | "glsl") || ext == self.key()
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 #[test]
70 fn platform_key_and_accepts_ext_cover_all_variants() {
71 assert_eq!(Platform::Metal.key(), "metal");
72 assert_eq!(Platform::Hlsl.key(), "hlsl");
73 assert_eq!(Platform::Glsl.key(), "glsl");
74
75 // The matching extension is accepted; another backend's shader
76 // extension is rejected; an unknown extension is accepted by default.
77 assert!(Platform::Metal.accepts_ext("metal"));
78 assert!(!Platform::Metal.accepts_ext("hlsl"));
79 assert!(!Platform::Metal.accepts_ext("glsl"));
80 assert!(Platform::Hlsl.accepts_ext("hlsl"));
81 assert!(!Platform::Hlsl.accepts_ext("metal"));
82 assert!(Platform::Glsl.accepts_ext("glsl"));
83 assert!(!Platform::Glsl.accepts_ext("hlsl"));
84 assert!(Platform::Metal.accepts_ext("txt"));
85 }
86}