gled-core 2.30.1

The engine of gled without a user interface: inputs, timing, rendering, Art-Net/DMX output and storage
Documentation
use crate::storage::asset::{project::Project, scene::grid::GridLocation};
use kanal::{Receiver, Sender, unbounded};
use once_cell::sync::{Lazy, OnceCell};
use parking_lot::Mutex;

static SENDER: OnceCell<Sender<ProjectState>> = OnceCell::new();
static SUBSCRIBERS: Lazy<Mutex<Vec<Sender<ProjectState>>>> = Lazy::new(|| Mutex::new(Vec::new()));

#[derive(Debug, Clone)]
pub(crate) struct ProjectState {
    pub(crate) project: Option<Project>,
    pub(crate) selected_scene_instance: GridLocation,
    pub(crate) blackout: bool,
    pub(crate) beats_per_minute: f32,
    pub(crate) beat_progression: f32,
}

impl ProjectState {
    pub(crate) fn enqueue(self) {
        SENDER
            .get()
            .expect("Could not get project state sender")
            .send(self)
            .expect("Could not send project state");
    }
}

pub(crate) fn init() {
    let (sender, receiver) = unbounded();
    SENDER
        .set(sender)
        .expect("Could not set project state sender");

    std::thread::spawn(move || {
        #[cfg(feature = "profiling")]
        profiling::register_thread!("output:state");

        for state in receiver {
            SUBSCRIBERS
                .lock()
                .retain(|subscriber| subscriber.send(state.clone()).is_ok());
        }
    });
}

pub(crate) fn new_receiver() -> Receiver<ProjectState> {
    let (sender, receiver) = unbounded();
    SUBSCRIBERS.lock().push(sender);
    receiver
}