use std::{ cell::{Ref, RefMut}, fmt::Display, marker::PhantomData, ops::{Add, Div, Mul, Sub}, }; mod rt; use dioxus_core::ScopeState; pub use rt::*; pub fn use_init_signal_rt(cx: &ScopeState) { cx.use_hook(|| { let rt = claim_rt(cx.schedule_update_any()); cx.provide_context(rt); }); } pub fn use_signal(cx: &ScopeState, f: impl FnOnce() -> T) -> Signal { cx.use_hook(|| { let rt: &'static SignalRt = match cx.consume_context() { Some(rt) => rt, None => cx.provide_context(claim_rt(cx.schedule_update_any())), }; let id = rt.init(f()); rt.subscribe(id, cx.scope_id()); struct SignalHook { signal: Signal, } impl Drop for SignalHook { fn drop(&mut self) { self.signal.rt.remove(self.signal.id); } } SignalHook { signal: Signal { id, rt, t: PhantomData, }, } }) .signal } pub struct Signal { id: usize, rt: &'static SignalRt, t: PhantomData, } impl Signal { pub fn read(&self) -> Ref { self.rt.read(self.id) } pub fn write(&self) -> RefMut { self.rt.write(self.id) } pub fn set(&mut self, value: T) { self.rt.set(self.id, value); } pub fn with(&self, f: impl FnOnce(&T) -> O) -> O { let write = self.read(); f(&*write) } pub fn update(&self, _f: impl FnOnce(&mut T) -> O) -> O { let mut write = self.write(); _f(&mut *write) } } impl Signal { pub fn get(&self) -> T { self.rt.get(self.id) } } impl std::ops::Deref for Signal { type Target = dyn Fn() -> T; fn deref(&self) -> &Self::Target { self.rt.getter(self.id) } } impl std::clone::Clone for Signal { fn clone(&self) -> Self { *self } } impl Copy for Signal {} impl Display for Signal { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.rt.with::(self.id, |v| T::fmt(v, f)) } } impl + Copy + 'static> std::ops::AddAssign for Signal { fn add_assign(&mut self, rhs: T) { self.set(self.get() + rhs); } } impl + Copy + 'static> std::ops::SubAssign for Signal { fn sub_assign(&mut self, rhs: T) { self.set(self.get() - rhs); } } impl + Copy + 'static> std::ops::MulAssign for Signal { fn mul_assign(&mut self, rhs: T) { self.set(self.get() * rhs); } } impl + Copy + 'static> std::ops::DivAssign for Signal { fn div_assign(&mut self, rhs: T) { self.set(self.get() / rhs); } }