Skip to main content

steel_core/behavior/
fluid.rs

1//! Fluid behavior registry.
2
3use std::ops::Deref;
4use std::sync::OnceLock;
5
6use steel_registry::fluid::FluidRef;
7use steel_registry::{REGISTRY, RegistryEntry, RegistryExt};
8
9use crate::fluid::{EmptyFluid, FluidBehavior};
10
11/// Wrapper for the global fluid behavior registry that implements `Deref`.
12pub struct FluidBehaviorLock(pub OnceLock<FluidBehaviorRegistry>);
13
14impl Deref for FluidBehaviorLock {
15    type Target = FluidBehaviorRegistry;
16
17    fn deref(&self) -> &Self::Target {
18        self.0.get().expect("Fluid behaviors not initialized")
19    }
20}
21
22/// Global fluid behavior registry.
23///
24/// Access behaviors directly via deref: `FLUID_BEHAVIORS.get_behavior(fluid)`
25pub static FLUID_BEHAVIORS: FluidBehaviorLock = FluidBehaviorLock(OnceLock::new());
26
27/// Registry for fluid behaviors.
28///
29/// Created after the main registry is frozen. All fluids are initialized with
30/// default behavior ([`EmptyFluid`]), then custom behaviors are registered.
31pub struct FluidBehaviorRegistry {
32    behaviors: Vec<Box<dyn FluidBehavior>>,
33}
34
35impl FluidBehaviorRegistry {
36    /// Creates a new behavior registry with default behaviors for all fluids.
37    #[must_use]
38    pub fn new() -> Self {
39        let fluid_count = REGISTRY.fluids.len();
40        let mut behaviors: Vec<Box<dyn FluidBehavior>> = Vec::with_capacity(fluid_count);
41
42        // Initialize all fluids with default behavior (EmptyFluid)
43        for _ in 0..fluid_count {
44            behaviors.push(Box::new(EmptyFluid));
45        }
46
47        Self { behaviors }
48    }
49
50    /// Sets a custom behavior for a fluid.
51    ///
52    /// # Panics
53    /// Panics if `fluid` is not registered in the global registry.
54    pub fn set_behavior(&mut self, fluid: FluidRef, behavior: Box<dyn FluidBehavior>) {
55        let id = fluid.id();
56        self.behaviors[id] = behavior;
57    }
58
59    /// Gets the behavior for a fluid.
60    ///
61    /// # Panics
62    /// Panics if `fluid` is not registered in the global registry.
63    #[must_use]
64    pub fn get_behavior(&self, fluid: FluidRef) -> &dyn FluidBehavior {
65        let id = fluid.id();
66        self.behaviors[id].as_ref()
67    }
68}
69
70impl Default for FluidBehaviorRegistry {
71    fn default() -> Self {
72        Self::new()
73    }
74}