aura-gui 0.2.2

UI nativa acelerada por GPU para escritorio, Android e iOS, en un solo crate: estilo tipo Tailwind, componentes, sombras, animaciones y agentes de IA. Reposo a cero. Licencia AGPL-3.0 o comercial.
//! Cola de eventos y suscripciones entre entidades (patrón Observer).

use crate::core::entity::{EntityId, EntityMap};
use std::any::Any;
use std::collections::{HashMap, VecDeque};
use std::rc::Rc;

pub(crate) type Listener = Rc<dyn Fn(&mut EntityMap, &dyn Any)>;

/// Identifica una suscripción para poder cancelarla.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Subscription(u64);

#[derive(Default)]
pub(crate) struct EventQueue {
    pending: VecDeque<(EntityId, Box<dyn Any>)>,
    listeners: HashMap<EntityId, Vec<(Subscription, EntityId, Listener)>>,
    next_id: u64,
}

impl EventQueue {
    pub fn push(&mut self, emitter: EntityId, event: Box<dyn Any>) {
        self.pending.push_back((emitter, event));
    }

    pub fn pop(&mut self) -> Option<(EntityId, Box<dyn Any>)> {
        self.pending.pop_front()
    }

    pub fn subscribe(
        &mut self,
        emitter: EntityId,
        subscriber: EntityId,
        listener: impl Fn(&mut EntityMap, &dyn Any) + 'static,
    ) -> Subscription {
        self.next_id += 1;
        let subscription = Subscription(self.next_id);
        self.listeners.entry(emitter).or_default().push((subscription, subscriber, Rc::new(listener)));
        subscription
    }

    pub fn unsubscribe(&mut self, subscription: Subscription) {
        for listeners in self.listeners.values_mut() {
            listeners.retain(|(id, _, _)| *id != subscription);
        }
    }

    /// Se copian los `Rc` para que un oyente pueda suscribirse o cancelar mientras se entrega.
    pub fn listeners(&self, emitter: EntityId) -> Vec<Listener> {
        self.listeners
            .get(&emitter)
            .map(|listeners| listeners.iter().map(|(_, _, listener)| listener.clone()).collect())
            .unwrap_or_default()
    }

    /// Olvida todo lo relacionado con una entidad eliminada.
    pub fn forget(&mut self, id: EntityId) {
        self.listeners.remove(&id);
        for listeners in self.listeners.values_mut() {
            listeners.retain(|(_, subscriber, _)| *subscriber != id);
        }
    }
}