use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};
static NEXT_SHADER_PROGRAM_ID: AtomicU64 = AtomicU64::new(1);
#[derive(Clone, Debug)]
pub struct ShaderProgram {
id: u64,
source: Arc<str>,
}
impl ShaderProgram {
pub fn new(wgsl: impl Into<Arc<str>>) -> Self {
let id = NEXT_SHADER_PROGRAM_ID.fetch_add(1, Ordering::Relaxed);
Self {
id,
source: wgsl.into(),
}
}
pub fn id(&self) -> u64 {
self.id
}
pub fn source(&self) -> &str {
&self.source
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_mints_unique_ids() {
let a = ShaderProgram::new("fn a() {}");
let b = ShaderProgram::new("fn b() {}");
assert_ne!(a.id(), b.id());
}
#[test]
fn new_mints_unique_ids_across_threads() {
let handles: Vec<_> = (0..8)
.map(|i| std::thread::spawn(move || ShaderProgram::new(format!("fn s{i}() {{}}")).id()))
.collect();
let mut ids: Vec<u64> = handles.into_iter().map(|h| h.join().unwrap()).collect();
ids.sort_unstable();
ids.dedup();
assert_eq!(ids.len(), 8, "all ids must be unique across threads");
}
#[test]
fn clone_shares_id() {
let a = ShaderProgram::new("fn a() {}");
let b = a.clone();
assert_eq!(a.id(), b.id());
}
#[test]
fn source_round_trips() {
let program = ShaderProgram::new("fn main() {}");
assert_eq!(program.source(), "fn main() {}");
}
}