Macro hooks_core::impl_hook

source ·
macro_rules! impl_hook {
    (
        type For
            $(<$(
                $($lt:lifetime)?
                $($tp1:ident $($tp2:ident)?)?
                $(
                    :
                    $($bound_lt:lifetime)?
                    $(+ $bounds_lt:lifetime)*
                    $(
                        $( + $({$plus_ignore:tt })? )?
                        $( ? $([$relax_ignore:tt])? )?
                        $bounds:path
                    )*
                )?
            ),* >)?
            = $ty:ty
            $(
                where
                __![$($($where_clause:tt)+)?]: __
                $(,)?
            )?
        ;
        $(
            $(#$fn_attr:tt)*
            fn $fn_name:ident $args:tt $(-> $fn_ret_ty:ty)?
            {$($impl_hook:tt)*}
        )*
    ) => { ... };
}
Expand description

Easily impl traits.

For example:

struct OutputOnce<T>(pub Option<T>);

impl_hook!(
    type For<T: Unpin> = OutputOnce<T>;

    /// HookUnmount is implemented with default `fn unmount()`
    fn unmount() {}

    /// HookPollNextUpdate is implemented
    fn poll_next_update(self, _cx: _) {
        std::task::Poll::Ready(self.get_mut().0.is_some())
    }

    /// HookValue and Hook is implemented
    /// HookValue::Value is `&'hook mut Option<T>`
    #[inline]
    fn use_hook(self) -> &'hook mut Option<T> {
        &mut self.get_mut().0
    }
);

Declare the type to impl for with type For = ...;

impl_hook!(
    type For = MyType;
);

You can declare generics and bounds.

impl_hook!(
    type For<'a, T: Clone + Default, F: FnMut(&T) -> T> = MyType<'a, T, F>;
);

Parsing with macro_rules is limited. For example, complex bounds are not supported.

impl_hook!(
    type For<F: for<'a> FnMut(&'a str) -> &'a str> = MyType<F>;
);

You can move complex bounds to a special where clause where __![...]: __

impl_hook!(
    type For<F> = MyType<F>
        where __![F: for<'a> FnMut(&'a str) -> &'a str]: __;
);

After declaring the type, you can easily impl traits for this type with methods.

Supported traits

impl HookUnmount with unmount

With default implementation:

impl_hook!(
    type For = MyType;
    fn unmount() {}
);

With custom implementation:

impl_hook!(
    type For = MyType;
    fn unmount(self) {
        self.do_something();
    }
);

impl HookPollNextUpdate with poll_next_update

Argument cx is of type &mut std::task::Context<'_>. The return type is std::task::Poll<bool>

impl_hook!(
    type For = MyType;
    fn poll_next_update(self, cx: _) {
        self.project().inner.poll(cx)
    }
);

impl HookValue and Hook with use_hook

Note that Hook requires HookUnmount + HookPollNextUpdate

impl_hook!(
    type For = MyType;
    fn unmount() {}
    fn poll_next_update(self, cx: _) { todo!() }
    fn use_hook(self) -> MyValueType {
        self.0
    }
);

impl IntoHook with into_hook

impl_hook!(
    type For = UseMyHook;
    fn into_hook(self) -> MyHook {
        MyHook(self.0)
    }
);

impl UpdateHook with update_hook

Note that UpdateHook requires IntoHook.

impl_hook!(
    type For = UseMyHook;
    fn into_hook(self) -> MyHook {
        MyHook(self.0)
    }
    fn update_hook(self, mut hook: _) {
        hook.0 = self.0
    }
);

impl UpdateHookUninitialized with h

Note that UpdateHookUninitialized requires UpdateHook + IntoHook.

impl_hook!(
    type For = UseMyHook;
    fn into_hook(self) -> MyHook {
        MyHook(self.0)
    }
    fn update_hook(self, mut hook: _) {
        hook.0 = self.0
    }
    fn h(self, mut hook: MyHookUninitialized) {
        hook.0.get_or_insert(self.0);
    }
);