mirror of
https://github.com/Zenithsiz/dynatos.git
synced 2026-02-08 21:09:52 +00:00
Derived now has a type parameter for the effect function.
This commit is contained in:
@@ -30,71 +30,99 @@
|
||||
//! not only store the latest value, it also needs to create an effect that is re-run
|
||||
//! each time any dependencies are updated.
|
||||
|
||||
// TODO: Make `Derived` always `usize`-sized
|
||||
// by merging the `effect::Inner` and `signal::Inner` somehow?
|
||||
|
||||
// Imports
|
||||
use {
|
||||
crate::{Effect, Signal, SignalSet, SignalWith},
|
||||
std::fmt,
|
||||
std::{fmt, marker::Unsize, ops::CoerceUnsized},
|
||||
};
|
||||
|
||||
/// Derived signal.
|
||||
///
|
||||
/// See the module documentation for more information.
|
||||
pub struct Derived<T> {
|
||||
pub struct Derived<T, F: ?Sized> {
|
||||
/// Effect
|
||||
effect: Effect<dyn Fn()>,
|
||||
|
||||
/// Value
|
||||
value: Signal<Option<T>>,
|
||||
effect: Effect<EffectFn<T, F>>,
|
||||
}
|
||||
|
||||
impl<T> Derived<T> {
|
||||
impl<T, F> Derived<T, F> {
|
||||
/// Creates a new derived signal
|
||||
pub fn new<F>(f: F) -> Self
|
||||
pub fn new(f: F) -> Self
|
||||
where
|
||||
T: 'static,
|
||||
F: Fn() -> T + 'static,
|
||||
{
|
||||
let value = Signal::new(None);
|
||||
let effect = Effect::new({
|
||||
let value = value.clone();
|
||||
move || value.set(Some(f()))
|
||||
});
|
||||
let effect = Effect::new(EffectFn { value, f });
|
||||
|
||||
Self { effect, value }
|
||||
Self { effect }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SignalWith for Derived<T> {
|
||||
impl<T, F: ?Sized> SignalWith for Derived<T, F> {
|
||||
type Value = T;
|
||||
|
||||
fn with<F, O>(&self, f: F) -> O
|
||||
fn with<F2, O>(&self, f: F2) -> O
|
||||
where
|
||||
F: FnOnce(&Self::Value) -> O,
|
||||
F2: FnOnce(&Self::Value) -> O,
|
||||
{
|
||||
self.value.with(|value| {
|
||||
let effect_fn = self.effect.inner_fn();
|
||||
effect_fn.value.with(|value| {
|
||||
let value = value.as_ref().expect("Value wasn't initialized");
|
||||
f(value)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for Derived<T> {
|
||||
impl<T, F: ?Sized> Clone for Derived<T, F> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
effect: self.effect.clone(),
|
||||
value: self.value.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug> fmt::Debug for Derived<T> {
|
||||
impl<T: fmt::Debug, F: ?Sized> fmt::Debug for Derived<T, F> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Derived")
|
||||
.field("effect", &self.effect)
|
||||
.field("value", &self.value)
|
||||
.finish()
|
||||
let effect_fn = self.effect.inner_fn();
|
||||
f.debug_struct("Derived").field("value", &effect_fn.value).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, F1: ?Sized, F2: ?Sized> CoerceUnsized<Derived<T, F2>> for Derived<T, F1> where F1: Unsize<F2> {}
|
||||
|
||||
/// Effect function
|
||||
struct EffectFn<T, F: ?Sized> {
|
||||
/// Value
|
||||
// TODO: Remove the indirection of the inner signal here.
|
||||
value: Signal<Option<T>>,
|
||||
|
||||
/// Function
|
||||
f: F,
|
||||
}
|
||||
|
||||
impl<T, F> FnOnce<()> for EffectFn<T, F>
|
||||
where
|
||||
F: Fn() -> T,
|
||||
{
|
||||
type Output = ();
|
||||
|
||||
extern "rust-call" fn call_once(mut self, args: ()) -> Self::Output {
|
||||
self.call_mut(args)
|
||||
}
|
||||
}
|
||||
impl<T, F> FnMut<()> for EffectFn<T, F>
|
||||
where
|
||||
F: Fn() -> T,
|
||||
{
|
||||
extern "rust-call" fn call_mut(&mut self, args: ()) -> Self::Output {
|
||||
self.call(args)
|
||||
}
|
||||
}
|
||||
impl<T, F> Fn<()> for EffectFn<T, F>
|
||||
where
|
||||
F: Fn() -> T,
|
||||
{
|
||||
extern "rust-call" fn call(&self, _args: ()) -> Self::Output {
|
||||
self.value.set(Some((self.f)()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Reactivity for `dynatos`
|
||||
|
||||
// Features
|
||||
#![feature(unsize, coerce_unsized)]
|
||||
#![feature(unsize, coerce_unsized, unboxed_closures, fn_traits)]
|
||||
|
||||
// Modules
|
||||
pub mod derived;
|
||||
|
||||
@@ -142,12 +142,7 @@ where
|
||||
}
|
||||
|
||||
// TODO: Allow impl for `impl SignalGet<Value: WithDynText>`
|
||||
#[duplicate::duplicate_item(
|
||||
Sig;
|
||||
[Signal];
|
||||
[Derived];
|
||||
)]
|
||||
impl<T> WithDynAttr for Sig<T>
|
||||
impl<T> WithDynAttr for Signal<T>
|
||||
where
|
||||
T: WithDynAttr,
|
||||
{
|
||||
@@ -159,6 +154,19 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, F> WithDynAttr for Derived<T, F>
|
||||
where
|
||||
T: WithDynAttr,
|
||||
F: ?Sized,
|
||||
{
|
||||
fn with_attr<F2, O>(&self, f: F2) -> O
|
||||
where
|
||||
F2: FnOnce(Option<&str>) -> O,
|
||||
{
|
||||
self.with(|text| text.with_attr(f))
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for values accepted by [`ElementDynAttr::set_dyn_attr_if`].
|
||||
///
|
||||
/// This allows it to work with the following types:
|
||||
@@ -188,12 +196,16 @@ impl DynAttrPred for bool {
|
||||
}
|
||||
|
||||
// TODO: Allow impl for `impl SignalGet<Value: WithDynText>`
|
||||
#[duplicate::duplicate_item(
|
||||
Sig;
|
||||
[Signal];
|
||||
[Derived];
|
||||
)]
|
||||
impl<T> DynAttrPred for Sig<T>
|
||||
impl<T> DynAttrPred for Signal<T>
|
||||
where
|
||||
T: DynAttrPred,
|
||||
{
|
||||
fn eval(&self) -> bool {
|
||||
self.with(T::eval)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, F: ?Sized> DynAttrPred for Derived<T, F>
|
||||
where
|
||||
T: DynAttrPred,
|
||||
{
|
||||
|
||||
@@ -113,12 +113,7 @@ where
|
||||
}
|
||||
|
||||
// TODO: Allow impl for `impl SignalGet<Value: WithDynText>`
|
||||
#[duplicate::duplicate_item(
|
||||
Sig;
|
||||
[Signal];
|
||||
[Derived];
|
||||
)]
|
||||
impl<T> WithDynText for Sig<T>
|
||||
impl<T> WithDynText for Signal<T>
|
||||
where
|
||||
T: WithDynText,
|
||||
{
|
||||
@@ -129,6 +124,18 @@ where
|
||||
self.with(|text| text.with_text(f))
|
||||
}
|
||||
}
|
||||
impl<T, F> WithDynText for Derived<T, F>
|
||||
where
|
||||
T: WithDynText,
|
||||
F: ?Sized,
|
||||
{
|
||||
fn with_text<F2, O>(&self, f: F2) -> O
|
||||
where
|
||||
F2: FnOnce(Option<&str>) -> O,
|
||||
{
|
||||
self.with(|text| text.with_text(f))
|
||||
}
|
||||
}
|
||||
impl<T> WithDynText for QuerySignal<T>
|
||||
where
|
||||
T: WithDynText,
|
||||
|
||||
@@ -140,12 +140,7 @@ impl ToDynProp for Ty {
|
||||
}
|
||||
|
||||
// TODO: Allow impl for `impl SignalGet<Value: WithDynText>`
|
||||
#[duplicate::duplicate_item(
|
||||
Sig;
|
||||
[Signal];
|
||||
[Derived];
|
||||
)]
|
||||
impl<T> ToDynProp for Sig<T>
|
||||
impl<T> ToDynProp for Signal<T>
|
||||
where
|
||||
T: ToDynProp,
|
||||
{
|
||||
@@ -153,6 +148,15 @@ where
|
||||
self.with(|prop| prop.to_prop())
|
||||
}
|
||||
}
|
||||
impl<T, F> ToDynProp for Derived<T, F>
|
||||
where
|
||||
T: ToDynProp,
|
||||
F: ?Sized,
|
||||
{
|
||||
fn to_prop(&self) -> Option<JsValue> {
|
||||
self.with(|prop| prop.to_prop())
|
||||
}
|
||||
}
|
||||
impl<T> ToDynProp for QuerySignal<T>
|
||||
where
|
||||
T: ToDynProp,
|
||||
|
||||
Reference in New Issue
Block a user