gled 2.28.4

gled is an application for creating animations and effects on artnet or dmx installations
use crate::storage::{asset::AssetTrait, collection::Collection};
use egui::mutex::Mutex;
use kanal::{Receiver, Sender, bounded};
use once_cell::sync::Lazy;
use std::{collections::HashMap, sync::atomic::AtomicUsize};
use typemap::ShareCloneMap;

static CURRENT: Lazy<Mutex<ShareCloneMap>> = Lazy::new(|| Mutex::new(ShareCloneMap::custom()));
static COLLECTION_ID: AtomicUsize = AtomicUsize::new(0);
static SENDERS: Lazy<Mutex<HashMap<usize, Sender<ShareCloneMap>>>> =
    Lazy::new(|| Mutex::new(HashMap::new()));

pub struct Collections {
    id: usize,
    receiver: Receiver<ShareCloneMap>,
    current: ShareCloneMap,
}

impl std::fmt::Debug for Collections {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Collections").finish_non_exhaustive()
    }
}

impl Default for Collections {
    fn default() -> Self {
        let (sender, receiver) = bounded(8);
        let id = COLLECTION_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
        SENDERS.lock().insert(id, sender);

        Self {
            id,
            receiver,
            current: CURRENT.lock().clone(),
        }
    }
}

impl Drop for Collections {
    fn drop(&mut self) {
        SENDERS.lock().remove(&self.id);
    }
}

impl Collections {
    #[cfg_attr(feature = "profiling", profiling::function)]
    pub fn update(&mut self) {
        while let Ok(Some(new_collections)) = self.receiver.try_recv() {
            self.current = new_collections;
        }
    }

    pub fn insert<T>(&mut self, val: Collection<T>)
    where
        T: AssetTrait,
    {
        self.current.insert::<Collection<T>>(val);
    }

    pub fn get<T>(&self) -> Option<&Collection<T>>
    where
        T: AssetTrait,
    {
        self.current.get::<Collection<T>>()
    }

    pub fn get_mut<T>(&mut self) -> &mut Collection<T>
    where
        T: AssetTrait,
    {
        self.current
            .entry::<Collection<T>>()
            .or_insert_with(Default::default)
    }

    pub fn save(&self) {
        for (id, sender) in SENDERS.lock().iter() {
            if id == &self.id {
                continue;
            }

            sender
                .send(self.current.clone())
                .expect("Could not send collections");
        }

        CURRENT.lock().clone_from(&self.current);
    }
}