use std::{any::Any, cell::RefCell, sync::Arc}; use dioxus_core::ScopeId; use slab::Slab; thread_local! { // we cannot drop these since any future might be using them static RUNTIMES: RefCell> = RefCell::new(Vec::new()); } /// Provide the runtime for signals /// /// This will reuse dead runtimes pub fn claim_rt(update_any: Arc) -> &'static SignalRt { RUNTIMES.with(|runtimes| { if let Some(rt) = runtimes.borrow_mut().pop() { return rt; } Box::leak(Box::new(SignalRt { signals: RefCell::new(Slab::new()), update_any, })) }) } /// Push this runtime into the global runtime list pub fn reclam_rt(_rt: &'static SignalRt) { RUNTIMES.with(|runtimes| { runtimes.borrow_mut().push(_rt); }); } pub struct SignalRt { pub(crate) signals: RefCell>, pub(crate) update_any: Arc, } impl SignalRt { pub fn init(&'static self, val: T) -> usize { self.signals.borrow_mut().insert(Inner { value: Box::new(val), subscribers: Vec::new(), getter: None, }) } pub fn subscribe(&self, id: usize, subscriber: ScopeId) { self.signals.borrow_mut()[id].subscribers.push(subscriber); } pub fn get(&self, id: usize) -> T { self.signals.borrow()[id] .value .downcast_ref::() .cloned() .unwrap() } pub fn set(&self, id: usize, value: T) { let mut signals = self.signals.borrow_mut(); let inner = &mut signals[id]; inner.value = Box::new(value); for subscriber in inner.subscribers.iter() { (self.update_any)(*subscriber); } } pub fn remove(&self, id: usize) { self.signals.borrow_mut().remove(id); } pub fn with(&self, id: usize, f: impl FnOnce(&T) -> O) -> O { let signals = self.signals.borrow(); let inner = &signals[id]; let inner = inner.value.downcast_ref::().unwrap(); f(inner) } pub(crate) fn read(&self, id: usize) -> std::cell::Ref { let signals = self.signals.borrow(); std::cell::Ref::map(signals, |signals| { signals[id].value.downcast_ref::().unwrap() }) } pub(crate) fn write(&self, id: usize) -> std::cell::RefMut { let signals = self.signals.borrow_mut(); std::cell::RefMut::map(signals, |signals| { signals[id].value.downcast_mut::().unwrap() }) } pub(crate) fn getter(&self, id: usize) -> &dyn Fn() -> T { let mut signals = self.signals.borrow_mut(); let inner = &mut signals[id]; let r = inner.getter.as_mut(); if r.is_none() { let rt = self; let r = move || rt.get::(id); let getter: Box T> = Box::new(r); let getter: Box = unsafe { std::mem::transmute(getter) }; inner.getter = Some(getter); } let r = inner.getter.as_ref().unwrap(); unsafe { std::mem::transmute::<&dyn Fn(), &dyn Fn() -> T>(r) } } } pub(crate) struct Inner { pub value: Box, pub subscribers: Vec, // todo: this has a soundness hole in it that you might not run into pub getter: Option>, }