use std::{ any::Any, fmt::{Debug, Display, Formatter, Result as FmtResult}, ops::{Deref, DerefMut}, sync::{Arc, Mutex, MutexGuard}, }; use crate::prelude::Context; #[derive(Clone)] pub struct HookEffect(Arc>); #[derive(Debug)] pub struct State { value: Arc>, dependents: Arc>>, } pub struct Inner<'a, T> { value: MutexGuard<'a, T>, dependents: Arc>>, updated: bool, } #[derive(Debug, Clone)] pub struct Mount(Arc>, Arc>>); pub fn use_state(v: T) -> State { State { value: Arc::new(Mutex::new(v)), dependents: Arc::new(Mutex::new(Vec::new())), } } impl State { /// Gets the cloned value, recommended for preventing deadlocks pub fn get_dl(&self) -> T { self.value.lock().unwrap().clone() } } impl State { /// Gets a lock on the state for read/write access. pub fn get(&self) -> Inner<'_, T> { Inner { value: self.value.lock().unwrap(), dependents: self.dependents.clone(), updated: false, } } /// Sets the value and marks it as changed. pub fn set(&self, v: T) { *self.value.lock().unwrap() = v; self.update(); } pub fn update(&self) { for d in self.dependents.lock().unwrap().iter() { d.call(); } } pub fn clone(&self) -> Self { Self { dependents: self.dependents.clone(), value: self.value.clone(), } } } impl Display for State { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { write!(f, "{}", self.value.lock().unwrap()) } } impl Debug for HookEffect { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { write!(f, "HookEffect") } } impl HookEffect { pub fn new(f: F) -> Self { Self(Arc::new(Mutex::new(f))) } pub fn call(&self) { (self.0.lock().unwrap())() } } impl Drop for Inner<'_, T> { fn drop(&mut self) { if self.updated { for d in self.dependents.lock().unwrap().iter() { d.call(); } } } } impl Deref for Inner<'_, T> { type Target = T; fn deref(&self) -> &Self::Target { &self.value } } impl DerefMut for Inner<'_, T> { fn deref_mut(&mut self) -> &mut Self::Target { self.updated = true; &mut self.value } } pub trait HookDependency { fn on_update(&self, hook: HookEffect); } impl HookDependency for State { fn on_update(&self, hook: HookEffect) { self.dependents.lock().unwrap().push(hook); } } impl HookDependency for Mount { fn on_update(&self, hook: HookEffect) { if *self.0.lock().unwrap() { hook.call(); } else { self.1.lock().unwrap().push(hook); } } } impl Mount { pub fn mount(&self) { *self.0.lock().unwrap() = true; for hook_effect in self.1.lock().unwrap().iter() { hook_effect.call(); } self.1.lock().unwrap().clear(); } } pub fn use_effect(f: F, dependencies: &[&dyn HookDependency]) { let f = Arc::new(Mutex::new(f)); let hook = HookEffect(Arc::new(Mutex::new({ let f = f.clone(); move || { let f = f.clone(); std::thread::spawn(move || (f.lock().unwrap())()); } }))); for d in dependencies { d.on_update(hook.clone()); } } pub fn use_mount() -> Mount { Mount(Arc::new(Mutex::new(true)), Arc::new(Mutex::new(Vec::new()))) } pub fn use_mount_manual() -> Mount { Mount( Arc::new(Mutex::new(false)), Arc::new(Mutex::new(Vec::new())), ) } pub fn use_sync_state< T: Send + Sync + 'static, E: Any + 'static, D: Fn(&E) -> T + Send + Sync + 'static, >( cx: &Arc, v: T, decoder: D, ) -> State { let state = use_state(v); cx.on_event({ let state = state.clone(); move |_, v: &E| state.set(decoder(v)) }); state } pub fn use_sync_effect< T: Send + Sync + 'static, Ev: 'static, E: Fn(&State) -> Ev + Send + Sync + 'static, >( cx: &Arc, state: &State, encoder: E, deps: &[&dyn HookDependency], ) { use_effect( { let state = state.clone(); let cx = cx.clone(); move || { cx.emit_event(&encoder(&state)); } }, deps, ); }