use std::any::Any;
use std::collections::HashMap;
use crate::core::NodeKey;
use crate::hooks::context::HookContext;
pub struct ComponentInstance {
component: Box<dyn Any + Send>,
pub hook_context: HookContext,
pub used: bool,
}
impl ComponentInstance {
pub fn new<C: Any + Send + 'static>(component: C) -> Self {
Self {
component: Box::new(component),
hook_context: HookContext::new(),
used: false,
}
}
pub fn get<C: 'static>(&self) -> Option<&C> {
self.component.downcast_ref::<C>()
}
pub fn get_mut<C: 'static>(&mut self) -> Option<&mut C> {
self.component.downcast_mut::<C>()
}
pub fn mark_used(&mut self) {
self.used = true;
}
pub fn reset_used(&mut self) {
self.used = false;
}
}
pub struct ComponentRegistry {
instances: HashMap<NodeKey, ComponentInstance>,
pending_cleanup: Vec<NodeKey>,
}
impl ComponentRegistry {
pub fn new() -> Self {
Self {
instances: HashMap::new(),
pending_cleanup: Vec::new(),
}
}
pub fn get_or_create<C, F>(&mut self, key: NodeKey, factory: F) -> &mut ComponentInstance
where
C: Any + Send + 'static,
F: FnOnce() -> C,
{
self.instances.entry(key).or_insert_with(|| {
let component = factory();
ComponentInstance::new(component)
})
}
pub fn get(&self, key: &NodeKey) -> Option<&ComponentInstance> {
self.instances.get(key)
}
pub fn get_mut(&mut self, key: &NodeKey) -> Option<&mut ComponentInstance> {
self.instances.get_mut(key)
}
pub fn contains(&self, key: &NodeKey) -> bool {
self.instances.contains_key(key)
}
pub fn begin_render(&mut self) {
for instance in self.instances.values_mut() {
instance.reset_used();
}
self.pending_cleanup.clear();
}
pub fn end_render(&mut self) {
for (key, instance) in &self.instances {
if !instance.used {
self.pending_cleanup.push(*key);
}
}
}
pub fn cleanup(&mut self) {
for key in self.pending_cleanup.drain(..) {
if let Some(mut instance) = self.instances.remove(&key) {
instance.hook_context.run_effects();
}
}
}
pub fn remove(&mut self, key: &NodeKey) -> Option<ComponentInstance> {
self.instances.remove(key)
}
pub fn len(&self) -> usize {
self.instances.len()
}
pub fn is_empty(&self) -> bool {
self.instances.is_empty()
}
pub fn clear(&mut self) {
for (_, mut instance) in self.instances.drain() {
instance.hook_context.run_effects();
}
self.pending_cleanup.clear();
}
pub fn keys(&self) -> impl Iterator<Item = &NodeKey> {
self.instances.keys()
}
pub fn iter(&self) -> impl Iterator<Item = (&NodeKey, &ComponentInstance)> {
self.instances.iter()
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&NodeKey, &mut ComponentInstance)> {
self.instances.iter_mut()
}
}
impl Default for ComponentRegistry {
fn default() -> Self {
Self::new()
}
}
impl Drop for ComponentRegistry {
fn drop(&mut self) {
self.clear();
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::any::TypeId;
struct TestComponent {
value: i32,
}
#[test]
fn test_component_instance_creation() {
let instance = ComponentInstance::new(TestComponent { value: 42 });
let component = instance.get::<TestComponent>().unwrap();
assert_eq!(component.value, 42);
}
#[test]
fn test_component_instance_mutation() {
let mut instance = ComponentInstance::new(TestComponent { value: 0 });
{
let component = instance.get_mut::<TestComponent>().unwrap();
component.value = 100;
}
let component = instance.get::<TestComponent>().unwrap();
assert_eq!(component.value, 100);
}
#[test]
fn test_registry_get_or_create() {
let mut registry = ComponentRegistry::new();
let key = NodeKey::new(TypeId::of::<TestComponent>(), 0);
{
let instance = registry.get_or_create(key, || TestComponent { value: 1 });
instance.mark_used();
let component = instance.get::<TestComponent>().unwrap();
assert_eq!(component.value, 1);
}
{
let instance = registry.get_or_create(key, || TestComponent { value: 999 });
let component = instance.get::<TestComponent>().unwrap();
assert_eq!(component.value, 1); }
}
#[test]
fn test_registry_cleanup_unused() {
let mut registry = ComponentRegistry::new();
let key1 = NodeKey::new(TypeId::of::<TestComponent>(), 0);
let key2 = NodeKey::new(TypeId::of::<TestComponent>(), 1);
registry.get_or_create(key1, || TestComponent { value: 1 });
registry.get_or_create(key2, || TestComponent { value: 2 });
assert_eq!(registry.len(), 2);
registry.begin_render();
if let Some(instance) = registry.get_mut(&key1) {
instance.mark_used();
}
registry.end_render();
registry.cleanup();
assert_eq!(registry.len(), 1);
assert!(registry.contains(&key1));
assert!(!registry.contains(&key2));
}
#[test]
fn test_registry_clear() {
let mut registry = ComponentRegistry::new();
let key = NodeKey::new(TypeId::of::<TestComponent>(), 0);
registry.get_or_create(key, || TestComponent { value: 1 });
assert_eq!(registry.len(), 1);
registry.clear();
assert!(registry.is_empty());
}
#[test]
fn test_used_flag() {
let mut instance = ComponentInstance::new(TestComponent { value: 0 });
assert!(!instance.used);
instance.mark_used();
assert!(instance.used);
instance.reset_used();
assert!(!instance.used);
}
}