ursus_materials/
strategy.rs1use crate::error::MaterialError;
2use crate::field::FieldDesc;
3use crate::material::Material;
4use crate::requirements::Requirements;
5use crate::value::MaterialValue;
6use std::collections::HashMap;
7use std::sync::Arc;
8
9pub trait ShadingStrategy: Send + Sync {
19 fn name(&self) -> &'static str;
22
23 fn requirements(&self) -> &Requirements;
25
26 fn fields(&self) -> &[FieldDesc];
29
30 fn resolve(&self, material: &Material) -> Result<Vec<MaterialValue>, MaterialError>;
33
34 fn validate(&self, material: &Material) -> Result<(), MaterialError> {
36 self.requirements().validate(material, self.name())
37 }
38}
39
40#[derive(Default)]
42pub struct StrategyRegistry {
43 by_name: HashMap<&'static str, Arc<dyn ShadingStrategy>>,
44}
45
46impl StrategyRegistry {
47 pub fn register(&mut self, strategy: impl ShadingStrategy + 'static) {
48 let name = strategy.name();
49 if self.by_name.insert(name, Arc::new(strategy)).is_some() {
50 log::warn!("StrategyRegistry: strategy '{name}' was already registered, overwriting");
51 }
52 }
53
54 pub fn by_name(&self, name: &str) -> Option<Arc<dyn ShadingStrategy>> {
55 self.by_name.get(name).cloned()
56 }
57
58 pub fn resolve(&self, material: &Material) -> Result<Vec<MaterialValue>, MaterialError> {
61 let strategy = self
62 .by_name(material.strategy)
63 .ok_or_else(|| MaterialError::UnknownStrategy(material.strategy.to_string()))?;
64 strategy.validate(material)?;
65 strategy.resolve(material)
66 }
67}