use dioxus_signals::{Readable, Writable};
use crate::use_signal;
pub trait Dependency: Sized + Clone {
type Out: Clone + PartialEq + 'static;
fn out(&self) -> Self::Out;
fn changed(&self, other: &Self::Out) -> bool {
self.out() != *other
}
}
impl Dependency for () {
type Out = ();
fn out(&self) -> Self::Out {}
}
pub trait DependencyElement: 'static + PartialEq + Clone {}
impl<T> DependencyElement for T where T: 'static + PartialEq + Clone {}
impl<A: DependencyElement> Dependency for &A {
type Out = A;
fn out(&self) -> Self::Out {
(*self).clone()
}
}
macro_rules! impl_dep {
(
$($el:ident=$name:ident $other:ident,)*
) => {
impl< $($el),* > Dependency for ($(&$el,)*)
where
$(
$el: DependencyElement
),*
{
type Out = ($($el,)*);
fn out(&self) -> Self::Out {
let ($($name,)*) = self;
($((*$name).clone(),)*)
}
fn changed(&self, other: &Self::Out) -> bool {
let ($($name,)*) = self;
let ($($other,)*) = other;
$(
if *$name != $other {
return true;
}
)*
false
}
}
};
}
impl_dep!(A = a1 a2,);
impl_dep!(A = a1 a2, B = b1 b2,);
impl_dep!(A = a1 a2, B = b1 b2, C = c1 c2,);
impl_dep!(A = a1 a2, B = b1 b2, C = c1 c2, D = d1 d2,);
impl_dep!(A = a1 a2, B = b1 b2, C = c1 c2, D = d1 d2, E = e1 e2,);
impl_dep!(A = a1 a2, B = b1 b2, C = c1 c2, D = d1 d2, E = e1 e2, F = f1 f2,);
impl_dep!(A = a1 a2, B = b1 b2, C = c1 c2, D = d1 d2, E = e1 e2, F = f1 f2, G = g1 g2,);
impl_dep!(A = a1 a2, B = b1 b2, C = c1 c2, D = d1 d2, E = e1 e2, F = f1 f2, G = g1 g2, H = h1 h2,);
pub fn use_reactive<O, D: Dependency>(
non_reactive_data: D,
mut closure: impl FnMut(D::Out) -> O + 'static,
) -> impl FnMut() -> O + 'static {
let mut first_run = false;
let mut last_state = use_signal(|| {
first_run = true;
non_reactive_data.out()
});
if !first_run && non_reactive_data.changed(&*last_state.peek()) {
last_state.set(non_reactive_data.out());
}
move || closure(last_state())
}
#[macro_export]
macro_rules! use_reactive {
(|| $($rest:tt)*) => { use_reactive( (), move |_| $($rest)* ) };
(| $($args:tt),* | $($rest:tt)*) => {
use_reactive(
($(&$args),*),
move |($($args),*)| $($rest)*
)
};
}