hooks/
signal.rs

1pub use UseSignal as use_signal;
2
3use std::pin::Pin;
4
5use hooks_core::{Hook, HookPollNextUpdate, HookUnmount};
6
7use crate::{ShareValue, ToOwnedShareValue};
8
9mod sealed {
10    use hooks_core::{HookValue, HookValueBounds};
11
12    use crate::ShareValue;
13
14    use super::Signal;
15
16    pub trait HookValueImplSignal<'hook, ImplicitBounds: HookValueBounds<'hook, Self> = &'hook Self>:
17        HookValue<'hook, ImplicitBounds, Value = Self::HookValueImplSignal>
18    {
19        type HookValueImplShareValueValue;
20        type HookValueImplSignal: Signal<
21            SignalHook = Self,
22            Value = Self::HookValueImplShareValueValue,
23        >;
24    }
25
26    impl<'hook, H: ?Sized> HookValueImplSignal<'hook> for H
27    where
28        H: HookValue<'hook>,
29        H::Value: Signal<SignalHook = Self>,
30    {
31        type HookValueImplShareValueValue = <H::Value as ShareValue>::Value;
32        type HookValueImplSignal = H::Value;
33    }
34}
35
36/// `for<'hook> sealed::HookValueImplSignal<'hook>` here acts like [`for<'hook> HookValue<'hook, Value: Signal<SignalHook = Self, Value = Self::SignalShareValue>>`](crate::HookValue::Value).
37pub trait SignalHook:
38    Hook
39    + Signal<Value = Self::SignalShareValue, SignalHook = Self>
40    + for<'hook> sealed::HookValueImplSignal<
41        'hook,
42        HookValueImplShareValueValue = Self::SignalShareValue,
43    >
44{
45    type SignalShareValue;
46
47    type SignalHookUninitialized: HookPollNextUpdate + HookUnmount + Default;
48
49    /// This is the opposite of [`Signal::to_signal_hook`].
50    ///
51    /// In contrast to [`Hook::use_hook`], this method just require a `&Self` instead of `Pin<&mut Self>`.
52    /// In implementations, [`Hook::use_hook`] might mark the SignalHook's updated value as already read
53    /// but this method should not.
54    fn to_signal(&self) -> crate::Value<'_, Self>;
55}
56
57pub trait Signal: ShareValue {
58    type SignalHook: SignalHook<SignalShareValue = Self::Value>;
59
60    fn is_signal_of(&self, signal_hook: &Self::SignalHook) -> bool;
61
62    /// This is the opposite of [`SignalHook::to_signal`].
63    fn to_signal_hook(&self) -> Self::SignalHook;
64
65    fn update_signal_hook(&self, hook: Pin<&mut Self::SignalHook>);
66    fn h_signal_hook<'hook>(
67        &self,
68        hook: Pin<&'hook mut <Self::SignalHook as SignalHook>::SignalHookUninitialized>,
69    ) -> crate::Value<'hook, Self::SignalHook>;
70
71    fn use_signal(&self) -> UseSignal<'_, Self> {
72        UseSignal(self)
73    }
74
75    fn notify_changed(&self);
76
77    fn map_mut_and_notify_if<R>(&self, f: impl FnOnce(&mut Self::Value) -> (R, bool)) -> R;
78}
79
80impl<S: Signal + ?Sized> Signal for &S {
81    type SignalHook = S::SignalHook;
82
83    fn is_signal_of(&self, signal_hook: &Self::SignalHook) -> bool {
84        S::is_signal_of(self, signal_hook)
85    }
86    fn to_signal_hook(&self) -> Self::SignalHook {
87        S::to_signal_hook(self)
88    }
89    fn update_signal_hook(&self, hook: Pin<&mut Self::SignalHook>) {
90        S::update_signal_hook(self, hook)
91    }
92    fn h_signal_hook<'hook>(
93        &self,
94        hook: ::core::pin::Pin<
95            &'hook mut <Self::SignalHook as SignalHook>::SignalHookUninitialized,
96        >,
97    ) -> crate::Value<'hook, Self::SignalHook> {
98        S::h_signal_hook(self, hook)
99    }
100    fn notify_changed(&self) {
101        S::notify_changed(self)
102    }
103    fn map_mut_and_notify_if<R>(&self, f: impl FnOnce(&mut Self::Value) -> (R, bool)) -> R {
104        S::map_mut_and_notify_if(self, f)
105    }
106}
107
108pub struct UseSignal<'a, S: Signal + ?Sized>(&'a S);
109
110hooks_core::impl_hook!(
111    impl<S: Signal> UseSignal<'_, S> {
112        fn into_hook(self) -> S::SignalHook {
113            self.0.to_signal_hook()
114        }
115
116        fn update_hook(self, hook: _) {
117            self.0.update_signal_hook(hook)
118        }
119
120        fn h(self, hook: <S::SignalHook as SignalHook>::SignalHookUninitialized) {
121            self.0.h_signal_hook(hook)
122        }
123    }
124);
125
126pub trait ToOwnedSignal: Signal + ToOwnedShareValue<OwnedShareValue = Self::OwnedSignal> {
127    type OwnedSignal: Signal<SignalHook = Self::SignalHook, Value = Self::Value>;
128}
129
130/// A trait alias for `Signal + ToOwnedShareValue<OwnedShareValue: Signal<SignalHook = Self::SignalHook, SignalHookUninitialized = Self::SignalHookUninitialized>>`
131impl<T: ?Sized + ToOwnedShareValue> ToOwnedSignal for T
132where
133    T: Signal,
134    T::OwnedShareValue: Signal<SignalHook = Self::SignalHook>,
135{
136    type OwnedSignal = T::OwnedShareValue;
137}