fui-rs 0.2.3-alpha1

Retained-mode Rust UI SDK for EffinDOM
Documentation
use crate::signal::{Callback, Signal, SubscriptionGuard};
use std::cell::RefCell;
use std::rc::Rc;

#[derive(Clone, Copy)]
pub struct FrameTimeSignalHandle;

thread_local! {
    static FRAME_TIME_SIGNAL: RefCell<Signal<f64>> = RefCell::new(Signal::new(0.0));
}

impl FrameTimeSignalHandle {
    pub fn value(&self) -> f64 {
        FRAME_TIME_SIGNAL.with(|slot| slot.borrow().get())
    }

    pub fn subscribe(&self, handler: impl Fn(f64) + 'static) -> SubscriptionGuard {
        handler(self.value());
        FRAME_TIME_SIGNAL.with(|slot| {
            let callback: Callback = Rc::new(move || handler(frame_time_signal().value()));
            slot.borrow_mut().subscribe(callback)
        })
    }
}

pub fn frame_time_signal() -> FrameTimeSignalHandle {
    FrameTimeSignalHandle
}

pub(crate) fn set_frame_time(timestamp_ms: f64) {
    FRAME_TIME_SIGNAL.with(|slot| {
        let callbacks = slot.borrow_mut().set(timestamp_ms);
        if let Some(callbacks) = callbacks {
            for callback in callbacks {
                callback();
            }
        }
    });
}

#[cfg(test)]
mod tests {
    use super::{frame_time_signal, set_frame_time};
    use std::cell::Cell;
    use std::rc::Rc;

    #[test]
    fn updates_frame_time_signal_and_notifies_subscribers() {
        let count = Rc::new(Cell::new(0));
        let seen = Rc::new(Cell::new(0.0));
        let count_for_handler = count.clone();
        let seen_for_handler = seen.clone();
        let _guard = frame_time_signal().subscribe(move |value| {
            count_for_handler.set(count_for_handler.get() + 1);
            seen_for_handler.set(value);
        });

        set_frame_time(1234.5);

        assert_eq!(frame_time_signal().value(), 1234.5);
        assert_eq!(seen.get(), 1234.5);
        assert!(count.get() >= 2);
    }
}