pub(crate) fn assemble(
hot_reload: bool,
file: &str,
defines: &[(&str, &str)],
splices: &[(&str, &str)],
) -> String {
let resolve = |f: &str| hot_reload.then(|| from_checkout(f)).flatten();
concinnity_core::render::slang_source::assemble_with_splices(file, defines, resolve, splices)
}
pub(crate) fn from_checkout(file: &str) -> Option<&'static str> {
let path = format!(
"{}/../concinnity-core/src/render/shaders/{}",
env!("CARGO_MANIFEST_DIR"),
file
);
match std::fs::read_to_string(&path) {
Ok(text) => Some(Box::leak(text.into_boxed_str())),
Err(e) => {
tracing::debug!("hot-reload: falling back to embedded {file} ({e})");
None
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_embedded_body_is_assembled_with_defines_leading() {
let src = assemble(false, "fog.slang", &[("A", "1")], &[]);
assert!(src.starts_with("#define A 1\n"));
assert!(!src.contains("{POST_COMMON}"));
}
#[test]
fn a_missing_hot_reload_file_falls_back_to_embedded() {
assert_eq!(
assemble(true, "definitely_not_a_shader.slang", &[("A", "1")], &[]),
"#define A 1\n"
);
}
#[test]
fn hot_reload_matches_the_embedded_assembly_for_an_unedited_shader() {
assert_eq!(
assemble(true, "fog.slang", &[("A", "1")], &[]),
assemble(false, "fog.slang", &[("A", "1")], &[])
);
}
}