use futures::{FutureExt, future::LocalBoxFuture};
use std::task::Poll;
use crate::{Hook, Hooks};
mod private {
pub trait Sealed {}
impl Sealed for crate::Hooks<'_, '_> {}
}
pub trait UseEffect: private::Sealed {
fn use_effect<F, D>(&mut self, f: F, deps: D)
where
F: FnOnce(),
D: PartialEq + Unpin + 'static;
fn use_async_effect<F, D>(&mut self, f: F, deps: D)
where
F: Future<Output = ()> + 'static,
D: PartialEq + Unpin + 'static;
}
pub struct UseEffectImpl<D> {
deps: Option<D>,
}
impl<D> Default for UseEffectImpl<D> {
fn default() -> Self {
Self { deps: None }
}
}
pub struct UseAsyncEffectImpl<D> {
f: Option<LocalBoxFuture<'static, ()>>,
deps: Option<D>,
}
impl<D> Default for UseAsyncEffectImpl<D> {
fn default() -> Self {
Self {
f: None,
deps: None,
}
}
}
impl<D: Unpin> Hook for UseAsyncEffectImpl<D> {
fn poll_change(&mut self, cx: &mut std::task::Context) -> std::task::Poll<()> {
if let Some(future) = self.f.as_mut()
&& future.as_mut().poll(cx).is_ready()
{
self.f = None;
return Poll::Ready(());
}
Poll::Pending
}
}
impl<D: Unpin> Hook for UseEffectImpl<D> {}
impl UseEffect for Hooks<'_, '_> {
fn use_effect<F, D>(&mut self, f: F, deps: D)
where
F: FnOnce(),
D: PartialEq + Unpin + 'static,
{
let hook = self.use_hook(UseEffectImpl::<D>::default);
if hook.deps.as_ref() != Some(&deps) {
f();
hook.deps = Some(deps);
}
}
fn use_async_effect<F, D>(&mut self, f: F, deps: D)
where
F: Future<Output = ()> + 'static,
D: PartialEq + Unpin + 'static,
{
let hook = self.use_hook(UseAsyncEffectImpl::<D>::default);
if hook.deps.as_ref() != Some(&deps) {
hook.f = Some(f.boxed_local());
hook.deps = Some(deps);
}
}
}