ratatui-reactive 0.6.0

A minimalistic framework for building TUI applications using fine-grained reactivity.
Documentation
use crate::spawn_local;
use async_local_channel::spsc;
use sycamore_reactive::{Signal, create_effect, create_signal, use_current_scope};

#[derive(Debug)]
pub struct DelayedSet<T: 'static> {
    signal: Signal<T>,
}

impl<T: 'static> Clone for DelayedSet<T> {
    #[inline]
    fn clone(&self) -> Self {
        *self
    }
}

impl<T: 'static> Copy for DelayedSet<T> {}

impl<T: 'static> DelayedSet<T> {
    #[inline]
    pub fn set(&self, value: T) {
        self.signal.set(value);
    }
}

#[derive(Debug)]
pub struct DelayedGet<T: 'static> {
    signal: Signal<T>,
}

impl<T: 'static> Clone for DelayedGet<T> {
    #[inline]
    fn clone(&self) -> Self {
        *self
    }
}

impl<T: 'static> Copy for DelayedGet<T> {}

impl<T: 'static + Default> DelayedGet<T> {
    #[inline]
    pub fn get(&self) -> T {
        self.signal.track();
        self.signal.take_silent()
    }
}

#[inline]
#[cfg_attr(debug_assertions, track_caller)]
pub fn delayed_signal<T: Default>(value: T) -> (DelayedSet<T>, DelayedGet<T>) {
    let input = create_signal(T::default());
    let output = create_signal(value);
    let (tx, rx) = spsc::channel();
    create_effect(move || {
        input.track();
        tx.send(input.take_silent()).unwrap();
    });
    let rx = rx.activate();
    let scope = use_current_scope();
    spawn_local(async move {
        loop {
            let value = rx.recv().await.unwrap();
            if output.is_alive() {
                scope.run_in(move || output.set(value))
            } else {
                return;
            }
        }
    });
    (DelayedSet { signal: input }, DelayedGet { signal: output })
}