use std::sync::Arc;
use parking_lot::RwLock;
use serde::Serialize;
use super::context::current_context;
use super::signal::{Signal, SignalId};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct EffectId(pub u32);
pub struct Effect {
pub id: EffectId,
callback: Arc<RwLock<Box<dyn FnMut() + Send + Sync>>>,
}
impl Effect {
pub fn run(&self) {
if let Some(ctx) = current_context() {
ctx.set_current_effect(Some(self.id));
}
(self.callback.write())();
if let Some(ctx) = current_context() {
ctx.set_current_effect(None);
}
}
}
pub fn use_effect<F>(callback: F) -> Effect
where
F: FnMut() + Send + Sync + 'static,
{
let id = current_context()
.map(|c| EffectId(c.next_effect_id()))
.unwrap_or(EffectId(0));
let cb: Arc<RwLock<Box<dyn FnMut() + Send + Sync>>> = Arc::new(RwLock::new(Box::new(callback)));
if let Some(ctx) = current_context() {
let cb_clone = cb.clone();
ctx.register_effect(id, move || {
(cb_clone.write())();
});
}
let eff = Effect { id, callback: cb };
eff.run();
eff
}
pub struct Computed<T: Clone + Serialize + Send + Sync + 'static> {
signal: Signal<T>,
#[allow(dead_code)]
effect: Effect,
}
impl<T: Clone + Serialize + Send + Sync + 'static> Computed<T> {
pub fn id(&self) -> SignalId {
self.signal.id()
}
pub fn get(&self) -> T {
self.signal.get()
}
pub fn peek(&self) -> T {
self.signal.peek()
}
}
pub fn use_computed<T, F>(mut compute: F) -> Computed<T>
where
T: Clone + Serialize + Send + Sync + 'static,
F: FnMut() -> T + Send + Sync + 'static,
{
let initial = compute();
let signal = Signal::new(initial);
let signal_for_effect = signal.clone();
let effect = use_effect(move || {
let next = compute();
signal_for_effect.set(next);
});
Computed { signal, effect }
}