use std::{
ops::{Deref, DerefMut},
pin::Pin,
task::Poll,
};
mod sealed {
pub trait Sealed<'hook, This: ?Sized> {}
impl<'hook, T: ?Sized> Sealed<'hook, T> for &'hook T {}
}
pub trait HookValueBounds<'hook, This: ?Sized>: sealed::Sealed<'hook, This> {}
impl<'hook, T: ?Sized> HookValueBounds<'hook, T> for &'hook T {}
pub trait Captures<U> {}
impl<T: ?Sized, U> Captures<U> for T {}
pub trait HookValue<'hook, ImplicitBounds: HookValueBounds<'hook, Self> = &'hook Self> {
type Value;
}
pub trait HookPollNextUpdate {
fn poll_next_update(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<bool>;
}
pub trait HookUnmount {
#[inline(always)]
fn unmount(self: Pin<&mut Self>) {}
}
pub trait Hook: HookPollNextUpdate + HookUnmount + for<'hook> HookValue<'hook> {
fn use_hook(self: Pin<&mut Self>) -> <Self as HookValue<'_>>::Value;
}
pub trait NonLendingHook:
Hook + for<'hook> HookValue<'hook, Value = Self::NonGenericValue>
{
type NonGenericValue;
}
impl<H, V> NonLendingHook for H
where
H: Hook + for<'hook> HookValue<'hook, Value = V>,
{
type NonGenericValue = V;
}
macro_rules! impl_for_deref_hook {
(
impl<$h:ident> (
$($ty:ty),*
$(,)?
) {
$poll_next_update:item
$unmount:item
$use_hook:item
}
) => {$(
impl<H: HookPollNextUpdate + Unpin + ?Sized> HookPollNextUpdate for $ty {
$poll_next_update
}
impl<H: HookUnmount + Unpin + ?Sized> HookUnmount for $ty {
$unmount
}
impl<'hook, H: Hook + Unpin + ?Sized> HookValue<'hook> for $ty {
type Value = <H as HookValue<'hook>>::Value;
}
impl<H: Hook + Unpin + ?Sized> Hook for $ty {
$use_hook
}
)*};
}
impl_for_deref_hook![
impl<H> (&mut H, Box<H>) {
#[inline]
fn poll_next_update(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<bool> {
H::poll_next_update(Pin::new(self.get_mut()), cx)
}
#[inline]
fn unmount(self: Pin<&mut Self>) {
H::unmount(Pin::new(self.get_mut()))
}
#[inline]
fn use_hook(self: Pin<&mut Self>) -> <Self as HookValue<'_>>::Value {
H::use_hook(Pin::new(self.get_mut()))
}
}
];
impl<P> HookPollNextUpdate for Pin<P>
where
P: DerefMut,
<P as Deref>::Target: HookPollNextUpdate,
{
#[inline]
fn poll_next_update(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<bool> {
<P::Target as HookPollNextUpdate>::poll_next_update(
crate::utils::pin_as_deref_mut(self),
cx,
)
}
}
impl<P> HookUnmount for Pin<P>
where
P: DerefMut,
<P as Deref>::Target: HookUnmount,
{
#[inline]
fn unmount(self: Pin<&mut Self>) {
<<P as Deref>::Target as HookUnmount>::unmount(crate::utils::pin_as_deref_mut(self))
}
}
impl<'hook, P> HookValue<'hook> for Pin<P>
where
P: DerefMut,
<P as Deref>::Target: Hook,
{
type Value = <<P as Deref>::Target as HookValue<'hook>>::Value;
}
impl<P> Hook for Pin<P>
where
P: DerefMut,
<P as Deref>::Target: Hook,
{
#[inline]
fn use_hook(self: Pin<&mut Self>) -> <Self as HookValue<'_>>::Value {
<P::Target as Hook>::use_hook(crate::utils::pin_as_deref_mut(self))
}
}
pub trait IntoHook {
type Hook: Hook;
fn into_hook(self) -> Self::Hook;
#[inline(always)]
fn into_hook_values(self) -> crate::Values<Self::Hook>
where
Self: Sized,
{
crate::Values::new(self.into_hook())
}
}
impl<H> IntoHook for H
where
H: Hook,
{
type Hook = H;
#[inline(always)]
fn into_hook(self) -> Self::Hook {
self
}
}
pub trait UpdateHook: IntoHook {
fn update_hook(self, hook: Pin<&mut Self::Hook>);
}
pub trait UpdateHookUninitialized: UpdateHook {
type Uninitialized: HookPollNextUpdate + HookUnmount + Default;
fn h(self, hook: Pin<&mut Self::Uninitialized>) -> <Self::Hook as HookValue<'_>>::Value;
}
pub type Value<'hook, H> = <H as HookValue<'hook>>::Value;