diff --git a/examples/signals.rs b/examples/signals.rs index e5e0935b5..988b9af41 100644 --- a/examples/signals.rs +++ b/examples/signals.rs @@ -14,7 +14,7 @@ fn app(cx: Scope) -> Element { use_future!(cx, || async move { loop { count += 1; - tokio::time::sleep(Duration::from_millis(100)).await; + tokio::time::sleep(Duration::from_millis(400)).await; } }); @@ -22,5 +22,9 @@ fn app(cx: Scope) -> Element { h1 { "High-Five counter: {count}" } button { onclick: move |_| count += 1, "Up high!" } button { onclick: move |_| count -= 1, "Down low!" } + + if count() > 5 { + rsx!{ h2 { "High five!" } } + } }) } diff --git a/packages/signals/src/lib.rs b/packages/signals/src/lib.rs index 2fcbdcdb2..e4b499ed8 100644 --- a/packages/signals/src/lib.rs +++ b/packages/signals/src/lib.rs @@ -26,6 +26,7 @@ pub fn use_signal(cx: &ScopeState, f: impl FnOnce() -> T) -> Signal< struct SignalHook { signal: Signal, } + impl Drop for SignalHook { fn drop(&mut self) { self.signal.rt.remove(self.signal.id); @@ -62,6 +63,11 @@ impl Signal { 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) @@ -74,13 +80,13 @@ impl Signal { } } -// impl std::ops::Deref for Signal { -// type Target = dyn Fn() -> T; +impl std::ops::Deref for Signal { + type Target = dyn Fn() -> T; -// fn deref(&self) -> &Self::Target { -// todo!() -// } -// } + fn deref(&self) -> &Self::Target { + self.rt.getter(self.id) + } +} impl std::clone::Clone for Signal { fn clone(&self) -> Self { @@ -123,27 +129,3 @@ impl + Copy + 'static> std::ops::DivAssign for Signal { self.set(self.get() / rhs); } } - -// impl + Copy> std::ops::AddAssign for Signal { -// fn add_assign(&mut self, rhs: T) { -// self.set((*self.current()) + rhs); -// } -// } - -// impl + Copy> std::ops::SubAssign for Signal { -// fn sub_assign(&mut self, rhs: T) { -// self.set((*self.current()) - rhs); -// } -// } - -// impl + Copy> std::ops::MulAssign for Signal { -// fn mul_assign(&mut self, rhs: T) { -// self.set((*self.current()) * rhs); -// } -// } - -// impl + Copy> std::ops::DivAssign for Signal { -// fn div_assign(&mut self, rhs: T) { -// self.set((*self.current()) / rhs); -// } -// } diff --git a/packages/signals/src/rt.rs b/packages/signals/src/rt.rs index d516b9ff0..e849f9008 100644 --- a/packages/signals/src/rt.rs +++ b/packages/signals/src/rt.rs @@ -4,6 +4,7 @@ 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()); } @@ -31,15 +32,16 @@ pub fn reclam_rt(_rt: &'static SignalRt) { } pub struct SignalRt { - signals: RefCell>, - update_any: Arc, + pub(crate) signals: RefCell>, + pub(crate) update_any: Arc, } impl SignalRt { - pub fn init(&self, val: T) -> usize { + pub fn init(&'static self, val: T) -> usize { self.signals.borrow_mut().insert(Inner { value: Box::new(val), subscribers: Vec::new(), + getter: None, }) } @@ -73,7 +75,7 @@ impl SignalRt { let signals = self.signals.borrow(); let inner = &signals[id]; let inner = inner.value.downcast_ref::().unwrap(); - f(&*inner) + f(inner) } pub(crate) fn read(&self, id: usize) -> std::cell::Ref { @@ -89,9 +91,31 @@ impl SignalRt { 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) } + } } -struct Inner { - value: Box, - subscribers: Vec, +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>, }