use super::*;
use core::any::Any;
use rustc_hash::FxHashMap;
#[derive(Default)]
pub(crate) struct LifecycleState {
pub(crate) current_frame_retain: Vec<Retain>,
pub(crate) previous_frame_retain: Vec<Retain>,
pub(crate) signal_watches: SignalWatchRegistry,
}
#[derive(Default)]
pub(crate) struct SignalWatchRegistry {
entries: FxHashMap<usize, SignalWatchEntry>,
generation: u64,
}
struct SignalWatchEntry {
_signal: Box<dyn Any>,
signal_type: core::any::TypeId,
_guard: Retain,
last_seen: u64,
}
impl SignalWatchRegistry {
fn begin_frame(&mut self) {
self.generation = self
.generation
.checked_add(1)
.expect("hydrolysis renderer: signal watch generation overflow");
}
fn finish_frame(&mut self) {
let generation = self.generation;
self.entries
.retain(|_, entry| entry.last_seen == generation);
}
pub(crate) fn mark_seen(&mut self, identity: usize, signal_type: core::any::TypeId) -> bool {
self.entries.get_mut(&identity).is_some_and(|entry| {
assert!(
entry.signal_type == signal_type,
"hydrolysis renderer: signal identity {identity:#x} is shared by two different signal types (derived-identity hash collision)"
);
entry.last_seen = self.generation;
true
})
}
pub(crate) fn insert(
&mut self,
identity: usize,
signal_type: core::any::TypeId,
signal: Box<dyn Any>,
guard: Retain,
) {
self.entries.insert(
identity,
SignalWatchEntry {
_signal: signal,
signal_type,
_guard: guard,
last_seen: self.generation,
},
);
}
}
pub(crate) struct DeferredLifeCycleHook {
pub(crate) env: Environment,
pub(crate) hook: LifeCycleHook,
}
impl LifecycleState {
pub(crate) fn begin_rebuild_frame(&mut self) {
self.previous_frame_retain.clear();
self.current_frame_retain.clear();
self.signal_watches.begin_frame();
}
pub(crate) fn finish_rebuild_frame(&mut self) {
self.previous_frame_retain = core::mem::take(&mut self.current_frame_retain);
self.signal_watches.finish_frame();
}
}
impl DeferredLifeCycleHook {
pub(crate) fn new(hook: LifeCycleHook, env: Environment) -> Self {
Self { env, hook }
}
pub(crate) fn call(self) {
self.hook.handle(&self.env);
}
}